Add initial support for USB MSC (#5466)

* Add initial support for USB MSC

* Add Firmware Upload/Download With MSC

Current running firmware is available as file inside the MSC Disk. To update the firmware on the ESP, just copy a regular firmware bin into the drive

* Support overwriting of the firmware file

Overwriting a file is done totally differently on MacOS, Windows and Linux. This change supports it on all of them.

* Allow CDC, FirmwareMSC and DFU to be enabled on boot

* Add example ESP32-S2 USB-ONLY board

* Various device code optimizations

Added `end()` methods to MSC classes
Made begin() methods safe to be called multiple times
Optimized CDC class

* Fix CDC Connect/Disconnect detection in Arduino IDE on Windows

* Rework cdc_write

* Update ESP32-S2 board configs
This commit is contained in:
Me No Dev 2021-08-02 15:35:13 +03:00 committed by GitHub
parent be84c8219c
commit 5bb8177aa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1871 additions and 191 deletions

View File

@ -34,6 +34,9 @@ set(CORE_SRCS
cores/esp32/StreamString.cpp cores/esp32/StreamString.cpp
cores/esp32/USB.cpp cores/esp32/USB.cpp
cores/esp32/USBCDC.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_pulse.c
cores/esp32/wiring_shift.c cores/esp32/wiring_shift.c
cores/esp32/WMath.cpp cores/esp32/WMath.cpp
@ -151,6 +154,7 @@ set(includedirs
libraries/SPI/src libraries/SPI/src
libraries/Ticker/src libraries/Ticker/src
libraries/Update/src libraries/Update/src
libraries/USB/src
libraries/WebServer/src libraries/WebServer/src
libraries/WiFiClientSecure/src libraries/WiFiClientSecure/src
libraries/WiFi/src libraries/WiFi/src

View File

@ -1,5 +1,7 @@
menu.UploadSpeed=Upload Speed 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.UploadMode=Upload Mode
menu.CPUFreq=CPU Frequency menu.CPUFreq=CPU Frequency
menu.FlashFreq=Flash Frequency menu.FlashFreq=Flash Frequency
@ -37,7 +39,7 @@ esp32c3.build.variant=esp32c3
esp32c3.build.board=ESP32C3_DEV esp32c3.build.board=ESP32C3_DEV
esp32c3.build.bootloader_addr=0x0 esp32c3.build.bootloader_addr=0x0
esp32c3.build.serial=0 esp32c3.build.cdc_on_boot=0
esp32c3.build.f_cpu=160000000L esp32c3.build.f_cpu=160000000L
esp32c3.build.flash_size=4MB esp32c3.build.flash_size=4MB
esp32c3.build.flash_freq=80m esp32c3.build.flash_freq=80m
@ -173,19 +175,31 @@ esp32s2.build.core=esp32
esp32s2.build.variant=esp32s2 esp32s2.build.variant=esp32s2
esp32s2.build.board=ESP32S2_DEV 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.f_cpu=240000000L
esp32s2.build.flash_size=4MB esp32s2.build.flash_size=4MB
esp32s2.build.flash_freq=80m esp32s2.build.flash_freq=80m
esp32s2.build.flash_mode=qio esp32s2.build.flash_mode=dio
esp32s2.build.boot=qio esp32s2.build.boot=qio
esp32s2.build.partitions=default esp32s2.build.partitions=default
esp32s2.build.defines= esp32s2.build.defines=
esp32s2.menu.SerialMode.default=UART0 esp32s2.menu.CDCOnBoot.default=Disabled
esp32s2.menu.SerialMode.default.build.serial=0 esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0
esp32s2.menu.SerialMode.cdc=USB CDC esp32s2.menu.CDCOnBoot.cdc=Enabled
esp32s2.menu.SerialMode.cdc.build.serial=1 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=UART0
esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false 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.name=ESP32 Wrover Kit (all versions)
esp32wroverkit.upload.tool=esptool_py esp32wroverkit.upload.tool=esptool_py
esp32wroverkit.upload.maximum_size=1310720 esp32wroverkit.upload.maximum_size=1310720
@ -865,7 +976,9 @@ feathers2.build.core=esp32
feathers2.build.variant=um_feathers2 feathers2.build.variant=um_feathers2
feathers2.build.board=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.f_cpu=240000000L
feathers2.build.flash_size=16MB feathers2.build.flash_size=16MB
feathers2.build.flash_freq=80m feathers2.build.flash_freq=80m
@ -874,10 +987,20 @@ feathers2.build.boot=qio
feathers2.build.partitions=fatflash feathers2.build.partitions=fatflash
feathers2.build.defines= feathers2.build.defines=
feathers2.menu.SerialMode.cdc=USB CDC feathers2.menu.CDCOnBoot.cdc=Enabled
feathers2.menu.SerialMode.cdc.build.serial=1 feathers2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
feathers2.menu.SerialMode.default=UART0 feathers2.menu.CDCOnBoot.default=Disabled
feathers2.menu.SerialMode.default.build.serial=0 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=Enabled
feathers2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM feathers2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
@ -993,7 +1116,9 @@ tinys2.build.core=esp32
tinys2.build.variant=um_tinys2 tinys2.build.variant=um_tinys2
tinys2.build.board=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.f_cpu=240000000L
tinys2.build.flash_size=4MB tinys2.build.flash_size=4MB
tinys2.build.flash_freq=80m tinys2.build.flash_freq=80m
@ -1002,10 +1127,20 @@ tinys2.build.boot=qio
tinys2.build.partitions=default tinys2.build.partitions=default
tinys2.build.defines= tinys2.build.defines=
tinys2.menu.SerialMode.cdc=USB CDC tinys2.menu.CDCOnBoot.cdc=Enabled
tinys2.menu.SerialMode.cdc.build.serial=1 tinys2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
tinys2.menu.SerialMode.default=UART0 tinys2.menu.CDCOnBoot.default=Disabled
tinys2.menu.SerialMode.default.build.serial=0 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=Enabled
tinys2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM tinys2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
@ -1166,7 +1301,9 @@ micros2.build.core=esp32
micros2.build.variant=micro_s2 micros2.build.variant=micro_s2
micros2.build.board=MICROS2 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.f_cpu=240000000L
micros2.build.flash_size=16MB micros2.build.flash_size=16MB
micros2.build.flash_freq=80m micros2.build.flash_freq=80m
@ -1175,10 +1312,20 @@ micros2.build.boot=qio
micros2.build.partitions=fatflash micros2.build.partitions=fatflash
micros2.build.defines= micros2.build.defines=
micros2.menu.SerialMode.cdc=USB CDC micros2.menu.CDCOnBoot.cdc=Enabled
micros2.menu.SerialMode.cdc.build.serial=1 micros2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
micros2.menu.SerialMode.default=UART0 micros2.menu.CDCOnBoot.default=Disabled
micros2.menu.SerialMode.default.build.serial=0 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=Enabled
micros2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM 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.variant=esp32s2thing_plus
sparkfun_esp32s2_thing_plus.build.board=ESP32S2_THING_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.f_cpu=240000000L
sparkfun_esp32s2_thing_plus.build.flash_size=4MB sparkfun_esp32s2_thing_plus.build.flash_size=4MB
sparkfun_esp32s2_thing_plus.build.flash_freq=80m 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.partitions=default
sparkfun_esp32s2_thing_plus.build.defines= sparkfun_esp32s2_thing_plus.build.defines=
sparkfun_esp32s2_thing_plus.menu.SerialMode.default=UART0 sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.default=Disabled
sparkfun_esp32s2_thing_plus.menu.SerialMode.default.build.serial=0 sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.default.build.cdc_on_boot=0
sparkfun_esp32s2_thing_plus.menu.SerialMode.cdc=USB CDC sparkfun_esp32s2_thing_plus.menu.CDCOnBoot.cdc=Enabled
sparkfun_esp32s2_thing_plus.menu.SerialMode.cdc.build.serial=1 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=Disabled
sparkfun_esp32s2_thing_plus.menu.PSRAM.disabled.build.defines= 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.variant=adafruit_metro_esp32s2
adafruit_metro_esp32s2.build.board=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.f_cpu=240000000L
adafruit_metro_esp32s2.build.flash_size=4MB adafruit_metro_esp32s2.build.flash_size=4MB
adafruit_metro_esp32s2.build.flash_freq=80m 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.partitions=default
adafruit_metro_esp32s2.build.defines= adafruit_metro_esp32s2.build.defines=
adafruit_metro_esp32s2.menu.SerialMode.cdc=USB CDC adafruit_metro_esp32s2.menu.CDCOnBoot.cdc=Enabled
adafruit_metro_esp32s2.menu.SerialMode.cdc.build.serial=1 adafruit_metro_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
adafruit_metro_esp32s2.menu.SerialMode.default=UART0 adafruit_metro_esp32s2.menu.CDCOnBoot.default=Disabled
adafruit_metro_esp32s2.menu.SerialMode.default.build.serial=0 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=Enabled
adafruit_metro_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM 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.variant=adafruit_magtag29_esp32s2
adafruit_magtag29_esp32s2.build.board=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.f_cpu=240000000L
adafruit_magtag29_esp32s2.build.flash_size=4MB adafruit_magtag29_esp32s2.build.flash_size=4MB
adafruit_magtag29_esp32s2.build.flash_freq=80m 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.partitions=default
adafruit_magtag29_esp32s2.build.defines= adafruit_magtag29_esp32s2.build.defines=
adafruit_magtag29_esp32s2.menu.SerialMode.cdc=USB CDC adafruit_magtag29_esp32s2.menu.CDCOnBoot.cdc=Enabled
adafruit_magtag29_esp32s2.menu.SerialMode.cdc.build.serial=1 adafruit_magtag29_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
adafruit_magtag29_esp32s2.menu.SerialMode.default=UART0 adafruit_magtag29_esp32s2.menu.CDCOnBoot.default=Disabled
adafruit_magtag29_esp32s2.menu.SerialMode.default.build.serial=0 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=Enabled
adafruit_magtag29_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM 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.variant=adafruit_funhouse_esp32s2
adafruit_funhouse_esp32s2.build.board=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.f_cpu=240000000L
adafruit_funhouse_esp32s2.build.flash_size=4MB adafruit_funhouse_esp32s2.build.flash_size=4MB
adafruit_funhouse_esp32s2.build.flash_freq=80m 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.partitions=default
adafruit_funhouse_esp32s2.build.defines= adafruit_funhouse_esp32s2.build.defines=
adafruit_funhouse_esp32s2.menu.SerialMode.cdc=USB CDC adafruit_funhouse_esp32s2.menu.CDCOnBoot.cdc=Enabled
adafruit_funhouse_esp32s2.menu.SerialMode.cdc.build.serial=1 adafruit_funhouse_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
adafruit_funhouse_esp32s2.menu.SerialMode.default=UART0 adafruit_funhouse_esp32s2.menu.CDCOnBoot.default=Disabled
adafruit_funhouse_esp32s2.menu.SerialMode.default.build.serial=0 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=Enabled
adafruit_funhouse_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM 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.variant=adafruit_feather_esp32s2
adafruit_feather_esp32s2_nopsram.build.board=ADAFRUIT_FEATHER_ESP32S2_NOPSRAM 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.f_cpu=240000000L
adafruit_feather_esp32s2_nopsram.build.flash_size=4MB adafruit_feather_esp32s2_nopsram.build.flash_size=4MB
adafruit_feather_esp32s2_nopsram.build.flash_freq=80m 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.partitions=default
adafruit_feather_esp32s2_nopsram.build.defines= adafruit_feather_esp32s2_nopsram.build.defines=
adafruit_feather_esp32s2_nopsram.menu.SerialMode.cdc=USB CDC adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.cdc=Enabled
adafruit_feather_esp32s2_nopsram.menu.SerialMode.cdc.build.serial=1 adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
adafruit_feather_esp32s2_nopsram.menu.SerialMode.default=UART0 adafruit_feather_esp32s2_nopsram.menu.CDCOnBoot.default=Disabled
adafruit_feather_esp32s2_nopsram.menu.SerialMode.default.build.serial=0 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=Disabled
adafruit_feather_esp32s2_nopsram.menu.PSRAM.disabled.build.defines= adafruit_feather_esp32s2_nopsram.menu.PSRAM.disabled.build.defines=

423
cores/esp32/FirmwareMSC.cpp Normal file
View File

@ -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 <cstring>
#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 */

69
cores/esp32/FirmwareMSC.h Normal file
View File

@ -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 <stdbool.h>
#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 */

View File

@ -37,7 +37,7 @@
#endif #endif
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #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); HardwareSerial Serial0(0);
#else #else
HardwareSerial Serial(0); HardwareSerial Serial(0);

View File

@ -113,10 +113,10 @@ protected:
extern void serialEventRun(void) __attribute__((weak)); extern void serialEventRun(void) __attribute__((weak));
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
#ifndef ARDUINO_SERIAL_PORT #ifndef ARDUINO_USB_CDC_ON_BOOT
#define ARDUINO_SERIAL_PORT 0 #define ARDUINO_USB_CDC_ON_BOOT 0
#endif #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 "USB.h"
#include "USBCDC.h" #include "USBCDC.h"
extern HardwareSerial Serial0; extern HardwareSerial Serial0;

View File

@ -31,14 +31,16 @@
#ifndef USB_SERIAL #ifndef USB_SERIAL
#define USB_SERIAL "0" #define USB_SERIAL "0"
#endif #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 #if CFG_TUD_DFU_RUNTIME
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf) 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) #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"); 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_protocol(MISC_PROTOCOL_IAD)
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED) ,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
,usb_power_ma(500) ,usb_power_ma(500)
,webusb_enabled(false) ,webusb_enabled(USB_WEBUSB_ENABLED)
,webusb_url("https://espressif.github.io/arduino-esp32/webusb.html") ,webusb_url(USB_WEBUSB_URL)
,_started(false) ,_started(false)
,_task_stack_size(task_stack_size) ,_task_stack_size(task_stack_size)
,_event_task_priority(event_task_priority) ,_event_task_priority(event_task_priority)

View File

@ -18,9 +18,11 @@
#include "Arduino.h" #include "Arduino.h"
#include "USBCDC.h" #include "USBCDC.h"
#include "common/tusb_common.h"
#include "esp_event.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); ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);
typedef enum { typedef enum {

View File

@ -28,7 +28,6 @@ USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
{ {
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); 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] = { uint8_t descriptor[TUD_CDC_DESC_LEN] = {
// Interface number, string index, EP notification address and size, EP data address (out, in) and size. // 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) 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 // 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) 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){ if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
devices[itf]->_onLineState(dtr, rts); 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 // 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) 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){ 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); 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 // Invoked when received new data
void tud_cdc_rx_cb(uint8_t itf) void tud_cdc_rx_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]->_onRX(); 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 // Invoked when space becomes available in TX buffer
void tud_cdc_tx_complete_cb(uint8_t itf){ void tud_cdc_tx_complete_cb(uint8_t itf){
//isr_log_v("itf: %u", itf); if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL && devices[itf]->tx_sem != NULL){
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
xSemaphoreGive(devices[itf]->tx_sem); xSemaphoreGive(devices[itf]->tx_sem);
devices[itf]->_onTX(); devices[itf]->_onTX();
} }
} }
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){ 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; return 0;
} }
if(!tud_cdc_n_connected(itf)){ 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){ while(tosend){
uint32_t space = tud_cdc_n_write_available(itf); uint32_t space = tud_cdc_n_write_available(itf);
if(!space){ if(!space){
delay(1); //make sure that we do not get previous semaphore
continue; 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){ if(tosend < space){
space = tosend; space = tosend;
@ -103,7 +105,7 @@ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size)
sofar += sent; sofar += sent;
tosend -= sent; tosend -= sent;
tud_cdc_n_write_flush(itf); tud_cdc_n_write_flush(itf);
xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY); //xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY);
} }
return sofar; 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); 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){ static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
((USBCDC*)arg)->_onUnplugged(); ((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); tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
if(itf < MAX_USB_CDC_DEVICES){ 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); 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){ void USBCDC::onEvent(esp_event_handler_t callback){
onEvent(ARDUINO_USB_CDC_ANY_EVENT, 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){ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
if(rx_queue){ if(rx_queue){
if(!rx_queue_len){
vQueueDelete(rx_queue);
rx_queue = NULL;
}
return 0; return 0;
} }
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); 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) void USBCDC::begin(unsigned long baud)
{ {
setRxBufferSize(256);//default if not preset
if(tx_sem == NULL){ if(tx_sem == NULL){
tx_sem = xSemaphoreCreateBinary(); tx_sem = xSemaphoreCreateBinary();
xSemaphoreTake(tx_sem, 0); xSemaphoreTake(tx_sem, 0);
} }
setRxBufferSize(256);//default if not preset
devices[itf] = this;
} }
void USBCDC::end() void USBCDC::end()
{ {
connected = false;
devices[itf] = NULL;
setRxBufferSize(0);
if (tx_sem != NULL) { if (tx_sem != NULL) {
vSemaphoreDelete(tx_sem); vSemaphoreDelete(tx_sem);
tx_sem = NULL; tx_sem = NULL;
@ -176,6 +186,11 @@ void USBCDC::_onUnplugged(void){
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 }; enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
void USBCDC::_onLineState(bool _dtr, bool _rts){ void USBCDC::_onLineState(bool _dtr, bool _rts){
static uint8_t lineState = CDC_LINE_IDLE; static uint8_t lineState = CDC_LINE_IDLE;
if(dtr == _dtr && rts == _rts){
return; // Skip duplicate events
}
dtr = _dtr; dtr = _dtr;
rts = _rts; rts = _rts;
@ -183,6 +198,11 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
if(!dtr && rts){ if(!dtr && rts){
if(lineState == CDC_LINE_IDLE){ if(lineState == CDC_LINE_IDLE){
lineState++; 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 { } else {
lineState = CDC_LINE_IDLE; lineState = CDC_LINE_IDLE;
} }
@ -212,7 +232,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
connected = true; connected = true;
arduino_usb_cdc_event_data_t p = {0}; 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); 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; connected = false;
arduino_usb_cdc_event_data_t p = {0}; 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); 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){ 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){ 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 // 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); usb_persist_restart(RESTART_BOOTLOADER);
} else { } else {
bit_rate = _bit_rate; bit_rate = _bit_rate;
@ -317,7 +337,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size)
void USBCDC::flush(void) void USBCDC::flush(void)
{ {
if(itf >= MAX_USB_CDC_DEVICES){ if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
return; return;
} }
tud_cdc_n_write_flush(itf); tud_cdc_n_write_flush(itf);
@ -325,7 +345,7 @@ void USBCDC::flush(void)
int USBCDC::availableForWrite(void) int USBCDC::availableForWrite(void)
{ {
if(itf >= MAX_USB_CDC_DEVICES){ if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
return -1; return -1;
} }
return tud_cdc_n_write_available(itf); return tud_cdc_n_write_available(itf);
@ -364,7 +384,7 @@ USBCDC::operator bool() const
return connected; 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); USBCDC Serial(0);
#endif #endif

View File

@ -54,6 +54,7 @@ class USBCDC: public Stream
{ {
public: public:
USBCDC(uint8_t itf=0); USBCDC(uint8_t itf=0);
~USBCDC();
void onEvent(esp_event_handler_t callback); void onEvent(esp_event_handler_t callback);
void onEvent(arduino_usb_cdc_event_t event, 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; extern USBCDC Serial;
#endif #endif

260
cores/esp32/USBMSC.cpp Normal file
View File

@ -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 */

49
cores/esp32/USBMSC.h Normal file
View File

@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@ -72,20 +72,15 @@ static void configure_pins(usb_hal_context_t *usb)
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
{ {
log_i("Driver installation...");
// Hal init
usb_hal_context_t hal = { usb_hal_context_t hal = {
.use_external_phy = config->external_phy .use_external_phy = config->external_phy
}; };
usb_hal_init(&hal); usb_hal_init(&hal);
configure_pins(&hal); configure_pins(&hal);
if (!tusb_init()) { if (!tusb_init()) {
log_e("Can't initialize the TinyUSB stack."); log_e("Can't initialize the TinyUSB stack.");
return ESP_FAIL; return ESP_FAIL;
} }
log_i("Driver installed");
return ESP_OK; 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_PRODUCT = "";
static tusb_str_t USB_DEVICE_MANUFACTURER = ""; static tusb_str_t USB_DEVICE_MANUFACTURER = "";
static tusb_str_t USB_DEVICE_SERIAL = ""; 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 uint8_t USB_DEVICE_ATTRIBUTES = 0;
static uint16_t USB_DEVICE_POWER = 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 uint32_t tinyusb_string_descriptor_len = 4;
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
// array of pointer to 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_MANUFACTURER,// 1: Manufacturer
USB_DEVICE_PRODUCT, // 2: Product USB_DEVICE_PRODUCT, // 2: Product
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
@ -563,31 +559,37 @@ static void usb_device_task(void *param) {
/* /*
* PUBLIC API * 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) 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))){ 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; return ESP_FAIL;
} }
tinyusb_loaded_interfaces_mask |= (1U << interface); tinyusb_loaded_interfaces_mask |= (1U << interface);
tinyusb_config_descriptor_len += descriptor_len; tinyusb_config_descriptor_len += descriptor_len;
tinyusb_loaded_interfaces_callbacks[interface] = cb; tinyusb_loaded_interfaces_callbacks[interface] = cb;
log_d("Interface %u enabled", interface); log_d("Interface %s enabled", tinyusb_interface_names[interface]);
return ESP_OK; return ESP_OK;
} }
esp_err_t tinyusb_init(tinyusb_device_config_t *config) { esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
static bool initialized = false; if(tinyusb_is_initialized){
if(initialized){
return ESP_OK; return ESP_OK;
} }
initialized = true; tinyusb_is_initialized = true;
tinyusb_endpoints.val = 0; tinyusb_endpoints.val = 0;
tinyusb_apply_device_config(config); tinyusb_apply_device_config(config);
if (!tinyusb_load_enabled_interfaces()) { if (!tinyusb_load_enabled_interfaces()) {
initialized = false; tinyusb_is_initialized = false;
return ESP_FAIL; 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) { if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
initialized = false; tinyusb_is_initialized = false;
return ESP_FAIL; 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); esp_err_t err = tinyusb_driver_install(&tusb_cfg);
if (err != ESP_OK) { if (err != ESP_OK) {
initialized = false; tinyusb_is_initialized = false;
return err; return err;
} }
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL); 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; 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 */ #endif /* CONFIG_TINYUSB_ENABLED */

View File

@ -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 // The following definitions and functions are to be used only by the drivers
typedef enum { typedef enum {
USB_INTERFACE_CDC, USB_INTERFACE_MSC,
USB_INTERFACE_DFU, USB_INTERFACE_DFU,
USB_INTERFACE_HID, USB_INTERFACE_HID,
USB_INTERFACE_VENDOR, USB_INTERFACE_VENDOR,
USB_INTERFACE_MSC, USB_INTERFACE_CDC,
USB_INTERFACE_MIDI, USB_INTERFACE_MIDI,
USB_INTERFACE_CUSTOM, USB_INTERFACE_CUSTOM,
USB_INTERFACE_MAX USB_INTERFACE_MAX

View File

@ -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;
}

View File

@ -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 <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#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

View File

@ -2,8 +2,11 @@
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "Arduino.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" #include "USB.h"
#if ARDUINO_USB_MSC_ON_BOOT
#include "FirmwareMSC.h"
#endif
#endif #endif
#ifndef ARDUINO_LOOP_STACK_SIZE #ifndef ARDUINO_LOOP_STACK_SIZE
@ -47,9 +50,17 @@ void loopTask(void *pvParameters)
extern "C" void app_main() extern "C" void app_main()
{ {
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC #if ARDUINO_USB_CDC_ON_BOOT
USB.begin();
Serial.begin(); 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 #endif
loopTaskWDTEnabled = false; loopTaskWDTEnabled = false;
initArduino(); initArduino();

View File

@ -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
}

View File

@ -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:
}

View File

@ -1,6 +1,6 @@
#include "USB.h" #include "USB.h"
#if ARDUINO_SERIAL_PORT #if ARDUINO_USB_CDC_ON_BOOT
#define HWSerial Serial0 #define HWSerial Serial0
#define USBSerial Serial #define USBSerial Serial
#else #else
@ -66,14 +66,8 @@ void setup() {
USB.onEvent(usbEventCallback); USB.onEvent(usbEventCallback);
USBSerial.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(); USBSerial.begin();
#endif USB.begin();
} }
void loop() { void loop() {

View File

@ -8,6 +8,7 @@
USB KEYWORD1 USB KEYWORD1
USBCDC KEYWORD1 USBCDC KEYWORD1
USBMSC KEYWORD1
####################################### #######################################
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
@ -18,6 +19,14 @@ end KEYWORD2
onEvent KEYWORD2 onEvent KEYWORD2
enableReset KEYWORD2 enableReset KEYWORD2
vendorID KEYWORD2
productID KEYWORD2
productRevision KEYWORD2
mediaPresent KEYWORD2
onStartStop KEYWORD2
onRead KEYWORD2
onWrite KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################

View File

@ -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

View File

@ -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.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.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 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 # 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.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.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 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 # 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.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.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 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 # ESP32C3 Support End
# #

View File

@ -0,0 +1,81 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
// 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 */