diff --git a/CMakeLists.txt b/CMakeLists.txt index ab32598c..2801ba61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,9 @@ set(CORE_SRCS cores/esp32/StreamString.cpp cores/esp32/USB.cpp cores/esp32/USBCDC.cpp + cores/esp32/USBMSC.cpp + cores/esp32/FirmwareMSC.cpp + cores/esp32/firmware_msc_fat.c cores/esp32/wiring_pulse.c cores/esp32/wiring_shift.c cores/esp32/WMath.cpp @@ -151,6 +154,7 @@ set(includedirs libraries/SPI/src libraries/Ticker/src libraries/Update/src + libraries/USB/src libraries/WebServer/src libraries/WiFiClientSecure/src libraries/WiFi/src diff --git a/boards.txt b/boards.txt index e8a38a6b..3f9d992c 100644 --- a/boards.txt +++ b/boards.txt @@ -1,5 +1,7 @@ menu.UploadSpeed=Upload Speed -menu.SerialMode=Serial Connected To +menu.CDCOnBoot=USB CDC On Boot +menu.MSCOnBoot=USB Firmware MSC On Boot +menu.DFUOnBoot=USB DFU On Boot menu.UploadMode=Upload Mode menu.CPUFreq=CPU Frequency menu.FlashFreq=Flash Frequency @@ -37,7 +39,7 @@ esp32c3.build.variant=esp32c3 esp32c3.build.board=ESP32C3_DEV esp32c3.build.bootloader_addr=0x0 -esp32c3.build.serial=0 +esp32c3.build.cdc_on_boot=0 esp32c3.build.f_cpu=160000000L esp32c3.build.flash_size=4MB esp32c3.build.flash_freq=80m @@ -173,19 +175,31 @@ esp32s2.build.core=esp32 esp32s2.build.variant=esp32s2 esp32s2.build.board=ESP32S2_DEV -esp32s2.build.serial=0 +esp32s2.build.cdc_on_boot=0 +esp32s2.build.msc_on_boot=0 +esp32s2.build.dfu_on_boot=0 esp32s2.build.f_cpu=240000000L esp32s2.build.flash_size=4MB esp32s2.build.flash_freq=80m -esp32s2.build.flash_mode=qio +esp32s2.build.flash_mode=dio esp32s2.build.boot=qio esp32s2.build.partitions=default esp32s2.build.defines= -esp32s2.menu.SerialMode.default=UART0 -esp32s2.menu.SerialMode.default.build.serial=0 -esp32s2.menu.SerialMode.cdc=USB CDC -esp32s2.menu.SerialMode.cdc.build.serial=1 +esp32s2.menu.CDCOnBoot.default=Disabled +esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0 +esp32s2.menu.CDCOnBoot.cdc=Enabled +esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +esp32s2.menu.MSCOnBoot.default=Disabled +esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0 +esp32s2.menu.MSCOnBoot.msc=Enabled +esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +esp32s2.menu.DFUOnBoot.default=Disabled +esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +esp32s2.menu.DFUOnBoot.dfu=Enabled +esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 esp32s2.menu.UploadMode.default=UART0 esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false @@ -635,6 +649,103 @@ pico32.menu.DebugLevel.verbose.build.code_debug=5 ############################################################## +esp32s2usb.name=ESP32S2 Native USB +esp32s2usb.vid.0=0x303a +esp32s2usb.pid.0=0x0003 + +esp32s2usb.upload.tool=esptool_py +esp32s2usb.upload.maximum_size=1310720 +esp32s2usb.upload.maximum_data_size=327680 +esp32s2usb.upload.flags= +esp32s2usb.upload.extra_flags= +esp32s2usb.upload.use_1200bps_touch=true +esp32s2usb.upload.wait_for_upload_port=true +esp32s2usb.upload.speed=921600 + +esp32s2usb.serial.disableDTR=false +esp32s2usb.serial.disableRTS=false + +esp32s2usb.build.tarch=xtensa +esp32s2usb.build.bootloader_addr=0x1000 +esp32s2usb.build.target=esp32s2 +esp32s2usb.build.mcu=esp32s2 +esp32s2usb.build.core=esp32 +esp32s2usb.build.variant=esp32s2usb +esp32s2usb.build.board=ESP32S2_USB + +esp32s2usb.build.cdc_on_boot=1 +esp32s2usb.build.msc_on_boot=1 +esp32s2usb.build.dfu_on_boot=1 +esp32s2usb.build.f_cpu=240000000L +esp32s2usb.build.flash_size=4MB +esp32s2usb.build.flash_freq=80m +esp32s2usb.build.flash_mode=dio +esp32s2usb.build.boot=qio +esp32s2usb.build.partitions=default +esp32s2usb.build.defines= + +esp32s2usb.menu.PSRAM.disabled=Disabled +esp32s2usb.menu.PSRAM.disabled.build.defines= +esp32s2usb.menu.PSRAM.enabled=Enabled +esp32s2usb.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM + +esp32s2usb.menu.FlashSize.4M=4MB (32Mb) +esp32s2usb.menu.FlashSize.4M.build.flash_size=4MB +esp32s2usb.menu.FlashSize.8M=8MB (64Mb) +esp32s2usb.menu.FlashSize.8M.build.flash_size=8MB +esp32s2usb.menu.FlashSize.8M.build.partitions=default_8MB +esp32s2usb.menu.FlashSize.16M=16MB (128Mb) +esp32s2usb.menu.FlashSize.16M.build.flash_size=16MB + +esp32s2usb.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +esp32s2usb.menu.PartitionScheme.default.build.partitions=default +esp32s2usb.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +esp32s2usb.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +esp32s2usb.menu.PartitionScheme.default_8MB=8M Flash (3MB APP/1.5MB FAT) +esp32s2usb.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +esp32s2usb.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +esp32s2usb.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +esp32s2usb.menu.PartitionScheme.minimal.build.partitions=minimal +esp32s2usb.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +esp32s2usb.menu.PartitionScheme.no_ota.build.partitions=no_ota +esp32s2usb.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +esp32s2usb.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +esp32s2usb.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +esp32s2usb.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +esp32s2usb.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +esp32s2usb.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +esp32s2usb.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +esp32s2usb.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +esp32s2usb.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +esp32s2usb.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +esp32s2usb.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +esp32s2usb.menu.PartitionScheme.huge_app.build.partitions=huge_app +esp32s2usb.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +esp32s2usb.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +esp32s2usb.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +esp32s2usb.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +esp32s2usb.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FAT) +esp32s2usb.menu.PartitionScheme.fatflash.build.partitions=ffat +esp32s2usb.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +esp32s2usb.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9MB FATFS) +esp32s2usb.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +esp32s2usb.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 + +esp32s2usb.menu.DebugLevel.none=None +esp32s2usb.menu.DebugLevel.none.build.code_debug=0 +esp32s2usb.menu.DebugLevel.error=Error +esp32s2usb.menu.DebugLevel.error.build.code_debug=1 +esp32s2usb.menu.DebugLevel.warn=Warn +esp32s2usb.menu.DebugLevel.warn.build.code_debug=2 +esp32s2usb.menu.DebugLevel.info=Info +esp32s2usb.menu.DebugLevel.info.build.code_debug=3 +esp32s2usb.menu.DebugLevel.debug=Debug +esp32s2usb.menu.DebugLevel.debug.build.code_debug=4 +esp32s2usb.menu.DebugLevel.verbose=Verbose +esp32s2usb.menu.DebugLevel.verbose.build.code_debug=5 + +############################################################## + esp32wroverkit.name=ESP32 Wrover Kit (all versions) esp32wroverkit.upload.tool=esptool_py esp32wroverkit.upload.maximum_size=1310720 @@ -865,7 +976,9 @@ feathers2.build.core=esp32 feathers2.build.variant=um_feathers2 feathers2.build.board=FEATHERS2 -feathers2.build.serial=1 +feathers2.build.cdc_on_boot=1 +feathers2.build.msc_on_boot=1 +feathers2.build.dfu_on_boot=0 feathers2.build.f_cpu=240000000L feathers2.build.flash_size=16MB feathers2.build.flash_freq=80m @@ -874,10 +987,20 @@ feathers2.build.boot=qio feathers2.build.partitions=fatflash feathers2.build.defines= -feathers2.menu.SerialMode.cdc=USB CDC -feathers2.menu.SerialMode.cdc.build.serial=1 -feathers2.menu.SerialMode.default=UART0 -feathers2.menu.SerialMode.default.build.serial=0 +feathers2.menu.CDCOnBoot.cdc=Enabled +feathers2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +feathers2.menu.CDCOnBoot.default=Disabled +feathers2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +feathers2.menu.MSCOnBoot.msc=Enabled +feathers2.menu.MSCOnBoot.msc.build.msc_on_boot=1 +feathers2.menu.MSCOnBoot.default=Disabled +feathers2.menu.MSCOnBoot.default.build.msc_on_boot=0 + +feathers2.menu.DFUOnBoot.default=Disabled +feathers2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +feathers2.menu.DFUOnBoot.dfu=Enabled +feathers2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 feathers2.menu.PSRAM.enabled=Enabled feathers2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -993,7 +1116,9 @@ tinys2.build.core=esp32 tinys2.build.variant=um_tinys2 tinys2.build.board=TINYS2 -tinys2.build.serial=1 +tinys2.build.cdc_on_boot=1 +tinys2.build.msc_on_boot=1 +tinys2.build.dfu_on_boot=0 tinys2.build.f_cpu=240000000L tinys2.build.flash_size=4MB tinys2.build.flash_freq=80m @@ -1002,10 +1127,20 @@ tinys2.build.boot=qio tinys2.build.partitions=default tinys2.build.defines= -tinys2.menu.SerialMode.cdc=USB CDC -tinys2.menu.SerialMode.cdc.build.serial=1 -tinys2.menu.SerialMode.default=UART0 -tinys2.menu.SerialMode.default.build.serial=0 +tinys2.menu.CDCOnBoot.cdc=Enabled +tinys2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +tinys2.menu.CDCOnBoot.default=Disabled +tinys2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +tinys2.menu.MSCOnBoot.msc=Enabled +tinys2.menu.MSCOnBoot.msc.build.msc_on_boot=1 +tinys2.menu.MSCOnBoot.default=Disabled +tinys2.menu.MSCOnBoot.default.build.msc_on_boot=0 + +tinys2.menu.DFUOnBoot.default=Disabled +tinys2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +tinys2.menu.DFUOnBoot.dfu=Enabled +tinys2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 tinys2.menu.PSRAM.enabled=Enabled tinys2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -1166,7 +1301,9 @@ micros2.build.core=esp32 micros2.build.variant=micro_s2 micros2.build.board=MICROS2 -micros2.build.serial=1 +micros2.build.cdc_on_boot=1 +micros2.build.msc_on_boot=1 +micros2.build.dfu_on_boot=0 micros2.build.f_cpu=240000000L micros2.build.flash_size=16MB micros2.build.flash_freq=80m @@ -1175,10 +1312,20 @@ micros2.build.boot=qio micros2.build.partitions=fatflash micros2.build.defines= -micros2.menu.SerialMode.cdc=USB CDC -micros2.menu.SerialMode.cdc.build.serial=1 -micros2.menu.SerialMode.default=UART0 -micros2.menu.SerialMode.default.build.serial=0 +micros2.menu.CDCOnBoot.cdc=Enabled +micros2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +micros2.menu.CDCOnBoot.default=Disabled +micros2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +micros2.menu.MSCOnBoot.msc=Enabled +micros2.menu.MSCOnBoot.msc.build.msc_on_boot=1 +micros2.menu.MSCOnBoot.default=Disabled +micros2.menu.MSCOnBoot.default.build.msc_on_boot=0 + +micros2.menu.DFUOnBoot.default=Disabled +micros2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +micros2.menu.DFUOnBoot.dfu=Enabled +micros2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 micros2.menu.PSRAM.enabled=Enabled micros2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -2025,7 +2172,9 @@ sparkfun_esp32s2_thing_plus.build.core=esp32 sparkfun_esp32s2_thing_plus.build.variant=esp32s2thing_plus sparkfun_esp32s2_thing_plus.build.board=ESP32S2_THING_PLUS -sparkfun_esp32s2_thing_plus.build.serial=0 +sparkfun_esp32s2_thing_plus.build.cdc_on_boot=0 +sparkfun_esp32s2_thing_plus.build.msc_on_boot=0 +sparkfun_esp32s2_thing_plus.build.dfu_on_boot=0 sparkfun_esp32s2_thing_plus.build.f_cpu=240000000L sparkfun_esp32s2_thing_plus.build.flash_size=4MB sparkfun_esp32s2_thing_plus.build.flash_freq=80m @@ -2034,10 +2183,20 @@ sparkfun_esp32s2_thing_plus.build.boot=qio sparkfun_esp32s2_thing_plus.build.partitions=default sparkfun_esp32s2_thing_plus.build.defines= -sparkfun_esp32s2_thing_plus.menu.SerialMode.default=UART0 -sparkfun_esp32s2_thing_plus.menu.SerialMode.default.build.serial=0 -sparkfun_esp32s2_thing_plus.menu.SerialMode.cdc=USB CDC -sparkfun_esp32s2_thing_plus.menu.SerialMode.cdc.build.serial=1 +sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.default=Disabled +sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.default.build.cdc_on_boot=0 +sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.cdc=Enabled +sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 + +sparkfun_esp32s2_thing_plus.menu.MSCOnBoot.default=Disabled +sparkfun_esp32s2_thing_plus.menu.MSCOnBoot.default.build.msc_on_boot=0 +sparkfun_esp32s2_thing_plus.menu.MSCOnBoot.msc=Enabled +sparkfun_esp32s2_thing_plus.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +sparkfun_esp32s2_thing_plus.menu.DFUOnBoot.default=Disabled +sparkfun_esp32s2_thing_plus.menu.DFUOnBoot.default.build.dfu_on_boot=0 +sparkfun_esp32s2_thing_plus.menu.DFUOnBoot.dfu=Enabled +sparkfun_esp32s2_thing_plus.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 sparkfun_esp32s2_thing_plus.menu.PSRAM.disabled=Disabled sparkfun_esp32s2_thing_plus.menu.PSRAM.disabled.build.defines= @@ -3334,7 +3493,9 @@ adafruit_metro_esp32s2.build.core=esp32 adafruit_metro_esp32s2.build.variant=adafruit_metro_esp32s2 adafruit_metro_esp32s2.build.board=METRO_ESP32S2 -adafruit_metro_esp32s2.build.serial=0 +adafruit_metro_esp32s2.build.cdc_on_boot=1 +adafruit_metro_esp32s2.build.msc_on_boot=0 +adafruit_metro_esp32s2.build.dfu_on_boot=0 adafruit_metro_esp32s2.build.f_cpu=240000000L adafruit_metro_esp32s2.build.flash_size=4MB adafruit_metro_esp32s2.build.flash_freq=80m @@ -3343,10 +3504,20 @@ adafruit_metro_esp32s2.build.boot=qio adafruit_metro_esp32s2.build.partitions=default adafruit_metro_esp32s2.build.defines= -adafruit_metro_esp32s2.menu.SerialMode.cdc=USB CDC -adafruit_metro_esp32s2.menu.SerialMode.cdc.build.serial=1 -adafruit_metro_esp32s2.menu.SerialMode.default=UART0 -adafruit_metro_esp32s2.menu.SerialMode.default.build.serial=0 +adafruit_metro_esp32s2.menu.CDCOnBoot.cdc=Enabled +adafruit_metro_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +adafruit_metro_esp32s2.menu.CDCOnBoot.default=Disabled +adafruit_metro_esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +adafruit_metro_esp32s2.menu.MSCOnBoot.default=Disabled +adafruit_metro_esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0 +adafruit_metro_esp32s2.menu.MSCOnBoot.msc=Enabled +adafruit_metro_esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +adafruit_metro_esp32s2.menu.DFUOnBoot.default=Disabled +adafruit_metro_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +adafruit_metro_esp32s2.menu.DFUOnBoot.dfu=Enabled +adafruit_metro_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 adafruit_metro_esp32s2.menu.PSRAM.enabled=Enabled adafruit_metro_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -3487,7 +3658,9 @@ adafruit_magtag29_esp32s2.build.core=esp32 adafruit_magtag29_esp32s2.build.variant=adafruit_magtag29_esp32s2 adafruit_magtag29_esp32s2.build.board=MAGTAG29_ESP32S2 -adafruit_magtag29_esp32s2.build.serial=0 +adafruit_magtag29_esp32s2.build.cdc_on_boot=1 +adafruit_magtag29_esp32s2.build.msc_on_boot=0 +adafruit_magtag29_esp32s2.build.dfu_on_boot=0 adafruit_magtag29_esp32s2.build.f_cpu=240000000L adafruit_magtag29_esp32s2.build.flash_size=4MB adafruit_magtag29_esp32s2.build.flash_freq=80m @@ -3496,10 +3669,20 @@ adafruit_magtag29_esp32s2.build.boot=qio adafruit_magtag29_esp32s2.build.partitions=default adafruit_magtag29_esp32s2.build.defines= -adafruit_magtag29_esp32s2.menu.SerialMode.cdc=USB CDC -adafruit_magtag29_esp32s2.menu.SerialMode.cdc.build.serial=1 -adafruit_magtag29_esp32s2.menu.SerialMode.default=UART0 -adafruit_magtag29_esp32s2.menu.SerialMode.default.build.serial=0 +adafruit_magtag29_esp32s2.menu.CDCOnBoot.cdc=Enabled +adafruit_magtag29_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +adafruit_magtag29_esp32s2.menu.CDCOnBoot.default=Disabled +adafruit_magtag29_esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +adafruit_magtag29_esp32s2.menu.MSCOnBoot.default=Disabled +adafruit_magtag29_esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0 +adafruit_magtag29_esp32s2.menu.MSCOnBoot.msc=Enabled +adafruit_magtag29_esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +adafruit_magtag29_esp32s2.menu.DFUOnBoot.default=Disabled +adafruit_magtag29_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +adafruit_magtag29_esp32s2.menu.DFUOnBoot.dfu=Enabled +adafruit_magtag29_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 adafruit_magtag29_esp32s2.menu.PSRAM.enabled=Enabled adafruit_magtag29_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -3640,7 +3823,9 @@ adafruit_funhouse_esp32s2.build.core=esp32 adafruit_funhouse_esp32s2.build.variant=adafruit_funhouse_esp32s2 adafruit_funhouse_esp32s2.build.board=FUNHOUSE_ESP32S2 -adafruit_funhouse_esp32s2.build.serial=0 +adafruit_funhouse_esp32s2.build.cdc_on_boot=1 +adafruit_funhouse_esp32s2.build.msc_on_boot=0 +adafruit_funhouse_esp32s2.build.dfu_on_boot=0 adafruit_funhouse_esp32s2.build.f_cpu=240000000L adafruit_funhouse_esp32s2.build.flash_size=4MB adafruit_funhouse_esp32s2.build.flash_freq=80m @@ -3649,10 +3834,20 @@ adafruit_funhouse_esp32s2.build.boot=qio adafruit_funhouse_esp32s2.build.partitions=default adafruit_funhouse_esp32s2.build.defines= -adafruit_funhouse_esp32s2.menu.SerialMode.cdc=USB CDC -adafruit_funhouse_esp32s2.menu.SerialMode.cdc.build.serial=1 -adafruit_funhouse_esp32s2.menu.SerialMode.default=UART0 -adafruit_funhouse_esp32s2.menu.SerialMode.default.build.serial=0 +adafruit_funhouse_esp32s2.menu.CDCOnBoot.cdc=Enabled +adafruit_funhouse_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +adafruit_funhouse_esp32s2.menu.CDCOnBoot.default=Disabled +adafruit_funhouse_esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +adafruit_funhouse_esp32s2.menu.MSCOnBoot.default=Disabled +adafruit_funhouse_esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0 +adafruit_funhouse_esp32s2.menu.MSCOnBoot.msc=Enabled +adafruit_funhouse_esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +adafruit_funhouse_esp32s2.menu.DFUOnBoot.default=Disabled +adafruit_funhouse_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0 +adafruit_funhouse_esp32s2.menu.DFUOnBoot.dfu=Enabled +adafruit_funhouse_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 adafruit_funhouse_esp32s2.menu.PSRAM.enabled=Enabled adafruit_funhouse_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM @@ -3793,7 +3988,9 @@ adafruit_feather_esp32s2_nopsram.build.core=esp32 adafruit_feather_esp32s2_nopsram.build.variant=adafruit_feather_esp32s2 adafruit_feather_esp32s2_nopsram.build.board=ADAFRUIT_FEATHER_ESP32S2_NOPSRAM -adafruit_feather_esp32s2_nopsram.build.serial=0 +adafruit_feather_esp32s2_nopsram.build.cdc_on_boot=0 +adafruit_feather_esp32s2_nopsram.build.msc_on_boot=0 +adafruit_feather_esp32s2_nopsram.build.dfu_on_boot=0 adafruit_feather_esp32s2_nopsram.build.f_cpu=240000000L adafruit_feather_esp32s2_nopsram.build.flash_size=4MB adafruit_feather_esp32s2_nopsram.build.flash_freq=80m @@ -3802,10 +3999,20 @@ adafruit_feather_esp32s2_nopsram.build.boot=qio adafruit_feather_esp32s2_nopsram.build.partitions=default adafruit_feather_esp32s2_nopsram.build.defines= -adafruit_feather_esp32s2_nopsram.menu.SerialMode.cdc=USB CDC -adafruit_feather_esp32s2_nopsram.menu.SerialMode.cdc.build.serial=1 -adafruit_feather_esp32s2_nopsram.menu.SerialMode.default=UART0 -adafruit_feather_esp32s2_nopsram.menu.SerialMode.default.build.serial=0 +adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.cdc=Enabled +adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.cdc.build.cdc_on_boot=1 +adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.default=Disabled +adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.default.build.cdc_on_boot=0 + +adafruit_feather_esp32s2_nopsram.menu.MSCOnBoot.default=Disabled +adafruit_feather_esp32s2_nopsram.menu.MSCOnBoot.default.build.msc_on_boot=0 +adafruit_feather_esp32s2_nopsram.menu.MSCOnBoot.msc=Enabled +adafruit_feather_esp32s2_nopsram.menu.MSCOnBoot.msc.build.msc_on_boot=1 + +adafruit_feather_esp32s2_nopsram.menu.DFUOnBoot.default=Disabled +adafruit_feather_esp32s2_nopsram.menu.DFUOnBoot.default.build.dfu_on_boot=0 +adafruit_feather_esp32s2_nopsram.menu.DFUOnBoot.dfu=Enabled +adafruit_feather_esp32s2_nopsram.menu.DFUOnBoot.dfu.build.dfu_on_boot=1 adafruit_feather_esp32s2_nopsram.menu.PSRAM.disabled=Disabled adafruit_feather_esp32s2_nopsram.menu.PSRAM.disabled.build.defines= diff --git a/cores/esp32/FirmwareMSC.cpp b/cores/esp32/FirmwareMSC.cpp new file mode 100644 index 00000000..c399a013 --- /dev/null +++ b/cores/esp32/FirmwareMSC.cpp @@ -0,0 +1,423 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "FirmwareMSC.h" +#include "esp_partition.h" +#include "esp_ota_ops.h" +#include "esp32-hal.h" +#include "pins_arduino.h" +#include "firmware_msc_fat.h" + +#if CONFIG_TINYUSB_MSC_ENABLED + +#ifndef USB_FW_MSC_VENDOR_ID +#define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars +#endif +#ifndef USB_FW_MSC_PRODUCT_ID +#define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars +#endif +#ifndef USB_FW_MSC_PRODUCT_REVISION +#define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars +#endif +#ifndef USB_FW_MSC_VOLUME_NAME +#define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars +#endif +#ifndef USB_FW_MSC_SERIAL_NUMBER +#define USB_FW_MSC_SERIAL_NUMBER 0x00000000 +#endif + +ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +//General Variables +static uint8_t * msc_ram_disk = NULL; +static fat_boot_sector_t * msc_boot = NULL; +static uint8_t * msc_table = NULL; +static uint16_t msc_table_sectors = 0; +static uint16_t msc_total_sectors = 0; +static bool mcs_is_fat16 = false; + +//Firmware Read +static const esp_partition_t* msc_run_partition = NULL; +static uint16_t fw_start_sector = 0; +static uint16_t fw_end_sector = 0; +static size_t fw_size = 0; +static fat_dir_entry_t * fw_entry = NULL; + +//Firmware Write +typedef enum { + MSC_UPDATE_IDLE, + MSC_UPDATE_STARTING, + MSC_UPDATE_RUNNING, + MSC_UPDATE_END +} msc_update_state_t; + +static const esp_partition_t* msc_ota_partition = NULL; +static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE; +static uint16_t msc_update_start_sector = 0; +static uint32_t msc_update_bytes_written = 0; +static fat_dir_entry_t * msc_update_entry = NULL; + +static uint32_t get_firmware_size(const esp_partition_t* partition){ + esp_image_metadata_t data; + const esp_partition_pos_t running_pos = { + .offset = partition->address, + .size = partition->size, + }; + data.start_addr = running_pos.offset; + esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data); + return data.image_len; +} + +//Get number of sectors required based on the size of the firmware and OTA partition +static size_t msc_update_get_required_disk_sectors(){ + size_t data_sectors = 16; + size_t total_sectors = 0; + msc_run_partition = esp_ota_get_running_partition(); + msc_ota_partition = esp_ota_get_next_update_partition(NULL); + if(msc_run_partition){ + fw_size = get_firmware_size(msc_run_partition); + data_sectors += FAT_SIZE_TO_SECTORS(fw_size); + log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size)); + } else { + log_w("APP partition not found. Reading disabled"); + } + if(msc_ota_partition){ + data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size); + log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size)); + } else { + log_w("OTA partition not found. Writing disabled"); + } + msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false); + total_sectors = data_sectors + msc_table_sectors + 2; + if(total_sectors > 0xFF4){ + log_d("USING FAT16"); + mcs_is_fat16 = true; + total_sectors -= msc_table_sectors; + msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true); + total_sectors += msc_table_sectors; + } else { + log_d("USING FAT12"); + mcs_is_fat16 = false; + } + log_d("FAT data sectors: %u", data_sectors); + log_d("FAT table sectors: %u", msc_table_sectors); + log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024); + return total_sectors; +} + +//setup the ramdisk and add the firmware download file +static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){ + msc_total_sectors = msc_update_get_required_disk_sectors(); + uint8_t ram_sectors = msc_table_sectors + 2; + msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE); + if(!msc_ram_disk){ + log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE); + return false; + } + fw_start_sector = ram_sectors; + fw_end_sector = fw_start_sector; + msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number); + msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16); + //fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label); + if(msc_run_partition){ + fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16); + fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector; + } + return true; +} + +static void msc_update_delete_disk(){ + fw_entry = NULL; + fw_size = 0; + fw_end_sector = 0; + fw_start_sector = 0; + msc_table = NULL; + msc_boot = NULL; + msc_table_sectors = 0; + msc_total_sectors = 0; + msc_run_partition = NULL; + msc_ota_partition = NULL; + msc_update_state = MSC_UPDATE_IDLE; + msc_update_start_sector = 0; + msc_update_bytes_written = 0; + msc_update_entry = NULL; + free(msc_ram_disk); + msc_ram_disk = NULL; +} + +//filter out entries to only include BINs in the root folder +static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){ + fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); + fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry; + + //empty entry + if(entry->file_magic == 0){ + return NULL; + } + //long file name + if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){ + return NULL; + } + //only files marked as archives + if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){ + return NULL; + } + //deleted + if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){ + return NULL; + } + //not bins + if(memcmp("BIN", entry->file_extension, 3)){ + return NULL; + } + return entry; +} + +//get an empty bin (the host will add an entry for file about to be written with size of zero) +static fat_dir_entry_t * msc_update_find_new_bin(){ + for(uint8_t i=16; i;){ + i--; + fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); + if(entry && entry->file_size == 0){ + return entry; + } + } + return NULL; +} + +//get a bin starting from particular sector +static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){ + for(uint8_t i=16; i; ){ + i--; + fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); + if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){ + return entry; + } + } + return NULL; +} + +//write the new data and erase the flash blocks when necessary +static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){ + esp_err_t err = ESP_OK; + if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){ + err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE); + log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK"); + if(err != ESP_OK){ + return err; + } + } + return esp_partition_write(partition, offset, data, size); +} + +//called when error was encountered while updating +static void msc_update_error(){ + log_e("UPDATE_ERROR: %u", msc_update_bytes_written); + arduino_firmware_msc_event_data_t p = {0}; + p.error.size = msc_update_bytes_written; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + msc_update_state = MSC_UPDATE_IDLE; + msc_update_entry = NULL; + msc_update_bytes_written = 0; + msc_update_start_sector = 0; +} + +//called when all firmware bytes have been received +static void msc_update_end(){ + log_d("UPDATE_END: %u", msc_update_entry->file_size); + msc_update_state = MSC_UPDATE_END; + size_t ota_size = get_firmware_size(msc_ota_partition); + if(ota_size != msc_update_entry->file_size){ + log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size); + msc_update_error(); + return; + } + if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){ + log_e("ENABLING OTA PARTITION FAILED"); + msc_update_error(); + return; + } + arduino_firmware_msc_event_data_t p = {0}; + p.end.size = msc_update_entry->file_size; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); +} + +static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){ + //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); + if(lba < fw_start_sector){ + //write to sectors that are in RAM + memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize); + if(msc_ota_partition && lba == (fw_start_sector - 1)){ + //monitor the root folder table + if(msc_update_state <= MSC_UPDATE_RUNNING){ + fat_dir_entry_t * update_entry = msc_update_find_new_bin(); + if(update_entry) { + if(msc_update_entry) { + log_v("REPLACING ENTRY"); + } else { + log_v("ASSIGNING ENTRY"); + } + if(msc_update_state <= MSC_UPDATE_STARTING){ + msc_update_state = MSC_UPDATE_STARTING; + msc_update_bytes_written = 0; + msc_update_start_sector = 0; + } + msc_update_entry = update_entry; + } else if(msc_update_state == MSC_UPDATE_RUNNING){ + if(!msc_update_entry && msc_update_start_sector){ + msc_update_entry = msc_update_find_bin(msc_update_start_sector); + } + if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){ + msc_update_end(); + } + } + } + } + } else if(msc_ota_partition && lba >= msc_update_start_sector){ + //handle writes to the region where the new firmware will be uploaded + arduino_firmware_msc_event_data_t p = {0}; + if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){ + msc_update_state = MSC_UPDATE_RUNNING; + msc_update_start_sector = lba; + msc_update_bytes_written = 0; + log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table); + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ + log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); + msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; + p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; + p.write.size = bufsize; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + } else { + msc_update_error(); + return 0; + } + } else if(msc_update_state == MSC_UPDATE_RUNNING){ + if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){ + bufsize = msc_update_entry->file_size - msc_update_bytes_written; + } + if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ + log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); + msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; + p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; + p.write.size = bufsize; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){ + msc_update_end(); + } + } else { + msc_update_error(); + return 0; + } + } + } + return bufsize; +} + +static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){ + //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); + if(lba < fw_start_sector){ + memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize); + } else if(msc_run_partition && lba < fw_end_sector){ + //read the currently running firmware + if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){ + return 0; + } + } else { + memset(buffer, 0, bufsize); + } + return bufsize; +} + +static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){ + //log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject); + arduino_firmware_msc_event_data_t p = {0}; + p.power.power_condition = power_condition; + p.power.start = start; + p.power.load_eject = load_eject; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + return true; +} + +static volatile TaskHandle_t msc_task_handle = NULL; +static void msc_task(void *pvParameters){ + for (;;) { + if(msc_update_state == MSC_UPDATE_END){ + delay(100); + esp_restart(); + } + delay(100); + } + msc_task_handle = NULL; + vTaskDelete(NULL); +} + +FirmwareMSC::FirmwareMSC():msc(){} + +FirmwareMSC::~FirmwareMSC(){ + end(); +} + +bool FirmwareMSC::begin(){ + if(msc_ram_disk){ + return true; + } + + if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){ + return false; + } + + if(!msc_task_handle){ + xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0); + if(!msc_task_handle){ + msc_update_delete_disk(); + return false; + } + } + + msc.vendorID(USB_FW_MSC_VENDOR_ID); + msc.productID(USB_FW_MSC_PRODUCT_ID); + msc.productRevision(USB_FW_MSC_PRODUCT_REVISION); + msc.onStartStop(msc_start_stop); + msc.onRead(msc_read); + msc.onWrite(msc_write); + msc.mediaPresent(true); + msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE); + return true; +} + +void FirmwareMSC::end(){ + msc.end(); + if(msc_task_handle){ + vTaskDelete(msc_task_handle); + msc_task_handle = NULL; + } + msc_update_delete_disk(); +} + +void FirmwareMSC::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback); +} +void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this); +} + +#if ARDUINO_USB_MSC_ON_BOOT +FirmwareMSC MSC_Update; +#endif + +#endif /* CONFIG_USB_MSC_ENABLED */ diff --git a/cores/esp32/FirmwareMSC.h b/cores/esp32/FirmwareMSC.h new file mode 100644 index 00000000..3caaf6a0 --- /dev/null +++ b/cores/esp32/FirmwareMSC.h @@ -0,0 +1,69 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include "USBMSC.h" +#if CONFIG_TINYUSB_MSC_ENABLED + +#include "esp_event.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); + +typedef enum { + ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_FIRMWARE_MSC_START_EVENT = 0, + ARDUINO_FIRMWARE_MSC_WRITE_EVENT, + ARDUINO_FIRMWARE_MSC_END_EVENT, + ARDUINO_FIRMWARE_MSC_ERROR_EVENT, + ARDUINO_FIRMWARE_MSC_POWER_EVENT, + ARDUINO_FIRMWARE_MSC_MAX_EVENT, +} arduino_firmware_msc_event_t; + +typedef union { + struct { + size_t offset; + size_t size; + } write; + struct { + uint8_t power_condition; + bool start; + bool load_eject; + } power; + struct { + size_t size; + } end; + struct { + size_t size; + } error; +} arduino_firmware_msc_event_data_t; + +class FirmwareMSC { +private: + USBMSC msc; + +public: + FirmwareMSC(); + ~FirmwareMSC(); + bool begin(); + void end(); + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback); +}; + +#if ARDUINO_USB_MSC_ON_BOOT +extern FirmwareMSC MSC_Update; +#endif + +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 7eb75354..2f1cb25d 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -37,7 +37,7 @@ #endif #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC HardwareSerial Serial0(0); #else HardwareSerial Serial(0); diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 1ea76917..795b8b68 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -113,10 +113,10 @@ protected: extern void serialEventRun(void) __attribute__((weak)); #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) -#ifndef ARDUINO_SERIAL_PORT -#define ARDUINO_SERIAL_PORT 0 +#ifndef ARDUINO_USB_CDC_ON_BOOT +#define ARDUINO_USB_CDC_ON_BOOT 0 #endif -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC #include "USB.h" #include "USBCDC.h" extern HardwareSerial Serial0; diff --git a/cores/esp32/USB.cpp b/cores/esp32/USB.cpp index 4ce28a6c..1221707c 100644 --- a/cores/esp32/USB.cpp +++ b/cores/esp32/USB.cpp @@ -31,14 +31,16 @@ #ifndef USB_SERIAL #define USB_SERIAL "0" #endif +#ifndef USB_WEBUSB_ENABLED +#define USB_WEBUSB_ENABLED false +#endif +#ifndef USB_WEBUSB_URL +#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html" +#endif #if CFG_TUD_DFU_RUNTIME static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf) { -#define DFU_ATTR_CAN_DOWNLOAD 1 -#define DFU_ATTR_CAN_UPLOAD 2 -#define DFU_ATTR_MANIFESTATION_TOLERANT 4 -#define DFU_ATTR_WILL_DETACH 8 #define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT"); @@ -120,8 +122,8 @@ ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority) ,usb_protocol(MISC_PROTOCOL_IAD) ,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED) ,usb_power_ma(500) -,webusb_enabled(false) -,webusb_url("https://espressif.github.io/arduino-esp32/webusb.html") +,webusb_enabled(USB_WEBUSB_ENABLED) +,webusb_url(USB_WEBUSB_URL) ,_started(false) ,_task_stack_size(task_stack_size) ,_event_task_priority(event_task_priority) diff --git a/cores/esp32/USB.h b/cores/esp32/USB.h index 2a5fdb71..d64962c7 100644 --- a/cores/esp32/USB.h +++ b/cores/esp32/USB.h @@ -18,9 +18,11 @@ #include "Arduino.h" #include "USBCDC.h" - +#include "common/tusb_common.h" #include "esp_event.h" +#define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) + ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS); typedef enum { diff --git a/cores/esp32/USBCDC.cpp b/cores/esp32/USBCDC.cpp index 9dcd6bfb..7a9cf5e0 100644 --- a/cores/esp32/USBCDC.cpp +++ b/cores/esp32/USBCDC.cpp @@ -28,7 +28,6 @@ USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) { uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); - // Interface number, string index, attributes, detach timeout, transfer size */ uint8_t descriptor[TUD_CDC_DESC_LEN] = { // Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64) @@ -41,7 +40,6 @@ static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { - //isr_log_v("itf: %u, dtr: %u, rts: %u", itf, dtr, rts); if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ devices[itf]->_onLineState(dtr, rts); } @@ -50,7 +48,6 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) // Invoked when line coding is change via SET_LINE_CODING void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) { - //isr_log_v("itf: %u, bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u", itf, p_line_coding->bit_rate, p_line_coding->data_bits, p_line_coding->stop_bits, p_line_coding->parity); if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); } @@ -59,7 +56,6 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) // Invoked when received new data void tud_cdc_rx_cb(uint8_t itf) { - //isr_log_v("itf: %u", itf); if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ devices[itf]->_onRX(); } @@ -72,15 +68,14 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){ // Invoked when space becomes available in TX buffer void tud_cdc_tx_complete_cb(uint8_t itf){ - //isr_log_v("itf: %u", itf); - if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ + if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL && devices[itf]->tx_sem != NULL){ xSemaphoreGive(devices[itf]->tx_sem); devices[itf]->_onTX(); } } static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){ - if(itf >= MAX_USB_CDC_DEVICES){ + if(itf >= MAX_USB_CDC_DEVICES || devices[itf] == NULL || devices[itf]->tx_sem == NULL){ return 0; } if(!tud_cdc_n_connected(itf)){ @@ -90,8 +85,15 @@ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size) while(tosend){ uint32_t space = tud_cdc_n_write_available(itf); if(!space){ - delay(1); - continue; + //make sure that we do not get previous semaphore + xSemaphoreTake(devices[itf]->tx_sem, 0); + //wait for tx_complete + if(xSemaphoreTake(devices[itf]->tx_sem, 200 / portTICK_PERIOD_MS) == pdTRUE){ + space = tud_cdc_n_write_available(itf); + } + if(!space){ + return sofar; + } } if(tosend < space){ space = tosend; @@ -103,7 +105,7 @@ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size) sofar += sent; tosend -= sent; tud_cdc_n_write_flush(itf); - xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY); + //xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY); } return sofar; } @@ -113,21 +115,21 @@ static void ARDUINO_ISR_ATTR cdc0_write_char(char c) tinyusb_cdc_write(0, (const uint8_t *)&c, 1); } -//void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); - static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ ((USBCDC*)arg)->_onUnplugged(); } -USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL) { +USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_sem(NULL) { tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor); if(itf < MAX_USB_CDC_DEVICES){ - devices[itf] = this; - tx_sem = NULL; arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this); } } +USBCDC::~USBCDC(){ + end(); +} + void USBCDC::onEvent(esp_event_handler_t callback){ onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback); } @@ -137,6 +139,10 @@ void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback size_t USBCDC::setRxBufferSize(size_t rx_queue_len){ if(rx_queue){ + if(!rx_queue_len){ + vQueueDelete(rx_queue); + rx_queue = NULL; + } return 0; } rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); @@ -148,15 +154,19 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){ void USBCDC::begin(unsigned long baud) { - setRxBufferSize(256);//default if not preset if(tx_sem == NULL){ tx_sem = xSemaphoreCreateBinary(); xSemaphoreTake(tx_sem, 0); } + setRxBufferSize(256);//default if not preset + devices[itf] = this; } void USBCDC::end() { + connected = false; + devices[itf] = NULL; + setRxBufferSize(0); if (tx_sem != NULL) { vSemaphoreDelete(tx_sem); tx_sem = NULL; @@ -176,6 +186,11 @@ void USBCDC::_onUnplugged(void){ enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 }; void USBCDC::_onLineState(bool _dtr, bool _rts){ static uint8_t lineState = CDC_LINE_IDLE; + + if(dtr == _dtr && rts == _rts){ + return; // Skip duplicate events + } + dtr = _dtr; rts = _rts; @@ -183,6 +198,11 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){ if(!dtr && rts){ if(lineState == CDC_LINE_IDLE){ lineState++; + if(connected){ + connected = false; + arduino_usb_cdc_event_data_t p = {0}; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } } else { lineState = CDC_LINE_IDLE; } @@ -212,7 +232,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){ connected = true; arduino_usb_cdc_event_data_t p = {0}; arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); - } else if(!dtr && !rts && connected){ + } else if(!dtr && connected){ connected = false; arduino_usb_cdc_event_data_t p = {0}; arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); @@ -228,7 +248,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){ void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){ if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){ // ArduinoIDE sends LineCoding with 1200bps baud to reset the device - if(_bit_rate == 1200){ + if(reboot_enable && _bit_rate == 1200){ usb_persist_restart(RESTART_BOOTLOADER); } else { bit_rate = _bit_rate; @@ -317,7 +337,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size) void USBCDC::flush(void) { - if(itf >= MAX_USB_CDC_DEVICES){ + if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){ return; } tud_cdc_n_write_flush(itf); @@ -325,7 +345,7 @@ void USBCDC::flush(void) int USBCDC::availableForWrite(void) { - if(itf >= MAX_USB_CDC_DEVICES){ + if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){ return -1; } return tud_cdc_n_write_available(itf); @@ -364,7 +384,7 @@ USBCDC::operator bool() const return connected; } -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC USBCDC Serial(0); #endif diff --git a/cores/esp32/USBCDC.h b/cores/esp32/USBCDC.h index d9a6376d..26df8a3c 100644 --- a/cores/esp32/USBCDC.h +++ b/cores/esp32/USBCDC.h @@ -54,6 +54,7 @@ class USBCDC: public Stream { public: USBCDC(uint8_t itf=0); + ~USBCDC(); void onEvent(esp_event_handler_t callback); void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback); @@ -129,7 +130,7 @@ protected: }; -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC extern USBCDC Serial; #endif diff --git a/cores/esp32/USBMSC.cpp b/cores/esp32/USBMSC.cpp new file mode 100644 index 00000000..c6327ecd --- /dev/null +++ b/cores/esp32/USBMSC.cpp @@ -0,0 +1,260 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "USBMSC.h" + +#if CFG_TUD_MSC +extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf) +{ + uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); + uint8_t ep_num = tinyusb_get_free_duplex_endpoint(); + TU_VERIFY (ep_num != 0); + uint8_t descriptor[TUD_MSC_DESC_LEN] = { + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) + }; + *itf+=1; + memcpy(dst, descriptor, TUD_MSC_DESC_LEN); + return TUD_MSC_DESC_LEN; +} + +typedef struct { + bool media_present; + uint8_t vendor_id[8]; + uint8_t product_id[16]; + uint8_t product_rev[4]; + uint16_t block_size; + uint32_t block_count; + bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject); + int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); +} msc_lun_t; + +static const uint8_t MSC_MAX_LUN = 3; +static uint8_t MSC_ACTIVE_LUN = 0; +static msc_lun_t msc_luns[MSC_MAX_LUN]; + +static void cplstr(void *dst, const void * src, size_t max_len){ + if(!src || !dst || !max_len){ + return; + } + size_t l = strlen((const char *)src); + if(l > max_len){ + l = max_len; + } + memcpy(dst, src, l); +} + +// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation +uint8_t tud_msc_get_maxlun_cb(void) +{ + log_v("%u", MSC_ACTIVE_LUN); + return MSC_ACTIVE_LUN; +} + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + log_v("[%u]", lun); + cplstr(vendor_id , msc_luns[lun].vendor_id, 8); + cplstr(product_id , msc_luns[lun].product_id, 16); + cplstr(product_rev, msc_luns[lun].product_rev, 4); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + log_v("[%u]: %u", lun, msc_luns[lun].media_present); + return msc_luns[lun].media_present; // RAM disk is always ready +} + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) +{ + log_v("[%u]", lun); + if(!msc_luns[lun].media_present){ + *block_count = 0; + *block_size = 0; + return; + } + + *block_count = msc_luns[lun].block_count; + *block_size = msc_luns[lun].block_size; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) +{ + log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject); + if(msc_luns[lun].start_stop){ + return msc_luns[lun].start_stop(power_condition, start, load_eject); + } + return true; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) +{ + log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); + if(!msc_luns[lun].media_present){ + return 0; + } + if(msc_luns[lun].read){ + return msc_luns[lun].read(lba, offset, buffer, bufsize); + } + return 0; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) +{ + log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); + if(!msc_luns[lun].media_present){ + return 0; + } + if(msc_luns[lun].write){ + return msc_luns[lun].write(lba, offset, buffer, bufsize); + } + return 0; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) +{ + // read10 & write10 has their own callback and MUST not be handled here + log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize); + + void const* response = NULL; + uint16_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + if(!msc_luns[lun].media_present){ + return -1; + } + + switch (scsi_cmd[0]) { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if (resplen > bufsize) resplen = bufsize; + + if (response && (resplen > 0)) { + if (in_xfer) { + memcpy(buffer, response, resplen); + } else { + // SCSI output + } + } + + return resplen; +} + +USBMSC::USBMSC(){ + if(MSC_ACTIVE_LUN < MSC_MAX_LUN){ + _lun = MSC_ACTIVE_LUN; + MSC_ACTIVE_LUN++; + msc_luns[_lun].media_present = false; + msc_luns[_lun].vendor_id[0] = 0; + msc_luns[_lun].product_id[0] = 0; + msc_luns[_lun].product_rev[0] = 0; + msc_luns[_lun].block_size = 0; + msc_luns[_lun].block_count = 0; + msc_luns[_lun].start_stop = NULL; + msc_luns[_lun].read = NULL; + msc_luns[_lun].write = NULL; + } + if(_lun == 0){ + tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor); + } +} + +USBMSC::~USBMSC(){ + end(); +} + +bool USBMSC::begin(uint32_t block_count, uint16_t block_size){ + msc_luns[_lun].block_size = block_size; + msc_luns[_lun].block_count = block_count; + if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){ + return false; + } + return true; +} + +void USBMSC::end(){ + msc_luns[_lun].media_present = false; + msc_luns[_lun].vendor_id[0] = 0; + msc_luns[_lun].product_id[0] = 0; + msc_luns[_lun].product_rev[0] = 0; + msc_luns[_lun].block_size = 0; + msc_luns[_lun].block_count = 0; + msc_luns[_lun].start_stop = NULL; + msc_luns[_lun].read = NULL; + msc_luns[_lun].write = NULL; +} + +void USBMSC::vendorID(const char * vid){ + cplstr(msc_luns[_lun].vendor_id, vid, 8); +} + +void USBMSC::productID(const char * pid){ + cplstr(msc_luns[_lun].product_id, pid, 16); +} + +void USBMSC::productRevision(const char * rev){ + cplstr(msc_luns[_lun].product_rev, rev, 4); +} + +void USBMSC::onStartStop(msc_start_stop_cb cb){ + msc_luns[_lun].start_stop = cb; +} + +void USBMSC::onRead(msc_read_cb cb){ + msc_luns[_lun].read = cb; +} + +void USBMSC::onWrite(msc_write_cb cb){ + msc_luns[_lun].write = cb; +} + +void USBMSC::mediaPresent(bool media_present){ + msc_luns[_lun].media_present = media_present; +} + +#endif /* CONFIG_USB_MSC_ENABLED */ diff --git a/cores/esp32/USBMSC.h b/cores/esp32/USBMSC.h new file mode 100644 index 00000000..799322a3 --- /dev/null +++ b/cores/esp32/USBMSC.h @@ -0,0 +1,49 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include +#include "esp32-hal.h" +#if CONFIG_TINYUSB_MSC_ENABLED + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject); + +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + +// Process data in buffer to disk's storage and return number of written bytes +typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); + +class USBMSC +{ +public: + USBMSC(); + ~USBMSC(); + bool begin(uint32_t block_count, uint16_t block_size); + void end(); + void vendorID(const char * vid);//max 8 chars + void productID(const char * pid);//max 16 chars + void productRevision(const char * ver);//max 4 chars + void mediaPresent(bool media_present); + void onStartStop(msc_start_stop_cb cb); + void onRead(msc_read_cb cb); + void onWrite(msc_write_cb cb); +private: + uint8_t _lun; +}; +#endif diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 6e8ad868..0da912b0 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -72,20 +72,15 @@ static void configure_pins(usb_hal_context_t *usb) esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) { - log_i("Driver installation..."); - - // Hal init usb_hal_context_t hal = { .use_external_phy = config->external_phy }; usb_hal_init(&hal); configure_pins(&hal); - if (!tusb_init()) { log_e("Can't initialize the TinyUSB stack."); return ESP_FAIL; } - log_i("Driver installed"); return ESP_OK; } @@ -106,6 +101,7 @@ static tusb_str_t WEBUSB_URL = ""; static tusb_str_t USB_DEVICE_PRODUCT = ""; static tusb_str_t USB_DEVICE_MANUFACTURER = ""; static tusb_str_t USB_DEVICE_SERIAL = ""; +static tusb_str_t USB_DEVICE_LANGUAGE = "\x09\x04";//English (0x0409) static uint8_t USB_DEVICE_ATTRIBUTES = 0; static uint16_t USB_DEVICE_POWER = 0; @@ -140,7 +136,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = { static uint32_t tinyusb_string_descriptor_len = 4; static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { // array of pointer to string descriptors - "\x09\x04", // 0: is supported language is English (0x0409) + USB_DEVICE_LANGUAGE, // 0: is supported language USB_DEVICE_MANUFACTURER,// 1: Manufacturer USB_DEVICE_PRODUCT, // 2: Product USB_DEVICE_SERIAL, // 3: Serials, should use chip ID @@ -563,31 +559,37 @@ static void usb_device_task(void *param) { /* * PUBLIC API * */ +static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"}; + +static bool tinyusb_is_initialized = false; esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb) { + if(tinyusb_is_initialized){ + log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); + return ESP_FAIL; + } if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){ - log_e("Interface %u not enabled", interface); + log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); return ESP_FAIL; } tinyusb_loaded_interfaces_mask |= (1U << interface); tinyusb_config_descriptor_len += descriptor_len; tinyusb_loaded_interfaces_callbacks[interface] = cb; - log_d("Interface %u enabled", interface); + log_d("Interface %s enabled", tinyusb_interface_names[interface]); return ESP_OK; } esp_err_t tinyusb_init(tinyusb_device_config_t *config) { - static bool initialized = false; - if(initialized){ + if(tinyusb_is_initialized){ return ESP_OK; } - initialized = true; + tinyusb_is_initialized = true; tinyusb_endpoints.val = 0; tinyusb_apply_device_config(config); if (!tinyusb_load_enabled_interfaces()) { - initialized = false; + tinyusb_is_initialized = false; return ESP_FAIL; } @@ -605,7 +607,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { } if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) { - initialized = false; + tinyusb_is_initialized = false; return ESP_FAIL; } @@ -614,7 +616,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { }; esp_err_t err = tinyusb_driver_install(&tusb_cfg); if (err != ESP_OK) { - initialized = false; + tinyusb_is_initialized = false; return err; } xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL); @@ -690,84 +692,4 @@ uint8_t tinyusb_get_free_out_endpoint(void){ return 0; } -/* -void usb_dw_reg_dump(void) -{ -#define USB_PRINT_REG(r) printf("USB0." #r " = 0x%x;\n", USB0.r) -#define USB_PRINT_IREG(i, r) printf("USB0.in_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.in_ep_reg[i].r) -#define USB_PRINT_OREG(i, r) printf("USB0.out_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.out_ep_reg[i].r) - uint8_t i; - USB_PRINT_REG(gotgctl); - USB_PRINT_REG(gotgint); - USB_PRINT_REG(gahbcfg); - USB_PRINT_REG(gusbcfg); - USB_PRINT_REG(grstctl); - USB_PRINT_REG(gintsts); - USB_PRINT_REG(gintmsk); - USB_PRINT_REG(grxstsr); - USB_PRINT_REG(grxstsp); - USB_PRINT_REG(grxfsiz); - USB_PRINT_REG(gnptxsts); - USB_PRINT_REG(gpvndctl); - USB_PRINT_REG(ggpio); - USB_PRINT_REG(guid); - USB_PRINT_REG(gsnpsid); - USB_PRINT_REG(ghwcfg1); - USB_PRINT_REG(ghwcfg2); - USB_PRINT_REG(ghwcfg3); - USB_PRINT_REG(ghwcfg4); - USB_PRINT_REG(glpmcfg); - USB_PRINT_REG(gpwrdn); - USB_PRINT_REG(gdfifocfg); - USB_PRINT_REG(gadpctl); - USB_PRINT_REG(hptxfsiz); - USB_PRINT_REG(hcfg); - USB_PRINT_REG(hfir); - USB_PRINT_REG(hfnum); - USB_PRINT_REG(hptxsts); - USB_PRINT_REG(haint); - USB_PRINT_REG(haintmsk); - USB_PRINT_REG(hflbaddr); - USB_PRINT_REG(hprt); - USB_PRINT_REG(dcfg); - USB_PRINT_REG(dctl); - USB_PRINT_REG(dsts); - USB_PRINT_REG(diepmsk); - USB_PRINT_REG(doepmsk); - USB_PRINT_REG(daint); - USB_PRINT_REG(daintmsk); - USB_PRINT_REG(dtknqr1); - USB_PRINT_REG(dtknqr2); - USB_PRINT_REG(dvbusdis); - USB_PRINT_REG(dvbuspulse); - USB_PRINT_REG(dtknqr3_dthrctl); - USB_PRINT_REG(dtknqr4_fifoemptymsk); - USB_PRINT_REG(deachint); - USB_PRINT_REG(deachintmsk); - USB_PRINT_REG(pcgctrl); - USB_PRINT_REG(pcgctrl1); - USB_PRINT_REG(gnptxfsiz); - for (i = 0; i < 4; i++) { - printf("USB0.dieptxf[%u] = 0x%x;\n", i, USB0.dieptxf[i]); - } -// for (i = 0; i < 16; i++) { -// printf("USB0.diepeachintmsk[%u] = 0x%x;\n", i, USB0.diepeachintmsk[i]); -// } -// for (i = 0; i < 16; i++) { -// printf("USB0.doepeachintmsk[%u] = 0x%x;\n", i, USB0.doepeachintmsk[i]); -// } - for (i = 0; i < 7; i++) { - printf("// EP %u:\n", i); - USB_PRINT_IREG(i, diepctl); - USB_PRINT_IREG(i, diepint); - USB_PRINT_IREG(i, dieptsiz); - USB_PRINT_IREG(i, diepdma); - USB_PRINT_IREG(i, dtxfsts); - USB_PRINT_OREG(i, doepctl); - USB_PRINT_OREG(i, doepint); - USB_PRINT_OREG(i, doeptsiz); - USB_PRINT_OREG(i, doepdma); - } -} - */ #endif /* CONFIG_TINYUSB_ENABLED */ diff --git a/cores/esp32/esp32-hal-tinyusb.h b/cores/esp32/esp32-hal-tinyusb.h index abef6410..7332887a 100644 --- a/cores/esp32/esp32-hal-tinyusb.h +++ b/cores/esp32/esp32-hal-tinyusb.h @@ -82,11 +82,11 @@ void usb_persist_restart(restart_type_t mode); // The following definitions and functions are to be used only by the drivers typedef enum { - USB_INTERFACE_CDC, + USB_INTERFACE_MSC, USB_INTERFACE_DFU, USB_INTERFACE_HID, USB_INTERFACE_VENDOR, - USB_INTERFACE_MSC, + USB_INTERFACE_CDC, USB_INTERFACE_MIDI, USB_INTERFACE_CUSTOM, USB_INTERFACE_MAX diff --git a/cores/esp32/firmware_msc_fat.c b/cores/esp32/firmware_msc_fat.c new file mode 100644 index 00000000..bc7ad550 --- /dev/null +++ b/cores/esp32/firmware_msc_fat.c @@ -0,0 +1,204 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "firmware_msc_fat.h" +//copy up to max_len chars from src to dst and do not terminate +static size_t cplstr(void *dst, const void * src, size_t max_len){ + if(!src || !dst || !max_len){ + return 0; + } + size_t l = strlen((const char *)src); + if(l > max_len){ + l = max_len; + } + memcpy(dst, src, l); + return l; +} + +//copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate +static void cplstrsp(void *dst, const void * src, size_t max_len){ + size_t l = cplstr(dst, src, max_len); + for(l; l < max_len; l++){ + ((uint8_t*)dst)[l] = 0x20; + } +} + +// FAT12 +static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12"; + +static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){ + uint32_t required_bytes = (((sector_num * 3)+1)/2); + return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0); +} + +static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){ + memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); + uint8_t * d = dst + DISK_SECTOR_SIZE; + d[0] = 0xF8; + d[1] = 0xFF; + d[2] = 0xFF; + return d; +} + +static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ + uint16_t offset = (index >> 1) * 3; + uint8_t * data = table + offset; + if(index & 1){ + data[2] = (value >> 4) & 0xFF; + data[1] = (data[1] & 0xF) | ((value & 0xF) << 4); + } else { + data[0] = value & 0xFF; + data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF); + } +} + +//FAT16 +static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16"; + +static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){ + uint32_t required_bytes = sector_num * 2; + return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0); +} + +static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){ + memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); + uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE); + d[0] = 0xFFF8; + d[1] = 0xFFFF; + return (uint8_t *)d; +} + +static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ + uint16_t offset = index * 2; + *(uint16_t *)(table + offset) = value; +} + +//Interface +const char * fat_file_system_type(bool fat16) { + return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE); +} + +uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){ + if(fat16){ + return fat16_sectors_per_alloc_table(sector_num); + } + return fat12_sectors_per_alloc_table(sector_num); +} + +uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){ + if(fat16){ + return fat16_add_table(dst, boot); + } + return fat12_add_table(dst, boot); +} + +void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){ + if(fat16){ + fat16_set_table_index(table, index, value); + } else { + fat12_set_table_index(table, index, value); + } +} + +fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){ + fat_boot_sector_t *boot = (fat_boot_sector_t*)dst; + boot->jump_instruction[0] = 0xEB; + boot->jump_instruction[1] = 0x3C; + boot->jump_instruction[2] = 0x90; + cplstr(boot->oem_name, "MSDOS5.0", 8); + boot->bytes_per_sector = DISK_SECTOR_SIZE; + boot->sectors_per_cluster = 1; + boot->reserved_sectors_count = 1; + boot->file_alloc_tables_num = 1; + boot->max_root_dir_entries = 16; + boot->fat12_sector_num = sector_num; + boot->media_descriptor = 0xF8; + boot->sectors_per_alloc_table = table_sectors; + boot->sectors_per_track = 1; + boot->num_heads = 1; + boot->hidden_sectors_count = 0; + boot->total_sectors_32 = 0; + boot->physical_drive_number = 0x00; + boot->reserved0 = 0x00; + boot->extended_boot_signature = 0x29; + boot->serial_number = serial_number; + cplstrsp(boot->volume_label, volume_label, 11); + memset(boot->reserved, 0, 448); + cplstrsp(boot->file_system_type, file_system_type, 8); + boot->signature = 0xAA55; + return boot; +} + +fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){ + fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; + fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE)); + memset(entry, 0, sizeof(fat_dir_entry_t)); + cplstrsp(entry->volume_label, volume_label, 11); + entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL; + return entry; +} + +fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){ + fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; + uint8_t * table = dst + DISK_SECTOR_SIZE; + fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); + memset(entry, 0, sizeof(fat_dir_entry_t)); + cplstrsp(entry->file_name, file_name, 8); + cplstrsp(entry->file_extension, file_extension, 3); + entry->file_attr = FAT_FILE_ATTR_ARCHIVE; + entry->file_size = file_size; + entry->data_start_sector = data_start_sector; + entry->extended_attr = 0; + + uint16_t file_sectors = file_size / DISK_SECTOR_SIZE; + if(file_size % DISK_SECTOR_SIZE){ + file_sectors++; + } + + uint16_t data_end_sector = data_start_sector + file_sectors; + for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){ + fat_set_table_index(table, i, i+1, is_fat16); + } + fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16); + + //Set Firmware Date based on the build time + static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + char mstr[8] = {'\0',}; + const char *str = __DATE__ " " __TIME__; + int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0; + int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds); + if(r >= 0){ + for(int i=0; i<12; i++){ + if(!strcmp(mstr, month_names_short[i])){ + month = i; + break; + } + } + entry->creation_time_ms = FAT_MS2V(seconds, ms); + entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds); + entry->creation_time_ymd = FAT_YMD2V(year, month, date); + entry->last_access_ymd = entry->creation_time_ymd; + entry->last_modified_hms = entry->creation_time_hms; + entry->last_modified_ymd = entry->creation_time_ymd; + } + return entry; +} + +uint8_t fat_lfn_checksum(const uint8_t *short_filename){ + uint8_t sum = 0; + for (uint8_t i = 11; i; i--) { + sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++; + } + return sum; +} diff --git a/cores/esp32/firmware_msc_fat.h b/cores/esp32/firmware_msc_fat.h new file mode 100644 index 00000000..dd88cdc7 --- /dev/null +++ b/cores/esp32/firmware_msc_fat.h @@ -0,0 +1,141 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#define FAT_U8(v) ((v) & 0xFF) +#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8) +#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24) + +#define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4) + +#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) +#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) +#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) + +#define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) +#define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8)) +#define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8)) + +#define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1) +#define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F) + +#define FAT_FILE_ATTR_READ_ONLY 0x01 +#define FAT_FILE_ATTR_HIDDEN 0x02 +#define FAT_FILE_ATTR_SYSTEM 0x04 +#define FAT_FILE_ATTR_VOLUME_LABEL 0x08 +#define FAT_FILE_ATTR_SUBDIRECTORY 0x10 +#define FAT_FILE_ATTR_ARCHIVE 0x20 +#define FAT_FILE_ATTR_DEVICE 0x40 + +static const uint16_t DISK_SECTOR_SIZE = 512; + +#define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0) + +typedef struct __attribute__ ((packed)) { + uint8_t jump_instruction[3]; + char oem_name[8];//padded with spaces (0x20) + uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512 + uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128 + uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32 + uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1 + uint16_t max_root_dir_entries;//FAT12 and FAT16 + uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16 + uint8_t media_descriptor; + uint16_t sectors_per_alloc_table;//FAT12 and FAT16 + uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access + uint16_t num_heads; + uint32_t hidden_sectors_count; + uint32_t total_sectors_32; + uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk + uint8_t reserved0; + uint8_t extended_boot_signature;//should be 0x29 + uint32_t serial_number;//0x1234 => 1234 + char volume_label[11];//padded with spaces (0x20) + char file_system_type[8];//padded with spaces (0x20) + uint8_t reserved[448]; + uint16_t signature;//should be 0xAA55 +} fat_boot_sector_t; + +typedef struct __attribute__ ((packed)) { + union { + struct { + char file_name[8];//padded with spaces (0x20) + char file_extension[3];//padded with spaces (0x20) + }; + struct { + uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..) + char file_magic_data[10]; + }; + char volume_label[11];//padded with spaces (0x20) + }; + uint8_t file_attr;//mask of FAT_FILE_ATTR_* + uint8_t reserved;//always 0 + uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms) + uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2) + uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d + uint16_t last_access_ymd; + uint16_t extended_attr; + uint16_t last_modified_hms; + uint16_t last_modified_ymd; + uint16_t data_start_sector; + uint32_t file_size; +} fat_dir_entry_t; + +typedef struct __attribute__ ((packed)) { + union { + struct { + uint8_t number:5; + uint8_t reserved0:1; + uint8_t llfp:1; + uint8_t reserved1:1; + } seq; + uint8_t seq_num; //0xE5: Deleted Entry + }; + uint16_t name0[5]; + uint8_t attr; //ALWAYS 0x0F + uint8_t type; //ALWAYS 0x00 + uint8_t dos_checksum; + uint16_t name1[6]; + uint16_t first_cluster; //ALWAYS 0x0000 + uint16_t name2[2]; +} fat_lfn_entry_t; + +typedef union { + fat_dir_entry_t dir; + fat_lfn_entry_t lfn; +} fat_entry_t; + +const char * fat_file_system_type(bool fat16); +uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16); +uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16); +void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16); +fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number); +fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label); +fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16); +uint8_t fat_lfn_checksum(const uint8_t *short_filename); + +#ifdef __cplusplus + } +#endif diff --git a/cores/esp32/main.cpp b/cores/esp32/main.cpp index 4e49f5b9..903e80f1 100644 --- a/cores/esp32/main.cpp +++ b/cores/esp32/main.cpp @@ -2,8 +2,11 @@ #include "freertos/task.h" #include "esp_task_wdt.h" #include "Arduino.h" -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC +#if (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) #include "USB.h" +#if ARDUINO_USB_MSC_ON_BOOT +#include "FirmwareMSC.h" +#endif #endif #ifndef ARDUINO_LOOP_STACK_SIZE @@ -47,9 +50,17 @@ void loopTask(void *pvParameters) extern "C" void app_main() { -#if ARDUINO_SERIAL_PORT //Serial used for USB CDC - USB.begin(); +#if ARDUINO_USB_CDC_ON_BOOT Serial.begin(); +#endif +#if ARDUINO_USB_MSC_ON_BOOT + MSC_Update.begin(); +#endif +#if ARDUINO_USB_DFU_ON_BOOT + USB.enableDFU(); +#endif +#if ARDUINO_USB_ON_BOOT + USB.begin(); #endif loopTaskWDTEnabled = false; initArduino(); diff --git a/libraries/USB/examples/FirmwareMSC/.skip.esp32 b/libraries/USB/examples/FirmwareMSC/.skip.esp32 new file mode 100644 index 00000000..e69de29b diff --git a/libraries/USB/examples/FirmwareMSC/.skip.esp32c3 b/libraries/USB/examples/FirmwareMSC/.skip.esp32c3 new file mode 100644 index 00000000..e69de29b diff --git a/libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino b/libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino new file mode 100644 index 00000000..afcd2783 --- /dev/null +++ b/libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino @@ -0,0 +1,74 @@ +#include "USB.h" +#include "FirmwareMSC.h" + +#if !ARDUINO_USB_MSC_ON_BOOT +FirmwareMSC MSC_Update; +#endif +#if ARDUINO_USB_CDC_ON_BOOT +#define HWSerial Serial0 +#define USBSerial Serial +#else +#define HWSerial Serial +USBCDC USBSerial; +#endif + +static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + if(event_base == ARDUINO_USB_EVENTS){ + arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_STARTED_EVENT: + HWSerial.println("USB PLUGGED"); + break; + case ARDUINO_USB_STOPPED_EVENT: + HWSerial.println("USB UNPLUGGED"); + break; + case ARDUINO_USB_SUSPEND_EVENT: + HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); + break; + case ARDUINO_USB_RESUME_EVENT: + HWSerial.println("USB RESUMED"); + break; + + default: + break; + } + } else if(event_base == ARDUINO_FIRMWARE_MSC_EVENTS){ + arduino_firmware_msc_event_data_t * data = (arduino_firmware_msc_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_FIRMWARE_MSC_START_EVENT: + HWSerial.println("MSC Update Start"); + break; + case ARDUINO_FIRMWARE_MSC_WRITE_EVENT: + //HWSerial.printf("MSC Update Write %u bytes at offset %u\n", data->write.size, data->write.offset); + HWSerial.print("."); + break; + case ARDUINO_FIRMWARE_MSC_END_EVENT: + HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size); + break; + case ARDUINO_FIRMWARE_MSC_ERROR_EVENT: + HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size); + break; + case ARDUINO_FIRMWARE_MSC_POWER_EVENT: + HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject); + break; + + default: + break; + } + } +} + +void setup() { + HWSerial.begin(115200); + HWSerial.setDebugOutput(true); + + USB.onEvent(usbEventCallback); + MSC_Update.onEvent(usbEventCallback); + MSC_Update.begin(); + USBSerial.begin(); + USB.begin(); +} + +void loop() { + // put your main code here, to run repeatedly +} diff --git a/libraries/USB/examples/USBMSC/.skip.esp32 b/libraries/USB/examples/USBMSC/.skip.esp32 new file mode 100644 index 00000000..e69de29b diff --git a/libraries/USB/examples/USBMSC/.skip.esp32c3 b/libraries/USB/examples/USBMSC/.skip.esp32c3 new file mode 100644 index 00000000..e69de29b diff --git a/libraries/USB/examples/USBMSC/USBMSC.ino b/libraries/USB/examples/USBMSC/USBMSC.ino new file mode 100644 index 00000000..0249c3ce --- /dev/null +++ b/libraries/USB/examples/USBMSC/USBMSC.ino @@ -0,0 +1,192 @@ +#include "USB.h" +#include "USBMSC.h" + +#if ARDUINO_USB_CDC_ON_BOOT +#define HWSerial Serial0 +#define USBSerial Serial +#else +#define HWSerial Serial +USBCDC USBSerial; +#endif + +USBMSC MSC; + +#define FAT_U8(v) ((v) & 0xFF) +#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8) +#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24) +#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) +#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) +#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) +#define FAT_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4) + +#define README_CONTENTS "This is tinyusb's MassStorage Class demo.\r\n\r\nIf you find any bugs or get any questions, feel free to file an\r\nissue at github.com/hathach/tinyusb" + +static const uint32_t DISK_SECTOR_COUNT = 2 * 8; // 8KB is the smallest size that windows allow to mount +static const uint16_t DISK_SECTOR_SIZE = 512; // Should be 512 +static const uint16_t DISC_SECTORS_PER_TABLE = 1; //each table sector can fit 170KB (340 sectors) + +static uint8_t msc_disk[DISK_SECTOR_COUNT][DISK_SECTOR_SIZE] = +{ + //------------- Block0: Boot Sector -------------// + { + // Header (62 bytes) + 0xEB, 0x3C, 0x90, //jump_instruction + 'M' , 'S' , 'D' , 'O' , 'S' , '5' , '.' , '0' , //oem_name + FAT_U16(DISK_SECTOR_SIZE), //bytes_per_sector + FAT_U8(1), //sectors_per_cluster + FAT_U16(1), //reserved_sectors_count + FAT_U8(1), //file_alloc_tables_num + FAT_U16(16), //max_root_dir_entries + FAT_U16(DISK_SECTOR_COUNT), //fat12_sector_num + 0xF8, //media_descriptor + FAT_U16(DISC_SECTORS_PER_TABLE), //sectors_per_alloc_table;//FAT12 and FAT16 + FAT_U16(1), //sectors_per_track;//A value of 0 may indicate LBA-only access + FAT_U16(1), //num_heads + FAT_U32(0), //hidden_sectors_count + FAT_U32(0), //total_sectors_32 + 0x00, //physical_drive_number;0x00 for (first) removable media, 0x80 for (first) fixed disk + 0x00, //reserved + 0x29, //extended_boot_signature;//should be 0x29 + FAT_U32(0x1234), //serial_number: 0x1234 => 1234 + 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , //volume_label padded with spaces (0x20) + 'F' , 'A' , 'T' , '1' , '2' , ' ' , ' ' , ' ' , //file_system_type padded with spaces (0x20) + + // Zero up to 2 last bytes of FAT magic code (448 bytes) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + //boot signature (2 bytes) + 0x55, 0xAA + }, + + //------------- Block1: FAT12 Table -------------// + { + FAT_TBL2B(0xFF8, 0xFFF), FAT_TBL2B(0xFFF, 0x000) // first 2 entries must be 0xFF8 0xFFF, third entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'E' , 'S' , 'P' , '3' , '2' , 'S' , '2' , ' ' , + 'M' , 'S' , 'C' , + 0x08, //FILE_ATTR_VOLUME_LABEL + 0x00, + FAT_MS2B(0,0), + FAT_HMS2B(0,0,0), + FAT_YMD2B(0,0,0), + FAT_YMD2B(0,0,0), + FAT_U16(0), + FAT_HMS2B(13,42,30), //last_modified_hms + FAT_YMD2B(2018,11,5), //last_modified_ymd + FAT_U16(0), + FAT_U32(0), + + // second entry is readme file + 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' ,//file_name[8]; padded with spaces (0x20) + 'T' , 'X' , 'T' , //file_extension[3]; padded with spaces (0x20) + 0x20, //file attributes: FILE_ATTR_ARCHIVE + 0x00, //ignore + FAT_MS2B(1,980), //creation_time_10_ms (max 199x10 = 1s 990ms) + FAT_HMS2B(13,42,36), //create_time_hms [5:6:5] => h:m:(s/2) + FAT_YMD2B(2018,11,5), //create_time_ymd [7:4:5] => (y+1980):m:d + FAT_YMD2B(2020,11,5), //last_access_ymd + FAT_U16(0), //extended_attributes + FAT_HMS2B(13,44,16), //last_modified_hms + FAT_YMD2B(2019,11,5), //last_modified_ymd + FAT_U16(2), //start of file in cluster + FAT_U32(sizeof(README_CONTENTS) - 1) //file size + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS +}; + +static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){ + HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize); + memcpy(msc_disk[lba] + offset, buffer, bufsize); + return bufsize; +} + +static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){ + HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize); + memcpy(buffer, msc_disk[lba] + offset, bufsize); + return bufsize; +} + +static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){ + HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject); + return true; +} + +static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + if(event_base == ARDUINO_USB_EVENTS){ + arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data; + switch (event_id){ + case ARDUINO_USB_STARTED_EVENT: + HWSerial.println("USB PLUGGED"); + break; + case ARDUINO_USB_STOPPED_EVENT: + HWSerial.println("USB UNPLUGGED"); + break; + case ARDUINO_USB_SUSPEND_EVENT: + HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); + break; + case ARDUINO_USB_RESUME_EVENT: + HWSerial.println("USB RESUMED"); + break; + + default: + break; + } + } +} + +void setup() { + HWSerial.begin(115200); + HWSerial.setDebugOutput(true); + + USB.onEvent(usbEventCallback); + MSC.vendorID("ESP32");//max 8 chars + MSC.productID("USB_MSC");//max 16 chars + MSC.productRevision("1.0");//max 4 chars + MSC.onStartStop(onStartStop); + MSC.onRead(onRead); + MSC.onWrite(onWrite); + MSC.mediaPresent(true); + MSC.begin(DISK_SECTOR_COUNT, DISK_SECTOR_SIZE); + USBSerial.begin(); + USB.begin(); +} + +void loop() { + // put your main code here, to run repeatedly: +} diff --git a/libraries/USB/examples/USBSerial/USBSerial.ino b/libraries/USB/examples/USBSerial/USBSerial.ino index c3094fd8..bb23418f 100644 --- a/libraries/USB/examples/USBSerial/USBSerial.ino +++ b/libraries/USB/examples/USBSerial/USBSerial.ino @@ -1,6 +1,6 @@ #include "USB.h" -#if ARDUINO_SERIAL_PORT +#if ARDUINO_USB_CDC_ON_BOOT #define HWSerial Serial0 #define USBSerial Serial #else @@ -66,14 +66,8 @@ void setup() { USB.onEvent(usbEventCallback); USBSerial.onEvent(usbEventCallback); -#if !ARDUINO_SERIAL_PORT - USB.enableDFU(); - USB.webUSB(true); - USB.webUSBURL("http://localhost/webusb"); - USB.productName("ESP32S2-USB"); - USB.begin(); USBSerial.begin(); -#endif + USB.begin(); } void loop() { diff --git a/libraries/USB/keywords.txt b/libraries/USB/keywords.txt index 8b1442df..932f72ef 100644 --- a/libraries/USB/keywords.txt +++ b/libraries/USB/keywords.txt @@ -8,6 +8,7 @@ USB KEYWORD1 USBCDC KEYWORD1 +USBMSC KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -18,6 +19,14 @@ end KEYWORD2 onEvent KEYWORD2 enableReset KEYWORD2 +vendorID KEYWORD2 +productID KEYWORD2 +productRevision KEYWORD2 +mediaPresent KEYWORD2 +onStartStop KEYWORD2 +onRead KEYWORD2 +onWrite KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/libraries/USB/src/USB_NOT.h b/libraries/USB/src/USB_NOT.h index e69de29b..f349ad19 100644 --- a/libraries/USB/src/USB_NOT.h +++ b/libraries/USB/src/USB_NOT.h @@ -0,0 +1,15 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once diff --git a/platform.txt b/platform.txt index ee51f533..2fa972dc 100644 --- a/platform.txt +++ b/platform.txt @@ -30,7 +30,7 @@ compiler.cpp.flags.esp32=-mlongcalls -Wno-frame-address -ffunction-sections -fda compiler.S.flags.esp32=-ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -O2 -Wwrite-strings -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -x assembler-with-cpp -MMD -c compiler.c.elf.flags.esp32=-T esp32.rom.redefined.ld -T memory.ld -T sections.ld -T esp32.rom.ld -T esp32.rom.api.ld -T esp32.rom.libgcc.ld -T esp32.rom.newlib-data.ld -T esp32.rom.syscalls.ld -T esp32.peripherals.ld -mlongcalls -Wno-frame-address -Wl,--cref -Wl,--gc-sections -fno-rtti -fno-lto -u _Z5setupv -u _Z4loopv -Wl,--wrap=mbedtls_mpi_exp_mod -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u ld_include_panic_highint_hdl -u start_app -u start_app_other_cores -u __ubsan_include -Wl,--wrap=longjmp -u __assert_func -u vfs_include_syscalls_impl -Wl,--undefined=uxTopUsedPriority -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -u __cxa_guard_dummy compiler.ar.flags.esp32=cr -build.extra_flags.esp32=-DARDUINO_SERIAL_PORT=0 +build.extra_flags.esp32=-DARDUINO_USB_CDC_ON_BOOT=0 # # ESP32 Support End # @@ -45,7 +45,7 @@ compiler.cpp.flags.esp32s2=-mlongcalls -ffunction-sections -fdata-sections -Wno- compiler.S.flags.esp32s2=-ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -O2 -Wwrite-strings -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -x assembler-with-cpp -MMD -c compiler.c.elf.flags.esp32s2=-T memory.ld -T sections.ld -T esp32s2.rom.ld -T esp32s2.rom.api.ld -T esp32s2.rom.libgcc.ld -T esp32s2.rom.newlib-funcs.ld -T esp32s2.rom.newlib-data.ld -T esp32s2.rom.spiflash.ld -T esp32s2.peripherals.ld -mlongcalls -Wl,--cref -Wl,--gc-sections -fno-rtti -fno-lto -u _Z5setupv -u _Z4loopv -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u ld_include_panic_highint_hdl -u start_app -u __ubsan_include -Wl,--wrap=longjmp -u __assert_func -u vfs_include_syscalls_impl -Wl,--undefined=uxTopUsedPriority -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -u __cxa_guard_dummy compiler.ar.flags.esp32s2=cr -build.extra_flags.esp32s2=-DARDUINO_SERIAL_PORT={build.serial} +build.extra_flags.esp32s2=-DARDUINO_USB_CDC_ON_BOOT={build.cdc_on_boot} -DARDUINO_USB_MSC_ON_BOOT={build.msc_on_boot} -DARDUINO_USB_DFU_ON_BOOT={build.dfu_on_boot} # # ESP32S2 Support End # @@ -60,7 +60,7 @@ compiler.cpp.flags.esp32c3=-march=rv32imc -ffunction-sections -fdata-sections -W compiler.S.flags.esp32c3=-ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -Wno-error=format= -nostartfiles -Wno-format -Og -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -x assembler-with-cpp -MMD -c compiler.c.elf.flags.esp32c3=-T memory.ld -T sections.ld -T esp32c3.rom.ld -T esp32c3.rom.api.ld -T esp32c3.rom.libgcc.ld -T esp32c3.rom.newlib.ld -T esp32c3.rom.version.ld -T esp32c3.peripherals.ld -nostartfiles -march=rv32imc --specs=nosys.specs -Wl,--cref -Wl,--gc-sections -fno-rtti -fno-lto -u _Z5setupv -u _Z4loopv -Wl,--wrap=mbedtls_mpi_exp_mod -u esp_app_desc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -u start_app -u __ubsan_include -u __assert_func -u vfs_include_syscalls_impl -Wl,--undefined=uxTopUsedPriority -u app_main -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -Wl,--wrap=_Unwind_SetEnableExceptionFdeSorting -Wl,--wrap=__register_frame_info_bases -Wl,--wrap=__register_frame_info -Wl,--wrap=__register_frame -Wl,--wrap=__register_frame_info_table_bases -Wl,--wrap=__register_frame_info_table -Wl,--wrap=__register_frame_table -Wl,--wrap=__deregister_frame_info_bases -Wl,--wrap=__deregister_frame_info -Wl,--wrap=_Unwind_Find_FDE -Wl,--wrap=_Unwind_GetGR -Wl,--wrap=_Unwind_GetCFA -Wl,--wrap=_Unwind_GetIP -Wl,--wrap=_Unwind_GetIPInfo -Wl,--wrap=_Unwind_GetRegionStart -Wl,--wrap=_Unwind_GetDataRelBase -Wl,--wrap=_Unwind_GetTextRelBase -Wl,--wrap=_Unwind_SetIP -Wl,--wrap=_Unwind_SetGR -Wl,--wrap=_Unwind_GetLanguageSpecificData -Wl,--wrap=_Unwind_FindEnclosingFunction -Wl,--wrap=_Unwind_Resume -Wl,--wrap=_Unwind_RaiseException -Wl,--wrap=_Unwind_DeleteException -Wl,--wrap=_Unwind_ForcedUnwind -Wl,--wrap=_Unwind_Resume_or_Rethrow -Wl,--wrap=_Unwind_Backtrace -Wl,--wrap=__cxa_call_unexpected -Wl,--wrap=__gxx_personality_v0 -u __cxa_guard_dummy -u __cxx_fatal_exception compiler.ar.flags.esp32c3=cr -build.extra_flags.esp32c3=-DARDUINO_SERIAL_PORT=0 +build.extra_flags.esp32c3=-DARDUINO_USB_CDC_ON_BOOT=0 # # ESP32C3 Support End # diff --git a/variants/esp32s2usb/pins_arduino.h b/variants/esp32s2usb/pins_arduino.h new file mode 100644 index 00000000..f3acb5c9 --- /dev/null +++ b/variants/esp32s2usb/pins_arduino.h @@ -0,0 +1,81 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +// Default USB Settings +#define USB_VID 0x303A +#define USB_PID 0x0003 +#define USB_MANUFACTURER "Espressif Systems" +#define USB_PRODUCT "ESP32-S2-USB" +#define USB_SERIAL "0" +#define USB_WEBUSB_ENABLED false +#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html" + +// Default USB FirmwareMSC Settings +#define USB_FW_MSC_VENDOR_ID "ESP32-S2" //max 8 chars +#define USB_FW_MSC_PRODUCT_ID "Firmware MSC" //max 16 chars +#define USB_FW_MSC_PRODUCT_REVISION "1.23" //max 4 chars +#define USB_FW_MSC_VOLUME_NAME "S2-Firmware" //max 11 chars +#define USB_FW_MSC_SERIAL_NUMBER 0x00000000 + + +#define EXTERNAL_NUM_INTERRUPTS 46 +#define NUM_DIGITAL_PINS 48 +#define NUM_ANALOG_INPUTS 20 + +#define analogInputToDigitalPin(p) (((p)<20)?(esp32_adc2gpio[(p)]):-1) +#define digitalPinToInterrupt(p) (((p)<48)?(p):-1) +#define digitalPinHasPWM(p) (p < 46) + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +static const uint8_t SS = 34; +static const uint8_t MOSI = 35; +static const uint8_t MISO = 37; +static const uint8_t SCK = 36; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t DAC1 = 17; +static const uint8_t DAC2 = 18; + +#endif /* Pins_Arduino_h */