├── .gitignore ├── msc_disk.h ├── FileOnPIco ├── INFO_UF2.TXT └── INDEX.HTM ├── fatImages ├── PicoImage.7z ├── TinyUSBFat12.img └── README.md ├── uploads ├── hello_uart.bin └── hello_uart.uf2 ├── checkUF2.h ├── LICENSE.TXT ├── CMakeLists.txt ├── Fat16Struct.h ├── README.md ├── main.c ├── tusb_config.h ├── fat12.h ├── usb_descriptors.c └── msc_disk.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | PicoImage.img -------------------------------------------------------------------------------- /msc_disk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void printReserveSectFat(); -------------------------------------------------------------------------------- /FileOnPIco/INFO_UF2.TXT: -------------------------------------------------------------------------------- 1 | UF2 Bootloader v3.0 2 | Model: Raspberry Pi RP2 3 | Board-ID: RPI-RP2 4 | -------------------------------------------------------------------------------- /fatImages/PicoImage.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendena/pico_drag_n_drop_programmer/HEAD/fatImages/PicoImage.7z -------------------------------------------------------------------------------- /uploads/hello_uart.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendena/pico_drag_n_drop_programmer/HEAD/uploads/hello_uart.bin -------------------------------------------------------------------------------- /uploads/hello_uart.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendena/pico_drag_n_drop_programmer/HEAD/uploads/hello_uart.uf2 -------------------------------------------------------------------------------- /fatImages/TinyUSBFat12.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendena/pico_drag_n_drop_programmer/HEAD/fatImages/TinyUSBFat12.img -------------------------------------------------------------------------------- /fatImages/README.md: -------------------------------------------------------------------------------- 1 | if you want to see the PicoImage.img you need uncompress the PicoImage.7z. Github wouldn't let me push up such a large file. -------------------------------------------------------------------------------- /FileOnPIco/INDEX.HTM: -------------------------------------------------------------------------------- 1 | Redirecting to raspberrypi.com -------------------------------------------------------------------------------- /checkUF2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //return size UF2 4 | unsigned char * getUF2Info(unsigned char * buffer, 5 | unsigned int * returnSize) 6 | { 7 | unsigned char * returnBuff = 0; 8 | unsigned int * intBuff = (unsigned int*)buffer; 9 | //printf("first number 0x%x, 0x%x, 0x%x\n",intBuff[0],intBuff[1], intBuff[142]); 10 | if(intBuff[0] == 0x0A324655 && 11 | intBuff[1] == 0x9E5D5157 && 12 | intBuff[127] == 0x0AB16F30) 13 | { 14 | printf("flags %x\n", intBuff[2]); 15 | printf("return size %x\n", intBuff[4]); 16 | *returnSize = intBuff[4]; 17 | returnBuff = (unsigned char *)&buffer[32]; 18 | } 19 | 20 | return returnBuff; 21 | } -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018, hathach (tinyusb.org) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) 4 | include($ENV{PICO_SDK_PATH}/tools/CMakeLists.txt) 5 | 6 | 7 | 8 | project(PICO_MSC C CXX ASM) 9 | 10 | set(CMAKE_C_STANDARD 11) 11 | set(CMAKE_CXX_STANDARD 17) 12 | 13 | 14 | pico_sdk_init() 15 | 16 | add_executable(PICO_MSC) 17 | 18 | target_sources(PICO_MSC PUBLIC 19 | ${CMAKE_CURRENT_LIST_DIR}/main.c 20 | ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c 21 | ${CMAKE_CURRENT_LIST_DIR}/msc_disk.c 22 | ) 23 | 24 | # Make sure TinyUSB can find tusb_config.h 25 | target_include_directories(PICO_MSC PUBLIC 26 | ${CMAKE_CURRENT_LIST_DIR}) 27 | 28 | # In addition to pico_stdlib required for common PicoSDK functionality, add dependency on tinyusb_device 29 | # for TinyUSB device support and tinyusb_board for the additional board support library used by the example 30 | target_link_libraries(PICO_MSC PUBLIC pico_stdlib tinyusb_device tinyusb_board hardware_flash) 31 | 32 | # Uncomment this line to enable fix for Errata RP2040-E5 (the fix requires use of GPIO 15) 33 | #target_compile_definitions(PICO_MSC PUBLIC PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1) 34 | 35 | pico_add_extra_outputs(PICO_MSC) 36 | 37 | pico_enable_stdio_usb(PICO_MSC 0) 38 | pico_enable_stdio_uart(PICO_MSC 1) 39 | 40 | 41 | set(PICO_COPY_TO_RAM,1) 42 | #add_compile_definitions(PICO_COPY_TO_RAM=1) 43 | #add_definitions(-DPICO_COPY_TO_RAM=1) -------------------------------------------------------------------------------- /Fat16Struct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "assert.h" 4 | #include "stdio.h" 5 | #include "stdint.h" 6 | 7 | typedef struct { 8 | char name[8]; 9 | char ext[3]; 10 | uint8_t attrs; 11 | uint8_t reserved; 12 | uint8_t createTimeFine; 13 | uint16_t createTime; 14 | uint16_t createDate; 15 | uint16_t lastAccessDate; 16 | uint16_t highStartCluster; 17 | uint16_t updateTime; 18 | uint16_t updateDate; 19 | uint16_t startCluster; 20 | uint32_t size; 21 | 22 | } __attribute__((packed)) DirEntry; 23 | 24 | static_assert(sizeof(DirEntry) == 32, "DirEntry size is not right"); 25 | 26 | typedef struct ReserveSect { 27 | uint8_t bootJump[3]; /* 0 Jump to bootstrap */ 28 | uint8_t oemName[8]; /* 3 OEM Manufacturer name */ 29 | uint16_t sectorSize __attribute((packed)); /* 11 Sector size in bytes */ 30 | uint8_t clusterSize; /* 13 Sectors per cluster */ 31 | uint16_t reservedSectors __attribute((packed)); /* 14 Number of reserved sectors */ 32 | uint8_t fatCopies; /* 16 # of FAT copies */ 33 | uint16_t rootEirEntries __attribute((packed)); /* 17 # of root directory entries */ 34 | uint16_t totalSectorsFat16 __attribute((packed)); /* 19 (UNUSED FAT32) Total number of sectors */ 35 | uint8_t mediaType; /* 21 Media type */ 36 | uint16_t fatTableSize __attribute((packed)); 37 | uint16_t secPerTrk __attribute((packed)); 38 | uint16_t numHeads __attribute((packed)); 39 | uint32_t hiddSec __attribute((packed)); 40 | uint32_t totalSec32 __attribute((packed)); 41 | } __attribute((packed)) ReserveSect; 42 | 43 | 44 | void printReserveSect(ReserveSect * bootSect) 45 | { 46 | printf("bootOEM %.8s\n", bootSect->oemName); 47 | printf("cluster size %x\n",bootSect->clusterSize); 48 | printf("fat copies %x\n", bootSect->fatCopies); 49 | printf("fat table size %x\n", bootSect->fatTableSize); 50 | printf("totalSec32 %x\n", bootSect->totalSec32); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example unoptimized Drag n' Drop Programmer 2 | This example is trying to mimic the way that the raspberry pi pico bootloader copies a UF2 file into the flash. The actuall bootloader can be found [here](https://github.com/raspberrypi/pico-bootrom), but it's highly optimized "by design", so i made this to explore how it worked at a less optimized way. Starting point for this was the [tinyUSB CDC_MSC example](https://github.com/hathach/tinyusb/tree/master/examples/device/cdc_msc) 3 | 4 | ## [Video describing project](https://www.youtube.com/watch?v=tmmHijhct_k) 5 | 6 | ## Things inside this demo are 7 | * USB MSC - "USB storage" 8 | * FAT16 file system 9 | * wrighting to flash 10 | * Basic UF2 Parsing 11 | 12 | 13 | ## to build 14 | * cmake .. -DPICO_COPY_TO_RAM=1 15 | 16 | ## Command to flash pico 17 | * openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -c "program PICO_MSC.elf verify reset exit" 18 | 19 | # Things inside this repo 20 | 21 | * fatImages - These are straight rips from a raspberry pi pico. Usefully for see the raw hex values of the fat table 22 | * FileOnPico - These are the files that the pico has by default 23 | * uploads - these are test programs that you can drag onto the raspberry pi pico 24 | 25 | 26 | 27 | 28 | # important links 29 | 30 | ### Fat file system 31 | * [best overview of fat files](http://elm-chan.org/docs/fat_e.html) 32 | * [another good one](https://www.pjrc.com/tech/8051/ide/fat32.html) 33 | * [more fat](http://www.tavi.co.uk/phobos/fat.html#media_descriptor) 34 | 35 | ### Moving program from flash to RAM 36 | * [Raspberry pi forum post about flash to ram](https://forums.raspberrypi.com/viewtopic.php?t=318471) 37 | * [LD_script for copy to ram](https://github.com/raspberrypi/pico-sdk/blob/2062372d203b372849d573f252cf7c6dc2800c0a/src/rp2_common/pico_standard_link/memmap_copy_to_ram.ld) 38 | * [CMAKE section to copy flash to ram](https://github.com/raspberrypi/pico-sdk/blob/2062372d203b372849d573f252cf7c6dc2800c0a/src/rp2_common/pico_standard_link/CMakeLists.txt#L49) 39 | 40 | ### No flash vs copy to ram 41 | * https://forums.raspberrypi.com/viewtopic.php?t=312474 42 | 43 | 44 | ### Wrighting to flash 45 | * https://www.makermatrix.com/blog/read-and-write-data-with-the-pi-pico-onboard-flash/ 46 | * https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__flash.html 47 | * https://kevinboone.me/picoflash.html?i=1 48 | 49 | 50 | ### UF2 File conversion 51 | * [Good wright up on UF2](https://microsoft.github.io/uf2/) 52 | 53 | ### [How to reset the chip](https://raspberrypi.stackexchange.com/questions/132439/pi-pico-software-reset-using-the-c-sdk) 54 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bsp/board.h" 6 | #include "tusb.h" 7 | #include 8 | #include "pico/stdlib.h" 9 | #include "pico.h" 10 | #include 11 | //--------------------------------------------------------------------+ 12 | // MACRO CONSTANT TYPEDEF PROTYPES 13 | //--------------------------------------------------------------------+ 14 | 15 | /* Blink pattern 16 | * - 250 ms : device not mounted 17 | * - 1000 ms : device mounted 18 | * - 2500 ms : device is suspended 19 | */ 20 | enum { 21 | BLINK_NOT_MOUNTED = 250, 22 | BLINK_MOUNTED = 1000, 23 | BLINK_SUSPENDED = 2500, 24 | }; 25 | 26 | static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; 27 | 28 | void led_blinking_task(void); 29 | void cdc_task(void); 30 | 31 | 32 | #if !PICO_COPY_TO_RAM 33 | #error "This example must be built to run from SRAM!" 34 | #endif 35 | 36 | /*------------- MAIN -------------*/ 37 | int main(void) 38 | { 39 | board_init(); 40 | 41 | // init device stack on configured roothub port 42 | tusb_init(); 43 | 44 | printReserveSectFat(); 45 | printf("\n\nStart\n\n"); 46 | 47 | 48 | while (1) 49 | { 50 | tud_task(); // tinyusb device task 51 | led_blinking_task(); 52 | //printf("testing this out\n"); 53 | //sleep_ms(100); 54 | 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | //--------------------------------------------------------------------+ 61 | // Device callbacks 62 | //--------------------------------------------------------------------+ 63 | 64 | // Invoked when device is mounted 65 | void tud_mount_cb(void) 66 | { 67 | blink_interval_ms = BLINK_MOUNTED; 68 | } 69 | 70 | // Invoked when device is unmounted 71 | void tud_umount_cb(void) 72 | { 73 | blink_interval_ms = BLINK_NOT_MOUNTED; 74 | } 75 | 76 | // Invoked when usb bus is suspended 77 | // remote_wakeup_en : if host allow us to perform remote wakeup 78 | // Within 7ms, device must draw an average of current less than 2.5 mA from bus 79 | void tud_suspend_cb(bool remote_wakeup_en) 80 | { 81 | (void) remote_wakeup_en; 82 | blink_interval_ms = BLINK_SUSPENDED; 83 | } 84 | 85 | // Invoked when usb bus is resumed 86 | void tud_resume_cb(void) 87 | { 88 | blink_interval_ms = BLINK_MOUNTED; 89 | } 90 | 91 | 92 | //--------------------------------------------------------------------+ 93 | // BLINKING TASK 94 | //--------------------------------------------------------------------+ 95 | void led_blinking_task(void) 96 | { 97 | static uint32_t start_ms = 0; 98 | static bool led_state = false; 99 | 100 | // Blink every interval ms 101 | if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time 102 | start_ms += blink_interval_ms; 103 | 104 | board_led_write(led_state); 105 | led_state = 1 - led_state; // toggle 106 | } 107 | -------------------------------------------------------------------------------- /tusb_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _TUSB_CONFIG_H_ 2 | #define _TUSB_CONFIG_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | //-------------------------------------------------------------------- 9 | // COMMON CONFIGURATION 10 | //-------------------------------------------------------------------- 11 | 12 | // defined by board.mk 13 | #ifndef CFG_TUSB_MCU 14 | #error CFG_TUSB_MCU must be defined 15 | #endif 16 | 17 | // RHPort number used for device can be defined by board.mk, default to port 0 18 | #ifndef BOARD_DEVICE_RHPORT_NUM 19 | #define BOARD_DEVICE_RHPORT_NUM 0 20 | #endif 21 | 22 | // RHPort max operational speed can defined by board.mk 23 | // Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed 24 | #ifndef BOARD_DEVICE_RHPORT_SPEED 25 | #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ 26 | CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) 27 | #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED 28 | #else 29 | #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED 30 | #endif 31 | #endif 32 | 33 | // Device mode with rhport and speed defined by board.mk 34 | #if BOARD_DEVICE_RHPORT_NUM == 0 35 | #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 36 | #elif BOARD_DEVICE_RHPORT_NUM == 1 37 | #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 38 | #else 39 | #error "Incorrect RHPort configuration" 40 | #endif 41 | 42 | #ifndef CFG_TUSB_OS 43 | #define CFG_TUSB_OS OPT_OS_NONE 44 | #endif 45 | 46 | // CFG_TUSB_DEBUG is defined by compiler in DEBUG build 47 | // #define CFG_TUSB_DEBUG 0 48 | 49 | /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. 50 | * Tinyusb use follows macros to declare transferring memory so that they can be put 51 | * into those specific section. 52 | * e.g 53 | * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) 54 | * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) 55 | */ 56 | #ifndef CFG_TUSB_MEM_SECTION 57 | #define CFG_TUSB_MEM_SECTION 58 | #endif 59 | 60 | #ifndef CFG_TUSB_MEM_ALIGN 61 | #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) 62 | #endif 63 | 64 | //-------------------------------------------------------------------- 65 | // DEVICE CONFIGURATION 66 | //-------------------------------------------------------------------- 67 | 68 | #ifndef CFG_TUD_ENDPOINT0_SIZE 69 | #define CFG_TUD_ENDPOINT0_SIZE 64 70 | #endif 71 | 72 | //------------- CLASS -------------// 73 | #define CFG_TUD_HID 0 74 | #define CFG_TUD_CDC 0 75 | #define CFG_TUD_MSC 1 76 | #define CFG_TUD_MIDI 0 77 | #define CFG_TUD_VENDOR 0 78 | 79 | // HID buffer size Should be sufficient to hold ID (if any) + Data 80 | #define CFG_TUD_HID_EP_BUFSIZE 16 81 | #define CFG_TUD_MSC_EP_BUFSIZE 512 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | 87 | #endif /* _TUSB_CONFIG_H_ */ 88 | -------------------------------------------------------------------------------- /fat12.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //Not currently being used by default. 3 | //Just a example of a fat12 system 4 | //if you don't want the overhead of using fat16 5 | //From TinyUSB examples 6 | /* 7 | 8 | enum 9 | { 10 | DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount 11 | DISK_BLOCK_SIZE = 512 12 | }; 13 | 14 | uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = 15 | { 16 | //------------- Block0: Boot Sector -------------// 17 | // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; 18 | // sector_per_cluster = 1; reserved_sectors = 1; 19 | // fat_num = 1; fat12_root_entry_num = 16; 20 | // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0; 21 | // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; 22 | // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; 23 | // FAT magic code at offset 510-511 24 | { 25 | 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, 26 | 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' , 28 | 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, 29 | 30 | // Zero up to 2 last bytes of FAT magic code 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA 62 | }, 63 | 64 | //------------- Block1: FAT12 Table -------------// 65 | { 66 | 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file 67 | }, 68 | 69 | //------------- Block2: Root Directory -------------// 70 | { 71 | // first entry is volume label 72 | 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | // second entry is readme file 75 | 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D, 76 | 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, 77 | sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) 78 | }, 79 | 80 | //------------- Block3: Readme Content -------------// 81 | README_CONTENTS 82 | }; 83 | 84 | //*/ -------------------------------------------------------------------------------- /usb_descriptors.c: -------------------------------------------------------------------------------- 1 | #include "tusb.h" 2 | #include "class/msc/msc.h" 3 | #include "device/usbd.h" 4 | /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. 5 | * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. 6 | * 7 | * Auto ProductID layout's Bitmap: 8 | * [MSB] HID | MSC | CDC [LSB] 9 | */ 10 | #define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) 11 | #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ 12 | _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) 13 | 14 | #define USB_VID 0xCafe 15 | #define USB_BCD 0x0200 16 | 17 | //--------------------------------------------------------------------+ 18 | // Device Descriptors 19 | //--------------------------------------------------------------------+ 20 | tusb_desc_device_t const desc_device = 21 | { 22 | .bLength = sizeof(tusb_desc_device_t), 23 | .bDescriptorType = TUSB_DESC_DEVICE, 24 | .bcdUSB = USB_BCD, 25 | 26 | // Use Interface Association Descriptor (IAD) for CDC 27 | // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) 28 | .bDeviceClass = TUSB_CLASS_MISC, 29 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 30 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 31 | 32 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 33 | 34 | .idVendor = USB_VID, 35 | .idProduct = USB_PID, 36 | .bcdDevice = 0x0100, 37 | 38 | .iManufacturer = 0x01, 39 | .iProduct = 0x02, 40 | .iSerialNumber = 0x03, 41 | 42 | .bNumConfigurations = 0x01 43 | }; 44 | 45 | // Invoked when received GET DEVICE DESCRIPTOR 46 | // Application return pointer to descriptor 47 | uint8_t const * tud_descriptor_device_cb(void) 48 | { 49 | return (uint8_t const *) &desc_device; 50 | } 51 | 52 | //--------------------------------------------------------------------+ 53 | // Configuration Descriptor 54 | //--------------------------------------------------------------------+ 55 | 56 | enum 57 | { 58 | ITF_NUM_MSC, 59 | ITF_NUM_TOTAL 60 | }; 61 | 62 | 63 | #define EPNUM_MSC_OUT 0x01 64 | #define EPNUM_MSC_IN 0x81 65 | 66 | 67 | #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) 68 | 69 | // full speed configuration 70 | uint8_t const desc_fs_configuration[] = 71 | { 72 | // Config number, interface count, string index, total length, attribute, power in mA 73 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 74 | 75 | // Interface number, string index, EP Out & EP In address, EP size 76 | TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 3 , EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), 77 | }; 78 | 79 | #if TUD_OPT_HIGH_SPEED 80 | // Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration 81 | 82 | // high speed configuration 83 | uint8_t const desc_hs_configuration[] = 84 | { 85 | // Config number, interface count, string index, total length, attribute, power in mA 86 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 87 | // Interface number, string index, EP Out & EP In address, EP size 88 | TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 3, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), 89 | }; 90 | 91 | // other speed configuration 92 | uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; 93 | 94 | // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed 95 | tusb_desc_device_qualifier_t const desc_device_qualifier = 96 | { 97 | .bLength = sizeof(tusb_desc_device_qualifier_t), 98 | .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, 99 | .bcdUSB = USB_BCD, 100 | 101 | .bDeviceClass = TUSB_CLASS_MISC, 102 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 103 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 104 | 105 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 106 | .bNumConfigurations = 0x01, 107 | .bReserved = 0x00 108 | }; 109 | 110 | // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request 111 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. 112 | // device_qualifier descriptor describes information about a high-speed capable device that would 113 | // change if the device were operating at the other speed. If not highspeed capable stall this request. 114 | uint8_t const* tud_descriptor_device_qualifier_cb(void) 115 | { 116 | return (uint8_t const*) &desc_device_qualifier; 117 | } 118 | 119 | // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request 120 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 121 | // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa 122 | uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) 123 | { 124 | (void) index; // for multiple configurations 125 | 126 | // if link speed is high return fullspeed config, and vice versa 127 | // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG 128 | memcpy(desc_other_speed_config, 129 | (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration, 130 | CONFIG_TOTAL_LEN); 131 | 132 | desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; 133 | 134 | return desc_other_speed_config; 135 | } 136 | 137 | #endif // highspeed 138 | 139 | 140 | // Invoked when received GET CONFIGURATION DESCRIPTOR 141 | // Application return pointer to descriptor 142 | // Descriptor contents must exist long enough for transfer to complete 143 | uint8_t const * tud_descriptor_configuration_cb(uint8_t index) 144 | { 145 | (void) index; // for multiple configurations 146 | 147 | #if TUD_OPT_HIGH_SPEED 148 | // Although we are highspeed, host may be fullspeed. 149 | return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; 150 | #else 151 | return desc_fs_configuration; 152 | #endif 153 | } 154 | 155 | //--------------------------------------------------------------------+ 156 | // String Descriptors 157 | //--------------------------------------------------------------------+ 158 | 159 | // array of pointer to string descriptors 160 | char const* string_desc_arr [] = 161 | { 162 | (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) 163 | "TinyUSB", // 1: Manufacturer 164 | "TinyUSB Device", // 2: Product 165 | "RPI-RP2", // 3: MSC Interface 166 | }; 167 | 168 | static uint16_t _desc_str[32]; 169 | 170 | // Invoked when received GET STRING DESCRIPTOR request 171 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 172 | uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) 173 | { 174 | (void) langid; 175 | 176 | uint8_t chr_count; 177 | 178 | if ( index == 0) 179 | { 180 | memcpy(&_desc_str[1], string_desc_arr[0], 2); 181 | chr_count = 1; 182 | }else 183 | { 184 | // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. 185 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors 186 | 187 | if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; 188 | 189 | const char* str = string_desc_arr[index]; 190 | 191 | // Cap at max char 192 | chr_count = (uint8_t) strlen(str); 193 | if ( chr_count > 31 ) chr_count = 31; 194 | 195 | // Convert ASCII string into UTF-16 196 | for(uint8_t i=0; i 7 | #include "checkUF2.h" 8 | // whether host does safe-eject 9 | static bool ejected = false; 10 | 11 | // Some MCU doesn't have enough 8KB SRAM to store the whole disk 12 | // We will use Flash as read-only disk with board that has 13 | 14 | void software_reset() 15 | { 16 | watchdog_enable(1, 1); 17 | while(1); 18 | } 19 | 20 | #define HTML_Page_Data \ 21 | R"(Redirecting to raspberrypi.com)" 22 | 23 | 24 | #define DATA_Page_Data \ 25 | "UF2 Bootloader v3.0\n\ 26 | Model: Raspberry Pi RP2\n\ 27 | Board-ID: RPI-RP2\n" 28 | 29 | 30 | enum 31 | { 32 | DISK_BLOCK_NUM = 0x3ffff, // 8KB is the smallest size that windows allow to mount 33 | DISK_BLOCK_SIZE = 512, 34 | DISK_CLUSTER_SIZE = 8 35 | }; 36 | 37 | //indexs of places 38 | enum 39 | { 40 | INDEX_RESERVED = 0, 41 | INDEX_FAT_TABLE_1_START = 1, //Fat table size is 0x81 42 | INDEX_FAT_TABLE_2_START = 0x82, 43 | INDEX_ROOT_DIRECTORY = 0x103, 44 | INDEX_DATA_STARTS = 0x123, 45 | INDEX_DATA_END = (0x12b + DISK_CLUSTER_SIZE - 1) 46 | }; 47 | 48 | 49 | #define MAX_SECTION_COUNT_FOR_FLASH_SECTION (FLASH_SECTOR_SIZE/FLASH_PAGE_SIZE) 50 | struct flashingLocation { 51 | unsigned int pageCountFlash; 52 | }flashingLocation = {.pageCountFlash = 0}; 53 | 54 | 55 | uint8_t DISK_reservedSection[DISK_BLOCK_SIZE] = 56 | { 57 | 0xEB, 0x3C, 0x90, 58 | 0x4D, 0x53, 0x57, 0x49, 0x4E, 0x34, 0x2E, 0x31, //MSWIN4.1 59 | 0x00, 0x02, //sector 512 60 | 0x08, //cluster size 8 sectors -unit for file sizes 61 | 0x01, 0x00, //BPB_RsvdSecCnt 62 | 0x02, //Number of fat tables 63 | 0x00, 0x02, //BPB_RootEntCnt 64 | 0x00, 0x00, //16 bit fat sector count - 0 larger then 0x10000 65 | 0xF8, //- non-removable disks a 66 | 0x81, 0x00, //BPB_FATSz16 - Size of fat table 67 | 0x01, 0x00, //BPB_SecPerTrk 68 | 0x01, 0x00, //BPB_NumHeads 69 | 0x01, 0x00, 0x00, 0x00, //??? BPB_HiddSec 70 | 0xFF, 0xFF, 0x03, 0x00, //BPB_TotSec32 71 | 0x00, //BS_DrvNum - probably be 0x80 but is not? 72 | 0x00, // 73 | 0x29, 74 | 0x50, 0x04, 0x0B, 0x00, //Volume Serial Number 75 | 'R' , 'P' , 'I' , '-' , 'R' , 'P' , '2' , ' ' , ' ' , ' ' , ' ' , 76 | 'F', 'A', 'T', '1', '6', ' ', ' ', ' ', 77 | 78 | 0x00, 0x00, 79 | 80 | // Zero up to 2 last bytes of FAT magic code 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 | 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 107 | 108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA 112 | }; 113 | 114 | uint8_t DISK_fatTable[DISK_BLOCK_SIZE] = 115 | { 116 | 0xF8, 0xFF, 117 | 0xFF, 0xFF, 118 | 0xFF, 0xFF, //HTML doc 119 | 0xFF, 0xFF, //Txt file 120 | }; 121 | 122 | 123 | uint8_t DISK_rootDirectory[DISK_BLOCK_SIZE] = 124 | { 125 | // first entry is volume label 126 | 'R' , 'P' , 'I' , '-' , 'R' , 'P' , '2' , ' ' , ' ' , ' ' , ' ' , 0x28, 0x00, 0x00, 0x00, 0x00, 127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128 | // second entry is html file 129 | 'I' , 'N' , 'D' , 'E' , 'X' , ' ' , ' ' , ' ' , 'H' , 'T' , 'M' , 0x21, 0x00, 0xC6, 0x52, 0x6D, 130 | 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 131 | 0x02, 0x00, //cluster location 132 | 0xF1, 0x00, 0x00, 0x00, // html's files size (4 Bytes) 133 | // third entry is text file 134 | 'I' , 'N' , 'F' , 'O' , '_' , 'U' , 'F' , '2' , 'T' , 'X' , 'T' , 0x21, 0x00, 0xC6, 0x52, 0x6D, 135 | 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 136 | 0x03, 0x00, //cluster location 137 | 0x3E, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) 138 | }; 139 | 140 | //block size is not cluster size 141 | uint8_t DISK_data[2][DISK_BLOCK_SIZE] = 142 | { 143 | {HTML_Page_Data}, 144 | {DATA_Page_Data} 145 | }; 146 | 147 | 148 | 149 | 150 | void printReserveSectFat() 151 | { 152 | printReserveSect((ReserveSect*)DISK_reservedSection); 153 | } 154 | 155 | // Invoked when received SCSI_CMD_INQUIRY 156 | // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively 157 | void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) 158 | { 159 | (void) lun; 160 | 161 | const char vid[] = "TinyUSB"; 162 | const char pid[] = "Mass Storage"; 163 | const char rev[] = "1.0"; 164 | 165 | memcpy(vendor_id , vid, strlen(vid)); 166 | memcpy(product_id , pid, strlen(pid)); 167 | memcpy(product_rev, rev, strlen(rev)); 168 | } 169 | 170 | // Invoked when received Test Unit Ready command. 171 | // return true allowing host to read/write this LUN e.g SD card inserted 172 | bool tud_msc_test_unit_ready_cb(uint8_t lun) 173 | { 174 | (void) lun; 175 | 176 | // RAM disk is ready until ejected 177 | if (ejected) { 178 | // Additional Sense 3A-00 is NOT_FOUND 179 | tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); 180 | return false; 181 | } 182 | 183 | return true; 184 | } 185 | 186 | // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size 187 | // Application update block count and block size 188 | void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) 189 | { 190 | (void) lun; 191 | 192 | *block_count = DISK_BLOCK_NUM; 193 | *block_size = DISK_BLOCK_SIZE; 194 | } 195 | 196 | // Invoked when received Start Stop Unit command 197 | // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage 198 | // - Start = 1 : active mode, if load_eject = 1 : load disk storage 199 | bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) 200 | { 201 | (void) lun; 202 | (void) power_condition; 203 | 204 | if ( load_eject ) 205 | { 206 | if (start) 207 | { 208 | // load disk storage 209 | }else 210 | { 211 | // unload disk storage 212 | ejected = true; 213 | } 214 | } 215 | 216 | return true; 217 | } 218 | 219 | // Callback invoked when received READ10 command. 220 | // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. 221 | int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) 222 | { 223 | (void) lun; 224 | 225 | // out of ramdisk 226 | if ( lba >= DISK_BLOCK_NUM ) return -1; 227 | //printf("lba 0x%x, bufsize %d, offset %d\n",lba, bufsize, offset); 228 | //uint8_t const* addr = msc_disk[lba] + offset; 229 | //memcpy(buffer, addr, bufsize); 230 | 231 | uint8_t * addr = 0; 232 | if(lba == INDEX_RESERVED) 233 | { 234 | addr = DISK_reservedSection; 235 | } 236 | else if(lba == INDEX_FAT_TABLE_1_START || lba == INDEX_FAT_TABLE_2_START) 237 | { 238 | addr = DISK_fatTable; 239 | } 240 | else if(lba == INDEX_ROOT_DIRECTORY) 241 | { 242 | addr = DISK_rootDirectory; 243 | } 244 | else if(lba >= INDEX_DATA_STARTS && lba <= INDEX_DATA_END ) 245 | { 246 | //printf("lba %d, bufsize %d, offset %d\n",lba, bufsize, offset); 247 | //DISK_data is only one section large but the cluster sizes are 8. 248 | //So if there was a larger file it would be bad. 249 | addr = DISK_data[(lba - INDEX_DATA_STARTS) / 8]; 250 | //printf("loading section %d\n",(lba - INDEX_DATA_STARTS) / 8); 251 | } 252 | if(addr != 0) 253 | { 254 | memcpy(buffer, addr, bufsize); 255 | } 256 | else{ 257 | memset(buffer,0, bufsize); 258 | } 259 | return (int32_t) bufsize; 260 | } 261 | 262 | bool tud_msc_is_writable_cb (uint8_t lun) 263 | { 264 | (void) lun; 265 | 266 | 267 | return true; 268 | } 269 | 270 | // Callback invoked when received WRITE10 command. 271 | // Process data in buffer to disk's storage and return number of written bytes 272 | int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) 273 | { 274 | (void) lun; 275 | printf("write - lba 0x%x, bufsize%d\n", lba,bufsize); 276 | 277 | // out of ramdisk 278 | if ( lba >= DISK_BLOCK_NUM ) return -1; 279 | //page to sector 280 | if(lba >= INDEX_DATA_END){ 281 | //memcpy(&flashingLocation.buff[flashingLocation.sectionCount * 512], buffer, bufsize); 282 | //uint32_t ints = save_and_disable_interrupts(); 283 | if(flashingLocation.pageCountFlash % MAX_SECTION_COUNT_FOR_FLASH_SECTION == 0) 284 | { 285 | printf("doing flash at offset 0x%x\n",flashingLocation.pageCountFlash * FLASH_PAGE_SIZE); 286 | flash_range_erase((flashingLocation.pageCountFlash / 16) * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE); 287 | } 288 | unsigned int * returnSize; 289 | unsigned char *addressUF2 = getUF2Info(buffer,returnSize); 290 | if(addressUF2 != 0) 291 | { 292 | printf("UF2 FILE %d!!!\n",flashingLocation.pageCountFlash ); 293 | flash_range_program(flashingLocation.pageCountFlash * FLASH_PAGE_SIZE, 294 | &buffer[32], 295 | 256); 296 | flashingLocation.pageCountFlash += 1; //(*returnSize/ FLASH_PAGE_SIZE); 297 | } 298 | else{ 299 | flash_range_program(flashingLocation.pageCountFlash * FLASH_PAGE_SIZE, 300 | buffer, 301 | bufsize); 302 | flashingLocation.pageCountFlash += (bufsize/ FLASH_PAGE_SIZE); 303 | } 304 | } 305 | 306 | if(lba == INDEX_ROOT_DIRECTORY) 307 | { 308 | printf("\n\n\nRestarting the raspberry pi pico!!!! \n\n\n"); 309 | sleep_ms(100);//just to make sure all uart get out 310 | 311 | software_reset(); 312 | } 313 | 314 | //#ifndef CFG_EXAMPLE_MSC_READONLY 315 | // uint8_t* addr = msc_disk[lba] + offset; 316 | // memcpy(addr, buffer, bufsize); 317 | //#else 318 | 319 | 320 | return (int32_t) bufsize; 321 | } 322 | 323 | // Callback invoked when received an SCSI command not in built-in list below 324 | // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE 325 | // - READ10 and WRITE10 has their own callbacks 326 | int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) 327 | { 328 | // read10 & write10 has their own callback and MUST not be handled here 329 | 330 | void const* response = NULL; 331 | int32_t resplen = 0; 332 | 333 | // most scsi handled is input 334 | bool in_xfer = true; 335 | 336 | switch (scsi_cmd[0]) 337 | { 338 | default: 339 | // Set Sense = Invalid Command Operation 340 | tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); 341 | 342 | // negative means error -> tinyusb could stall and/or response with failed status 343 | resplen = -1; 344 | break; 345 | } 346 | 347 | // return resplen must not larger than bufsize 348 | if ( resplen > bufsize ) resplen = bufsize; 349 | 350 | if ( response && (resplen > 0) ) 351 | { 352 | if(in_xfer) 353 | { 354 | memcpy(buffer, response, (size_t) resplen); 355 | }else 356 | { 357 | // SCSI output 358 | } 359 | } 360 | 361 | return (int32_t) resplen; 362 | } 363 | --------------------------------------------------------------------------------