Merge branch 'master' into release/v3.3.x

This commit is contained in:
Me No Dev 2025-07-03 12:25:04 +03:00 committed by GitHub
commit 70696df2d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 1334 additions and 132 deletions

View file

@ -9,7 +9,8 @@
{ {
"name": "ArduinoBLE", "name": "ArduinoBLE",
"exclude_targets": [ "exclude_targets": [
"esp32s2" "esp32s2",
"esp32p4"
], ],
"sketch_path": [ "sketch_path": [
"~/Arduino/libraries/ArduinoBLE/examples/Central/Scan/Scan.ino" "~/Arduino/libraries/ArduinoBLE/examples/Central/Scan/Scan.ino"

View file

@ -41204,7 +41204,7 @@ sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2=TinyUF2 4MB (1.3MB APP/960KB F
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader-tinyuf2 sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions-4MB-tinyuf2 sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions-4MB-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.maximum_size=1441792 sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.maximum_size=1441792
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x2d0000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin" sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x2d0000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin" 0x170000 "{runtime.platform.path}/variants/{build.variant}/APOTA.bin"
sensebox_mcu_esp32s2.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) sensebox_mcu_esp32s2.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.default.build.partitions=default sensebox_mcu_esp32s2.menu.PartitionScheme.default.build.partitions=default
sensebox_mcu_esp32s2.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) sensebox_mcu_esp32s2.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
@ -50758,3 +50758,403 @@ cyobot_v2_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
cyobot_v2_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote cyobot_v2_esp32s3.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote
############################################################## ##############################################################
rakwireless_rak3112.name=RAKwireless RAK3112
rakwireless_rak3112.upload.tool=esptool_py
rakwireless_rak3112.upload.tool.default=esptool_py
rakwireless_rak3112.upload.tool.network=esp_ota
rakwireless_rak3112.upload.maximum_size=1310720
rakwireless_rak3112.upload.maximum_data_size=327680
rakwireless_rak3112.upload.wait_for_upload_port=false
rakwireless_rak3112.upload.speed=460800
rakwireless_rak3112.upload.flags=
rakwireless_rak3112.upload.extra_flags=
rakwireless_rak3112.bootloader.tool=esptool_py
rakwireless_rak3112.bootloader.tool.default=esptool_py
rakwireless_rak3112.serial.disableDTR=true
rakwireless_rak3112.serial.disableRTS=true
rakwireless_rak3112.build.tarch=xtensa
rakwireless_rak3112.build.bootloader_addr=0x0
rakwireless_rak3112.build.mcu=esp32s3
rakwireless_rak3112.build.core=esp32
rakwireless_rak3112.build.target=esp32s3
rakwireless_rak3112.build.variant=rakwireless_rak3112
rakwireless_rak3112.build.board=RAKWIRELESS_RAK3112
rakwireless_rak3112.build.usb_mode=1
rakwireless_rak3112.build.cdc_on_boot=1
rakwireless_rak3112.build.msc_on_boot=0
rakwireless_rak3112.build.dfu_on_boot=0
rakwireless_rak3112.build.f_cpu=240000000L
rakwireless_rak3112.build.flash_size=16MB
rakwireless_rak3112.build.flash_freq=80m
rakwireless_rak3112.build.flash_mode=dio
rakwireless_rak3112.build.boot=dio
rakwireless_rak3112.build.partitions=default
rakwireless_rak3112.build.defines=
rakwireless_rak3112.menu.PSRAM.enabled=Enabled
rakwireless_rak3112.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
rakwireless_rak3112.menu.PSRAM.enabled.build.psram_type=opi
rakwireless_rak3112.menu.PSRAM.disabled=Disabled
rakwireless_rak3112.menu.PSRAM.disabled.build.defines=
rakwireless_rak3112.menu.LoopCore.1=Core 1
rakwireless_rak3112.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1
rakwireless_rak3112.menu.LoopCore.0=Core 0
rakwireless_rak3112.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0
rakwireless_rak3112.menu.EventsCore.1=Core 1
rakwireless_rak3112.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
rakwireless_rak3112.menu.EventsCore.0=Core 0
rakwireless_rak3112.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0
rakwireless_rak3112.menu.USBMode.hwcdc=Hardware CDC and JTAG
rakwireless_rak3112.menu.USBMode.hwcdc.build.usb_mode=1
rakwireless_rak3112.menu.USBMode.default=USB-OTG (TinyUSB)
rakwireless_rak3112.menu.USBMode.default.build.usb_mode=0
rakwireless_rak3112.menu.CDCOnBoot.default=Enabled
rakwireless_rak3112.menu.CDCOnBoot.default.build.cdc_on_boot=1
rakwireless_rak3112.menu.CDCOnBoot.cdc=Disabled
rakwireless_rak3112.menu.CDCOnBoot.cdc.build.cdc_on_boot=0
rakwireless_rak3112.menu.MSCOnBoot.default=Disabled
rakwireless_rak3112.menu.MSCOnBoot.default.build.msc_on_boot=0
rakwireless_rak3112.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode)
rakwireless_rak3112.menu.MSCOnBoot.msc.build.msc_on_boot=1
rakwireless_rak3112.menu.DFUOnBoot.default=Disabled
rakwireless_rak3112.menu.DFUOnBoot.default.build.dfu_on_boot=0
rakwireless_rak3112.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode)
rakwireless_rak3112.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
rakwireless_rak3112.menu.UploadMode.default=UART0 / Hardware CDC
rakwireless_rak3112.menu.UploadMode.default.upload.use_1200bps_touch=false
rakwireless_rak3112.menu.UploadMode.default.upload.wait_for_upload_port=false
rakwireless_rak3112.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
rakwireless_rak3112.menu.UploadMode.cdc.upload.use_1200bps_touch=true
rakwireless_rak3112.menu.UploadMode.cdc.upload.wait_for_upload_port=true
rakwireless_rak3112.menu.PartitionScheme.default_16MB=Default (6.25MB APP/3.43MB SPIFFS)
rakwireless_rak3112.menu.PartitionScheme.default_16MB.build.partitions=default_16MB
rakwireless_rak3112.menu.PartitionScheme.default_16MB.upload.maximum_size=6553600
rakwireless_rak3112.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9MB FATFS)
rakwireless_rak3112.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
rakwireless_rak3112.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
rakwireless_rak3112.menu.PartitionScheme.tinyuf2=TinyUF2 16MB (2MB APP/11.6MB FATFS)
rakwireless_rak3112.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader-tinyuf2
rakwireless_rak3112.menu.PartitionScheme.tinyuf2.build.partitions=tinyuf2-partitions-16MB
rakwireless_rak3112.menu.PartitionScheme.tinyuf2.upload.maximum_size=2097152
rakwireless_rak3112.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
rakwireless_rak3112.menu.PartitionScheme.tinyuf2_noota=TinyUF2 16MB No OTA(4MB APP/11.6MB FATFS)
rakwireless_rak3112.menu.PartitionScheme.tinyuf2_noota.build.custom_bootloader=bootloader-tinyuf2
rakwireless_rak3112.menu.PartitionScheme.tinyuf2_noota.build.partitions=tinyuf2-partitions-16MB-noota
rakwireless_rak3112.menu.PartitionScheme.tinyuf2_noota.upload.maximum_size=4194304
rakwireless_rak3112.menu.PartitionScheme.tinyuf2_noota.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
rakwireless_rak3112.menu.PartitionScheme.large_spiffs=Large SPIFFS (4.5MB APP/6.93MB SPIFFS)
rakwireless_rak3112.menu.PartitionScheme.large_spiffs.build.partitions=large_spiffs_16MB
rakwireless_rak3112.menu.PartitionScheme.large_spiffs.upload.maximum_size=4718592
rakwireless_rak3112.menu.PartitionScheme.custom=Custom
rakwireless_rak3112.menu.PartitionScheme.custom.build.partitions=
rakwireless_rak3112.menu.PartitionScheme.custom.upload.maximum_size=16777216
rakwireless_rak3112.menu.CPUFreq.240=240MHz (WiFi/BT)
rakwireless_rak3112.menu.CPUFreq.240.build.f_cpu=240000000L
rakwireless_rak3112.menu.CPUFreq.160=160MHz (WiFi/BT)
rakwireless_rak3112.menu.CPUFreq.160.build.f_cpu=160000000L
rakwireless_rak3112.menu.CPUFreq.80=80MHz (WiFi/BT)
rakwireless_rak3112.menu.CPUFreq.80.build.f_cpu=80000000L
rakwireless_rak3112.menu.FlashMode.qio=QIO
rakwireless_rak3112.menu.FlashMode.qio.build.flash_mode=dio
rakwireless_rak3112.menu.FlashMode.qio.build.boot=qio
rakwireless_rak3112.menu.FlashMode.dio=DIO
rakwireless_rak3112.menu.FlashMode.dio.build.flash_mode=dio
rakwireless_rak3112.menu.FlashMode.dio.build.boot=dio
rakwireless_rak3112.menu.FlashFreq.80=80MHz
rakwireless_rak3112.menu.FlashFreq.80.build.flash_freq=80m
rakwireless_rak3112.menu.FlashFreq.40=40MHz
rakwireless_rak3112.menu.FlashFreq.40.build.flash_freq=40m
rakwireless_rak3112.menu.UploadSpeed.921600=921600
rakwireless_rak3112.menu.UploadSpeed.921600.upload.speed=921600
rakwireless_rak3112.menu.UploadSpeed.115200=115200
rakwireless_rak3112.menu.UploadSpeed.115200.upload.speed=115200
rakwireless_rak3112.menu.UploadSpeed.256000.windows=256000
rakwireless_rak3112.menu.UploadSpeed.256000.upload.speed=256000
rakwireless_rak3112.menu.UploadSpeed.230400.windows.upload.speed=256000
rakwireless_rak3112.menu.UploadSpeed.230400=230400
rakwireless_rak3112.menu.UploadSpeed.230400.upload.speed=230400
rakwireless_rak3112.menu.UploadSpeed.460800.linux=460800
rakwireless_rak3112.menu.UploadSpeed.460800.macosx=460800
rakwireless_rak3112.menu.UploadSpeed.460800.upload.speed=460800
rakwireless_rak3112.menu.UploadSpeed.512000.windows=512000
rakwireless_rak3112.menu.UploadSpeed.512000.upload.speed=512000
rakwireless_rak3112.menu.DebugLevel.none=None
rakwireless_rak3112.menu.DebugLevel.none.build.code_debug=0
rakwireless_rak3112.menu.DebugLevel.error=Error
rakwireless_rak3112.menu.DebugLevel.error.build.code_debug=1
rakwireless_rak3112.menu.DebugLevel.warn=Warn
rakwireless_rak3112.menu.DebugLevel.warn.build.code_debug=2
rakwireless_rak3112.menu.DebugLevel.info=Info
rakwireless_rak3112.menu.DebugLevel.info.build.code_debug=3
rakwireless_rak3112.menu.DebugLevel.debug=Debug
rakwireless_rak3112.menu.DebugLevel.debug.build.code_debug=4
rakwireless_rak3112.menu.DebugLevel.verbose=Verbose
rakwireless_rak3112.menu.DebugLevel.verbose.build.code_debug=5
rakwireless_rak3112.menu.EraseFlash.none=Disabled
rakwireless_rak3112.menu.EraseFlash.none.upload.erase_cmd=
rakwireless_rak3112.menu.EraseFlash.all=Enabled
rakwireless_rak3112.menu.EraseFlash.all.upload.erase_cmd=-e
##############################################################
kodedot.name=kode dot
kodedot.bootloader.tool=esptool_py
kodedot.bootloader.tool.default=esptool_py
kodedot.upload.tool=esptool_py_app_only
kodedot.upload.tool.default=esptool_py_app_only
kodedot.upload.tool.network=esp_ota
kodedot.upload.maximum_size=8388608
kodedot.upload.maximum_data_size=327680
kodedot.upload.flags=
kodedot.upload.extra_flags=
kodedot.upload.use_1200bps_touch=false
kodedot.upload.wait_for_upload_port=false
kodedot.upload.speed=921600
kodedot.upload.erase_cmd=
kodedot.serial.disableDTR=false
kodedot.serial.disableRTS=false
kodedot.build.tarch=xtensa
kodedot.build.bootloader_addr=0x0
kodedot.build.target=esp32s3
kodedot.build.mcu=esp32s3
kodedot.build.core=esp32
kodedot.build.variant=kodedot
kodedot.build.board=KODE_DOT
kodedot.build.usb_mode=1
kodedot.build.cdc_on_boot=1
kodedot.build.msc_on_boot=0
kodedot.build.dfu_on_boot=0
kodedot.build.f_cpu=240000000L
kodedot.build.flash_offset=0x400000
kodedot.build.flash_size=16MB
kodedot.build.flash_freq=80m
kodedot.build.flash_mode=dio
kodedot.build.custom_partitions=kodedot_partitions
kodedot.build.psram_type=qspi
kodedot.build.defines=
kodedot.build.loop_core=-DARDUINO_RUNNING_CORE=1
kodedot.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
kodedot.recipe.hooks.objcopy.postobjcopy.3.pattern=
kodedot.recipe.hooks.objcopy.postobjcopy.3.pattern_args=
kodedot.recipe.output.save_file={build.project_name}.ino.bin
##############################################################
# FED4 Board
fed4.name=FED4
fed4.vid.0=0x303A
fed4.pid.0=0x82E5
fed4.upload_port.0.vid=0x303A
fed4.upload_port.0.pid=0x82E5
fed4.bootloader.tool=esptool_py
fed4.bootloader.tool.default=esptool_py
fed4.upload.tool=esptool_py
fed4.upload.tool.default=esptool_py
fed4.upload.tool.network=esp_ota
fed4.upload.maximum_size=1310720
fed4.upload.maximum_data_size=327680
fed4.upload.flags=
fed4.upload.extra_flags=
fed4.upload.use_1200bps_touch=false
fed4.upload.wait_for_upload_port=false
fed4.serial.disableDTR=false
fed4.serial.disableRTS=false
fed4.build.tarch=xtensa
fed4.build.bootloader_addr=0x0
fed4.build.target=esp32s3
fed4.build.mcu=esp32s3
fed4.build.core=esp32
fed4.build.variant=fed4
fed4.build.board=FED4
fed4.build.usb_mode=1
fed4.build.cdc_on_boot=0
fed4.build.msc_on_boot=0
fed4.build.dfu_on_boot=0
fed4.build.f_cpu=240000000L
fed4.build.flash_size=16MB
fed4.build.flash_freq=80m
fed4.build.flash_mode=dio
fed4.build.boot=qio
fed4.build.boot_freq=80m
fed4.build.partitions=default_16MB
fed4.build.defines=
fed4.build.loop_core=
fed4.build.event_core=
fed4.build.psram_type=qspi
fed4.build.memory_type={build.boot}_{build.psram_type}
## IDE 2.0 Seems to not update the value
fed4.menu.JTAGAdapter.default=Disabled
fed4.menu.JTAGAdapter.default.build.copy_jtag_files=0
fed4.menu.JTAGAdapter.builtin=Integrated USB JTAG
fed4.menu.JTAGAdapter.builtin.build.openocdscript=fed4-builtin.cfg
fed4.menu.JTAGAdapter.builtin.build.copy_jtag_files=1
fed4.menu.JTAGAdapter.external=FTDI Adapter
fed4.menu.JTAGAdapter.external.build.openocdscript=fed4-ftdi.cfg
fed4.menu.JTAGAdapter.external.build.copy_jtag_files=1
fed4.menu.JTAGAdapter.bridge=ESP USB Bridge
fed4.menu.JTAGAdapter.bridge.build.openocdscript=fed4-bridge.cfg
fed4.menu.JTAGAdapter.bridge.build.copy_jtag_files=1
fed4.menu.FlashMode.qio=QIO 80MHz
fed4.menu.FlashMode.qio.build.flash_mode=dio
fed4.menu.FlashMode.qio.build.boot=qio
fed4.menu.FlashMode.qio.build.boot_freq=80m
fed4.menu.FlashMode.qio.build.flash_freq=80m
fed4.menu.FlashMode.qio120=QIO 120MHz
fed4.menu.FlashMode.qio120.build.flash_mode=dio
fed4.menu.FlashMode.qio120.build.boot=qio
fed4.menu.FlashMode.qio120.build.boot_freq=120m
fed4.menu.FlashMode.qio120.build.flash_freq=80m
fed4.menu.FlashMode.dio=DIO 80MHz
fed4.menu.FlashMode.dio.build.flash_mode=dio
fed4.menu.FlashMode.dio.build.boot=dio
fed4.menu.FlashMode.dio.build.boot_freq=80m
fed4.menu.FlashMode.dio.build.flash_freq=80m
fed4.menu.FlashSize.16M=16MB (128Mb)
fed4.menu.FlashSize.16M.build.flash_size=16MB
fed4.menu.LoopCore.1=Core 1
fed4.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1
fed4.menu.LoopCore.0=Core 0
fed4.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0
fed4.menu.EventsCore.1=Core 1
fed4.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
fed4.menu.EventsCore.0=Core 0
fed4.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0
fed4.menu.USBMode.hwcdc=Hardware CDC and JTAG
fed4.menu.USBMode.hwcdc.build.usb_mode=1
fed4.menu.USBMode.default=USB-OTG (TinyUSB)
fed4.menu.USBMode.default.build.usb_mode=0
fed4.menu.CDCOnBoot.default=Disabled
fed4.menu.CDCOnBoot.default.build.cdc_on_boot=0
fed4.menu.CDCOnBoot.cdc=Enabled
fed4.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
fed4.menu.MSCOnBoot.default=Disabled
fed4.menu.MSCOnBoot.default.build.msc_on_boot=0
fed4.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode)
fed4.menu.MSCOnBoot.msc.build.msc_on_boot=1
fed4.menu.DFUOnBoot.default=Disabled
fed4.menu.DFUOnBoot.default.build.dfu_on_boot=0
fed4.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode)
fed4.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
fed4.menu.UploadMode.default=UART0 / Hardware CDC
fed4.menu.UploadMode.default.upload.use_1200bps_touch=false
fed4.menu.UploadMode.default.upload.wait_for_upload_port=false
fed4.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
fed4.menu.UploadMode.cdc.upload.use_1200bps_touch=true
fed4.menu.UploadMode.cdc.upload.wait_for_upload_port=true
fed4.menu.PartitionScheme.default_16MB=Default (6.25MB APP/3.43MB SPIFFS)
fed4.menu.PartitionScheme.default_16MB.build.partitions=default_16MB
fed4.menu.PartitionScheme.default_16MB.upload.maximum_size=6553600
fed4.menu.PartitionScheme.large_spiffs=Large SPIFFS (4.5MB APP/6.93MB SPIFFS)
fed4.menu.PartitionScheme.large_spiffs.build.partitions=large_spiffs_16MB
fed4.menu.PartitionScheme.large_spiffs.upload.maximum_size=4718592
fed4.menu.PartitionScheme.app3M_fat9M_16MB=FFAT (3MB APP/9MB FATFS)
fed4.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
fed4.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
fed4.menu.PartitionScheme.fatflash=Large FFAT (2MB APP/12.5MB FATFS)
fed4.menu.PartitionScheme.fatflash.build.partitions=ffat
fed4.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
fed4.menu.CPUFreq.240=240MHz (WiFi)
fed4.menu.CPUFreq.240.build.f_cpu=240000000L
fed4.menu.CPUFreq.160=160MHz (WiFi)
fed4.menu.CPUFreq.160.build.f_cpu=160000000L
fed4.menu.CPUFreq.80=80MHz (WiFi)
fed4.menu.CPUFreq.80.build.f_cpu=80000000L
fed4.menu.CPUFreq.40=40MHz
fed4.menu.CPUFreq.40.build.f_cpu=40000000L
fed4.menu.CPUFreq.20=20MHz
fed4.menu.CPUFreq.20.build.f_cpu=20000000L
fed4.menu.CPUFreq.10=10MHz
fed4.menu.CPUFreq.10.build.f_cpu=10000000L
fed4.menu.UploadSpeed.921600=921600
fed4.menu.UploadSpeed.921600.upload.speed=921600
fed4.menu.UploadSpeed.115200=115200
fed4.menu.UploadSpeed.115200.upload.speed=115200
fed4.menu.UploadSpeed.256000.windows=256000
fed4.menu.UploadSpeed.256000.upload.speed=256000
fed4.menu.UploadSpeed.230400.windows.upload.speed=256000
fed4.menu.UploadSpeed.230400=230400
fed4.menu.UploadSpeed.230400.upload.speed=230400
fed4.menu.UploadSpeed.460800.linux=460800
fed4.menu.UploadSpeed.460800.macosx=460800
fed4.menu.UploadSpeed.460800.upload.speed=460800
fed4.menu.UploadSpeed.512000.windows=512000
fed4.menu.UploadSpeed.512000.upload.speed=512000
fed4.menu.DebugLevel.none=None
fed4.menu.DebugLevel.none.build.code_debug=0
fed4.menu.DebugLevel.error=Error
fed4.menu.DebugLevel.error.build.code_debug=1
fed4.menu.DebugLevel.warn=Warn
fed4.menu.DebugLevel.warn.build.code_debug=2
fed4.menu.DebugLevel.info=Info
fed4.menu.DebugLevel.info.build.code_debug=3
fed4.menu.DebugLevel.debug=Debug
fed4.menu.DebugLevel.debug.build.code_debug=4
fed4.menu.DebugLevel.verbose=Verbose
fed4.menu.DebugLevel.verbose.build.code_debug=5
fed4.menu.EraseFlash.none=Disabled
fed4.menu.EraseFlash.none.upload.erase_cmd=
fed4.menu.EraseFlash.all=Enabled
fed4.menu.EraseFlash.all.upload.erase_cmd=-e
fed4.menu.ZigbeeMode.default=Disabled
fed4.menu.ZigbeeMode.default.build.zigbee_mode=
fed4.menu.ZigbeeMode.default.build.zigbee_libs=
fed4.menu.ZigbeeMode.zczr=Zigbee ZCZR (coordinator/router)
fed4.menu.ZigbeeMode.zczr.build.zigbee_mode=-DZIGBEE_MODE_ZCZR
fed4.menu.ZigbeeMode.zczr.build.zigbee_libs=-lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.remote
##############################################################

View file

@ -180,7 +180,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (maxStrLen < sizeof(sso.buff) - 1) { if (maxStrLen < sizeof(sso.buff) - 1) {
if (isSSO() || !buffer()) { if (isSSO() || !buffer()) {
// Already using SSO, nothing to do // Already using SSO, nothing to do
uint16_t oldLen = len(); size_t oldLen = len();
setSSO(true); setSSO(true);
setLen(oldLen); setLen(oldLen);
} else { // if bufptr && !isSSO() } else { // if bufptr && !isSSO()
@ -188,7 +188,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
char temp[sizeof(sso.buff)]; char temp[sizeof(sso.buff)];
memcpy(temp, buffer(), maxStrLen); memcpy(temp, buffer(), maxStrLen);
free(wbuffer()); free(wbuffer());
uint16_t oldLen = len(); size_t oldLen = len();
setSSO(true); setSSO(true);
memcpy(wbuffer(), temp, maxStrLen); memcpy(wbuffer(), temp, maxStrLen);
setLen(oldLen); setLen(oldLen);
@ -201,7 +201,7 @@ bool String::changeBuffer(unsigned int maxStrLen) {
if (newSize > CAPACITY_MAX) { if (newSize > CAPACITY_MAX) {
return false; return false;
} }
uint16_t oldLen = len(); size_t oldLen = len();
char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize); char *newbuffer = (char *)realloc(isSSO() ? nullptr : wbuffer(), newSize);
if (newbuffer) { if (newbuffer) {
size_t oldSize = capacity() + 1; // include NULL. size_t oldSize = capacity() + 1; // include NULL.

View file

@ -1,37 +1,10 @@
#include "esp_camera.h" #include "esp_camera.h"
#include <WiFi.h> #include <WiFi.h>
// // ===========================
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality // Select camera model in board_config.h
// Ensure ESP32 Wrover Module or other board with PSRAM is selected // ===========================
// Partial images will be transmitted if image exceeds buffer size #include "board_config.h"
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"
// =========================== // ===========================
// Enter your WiFi credentials // Enter your WiFi credentials
@ -40,7 +13,7 @@ const char *ssid = "**********";
const char *password = "**********"; const char *password = "**********";
void startCameraServer(); void startCameraServer();
void setupLedFlash(int pin); void setupLedFlash();
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -130,7 +103,7 @@ void setup() {
// Setup LED FLash if LED pin is defined in camera_pins.h // Setup LED FLash if LED pin is defined in camera_pins.h
#if defined(LED_GPIO_NUM) #if defined(LED_GPIO_NUM)
setupLedFlash(LED_GPIO_NUM); setupLedFlash();
#endif #endif
WiFi.begin(ssid, password); WiFi.begin(ssid, password);

View file

@ -19,18 +19,14 @@
#include "esp32-hal-ledc.h" #include "esp32-hal-ledc.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "camera_index.h" #include "camera_index.h"
#include "board_config.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h" #include "esp32-hal-log.h"
#endif #endif
// Enable LED FLASH setting
#define CONFIG_LED_ILLUMINATOR_ENABLED 1
// LED FLASH setup // LED FLASH setup
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
#define LED_LEDC_GPIO 22 //configure LED pin
#define CONFIG_LED_MAX_INTENSITY 255 #define CONFIG_LED_MAX_INTENSITY 255
int led_duty = 0; int led_duty = 0;
@ -91,13 +87,13 @@ static int ra_filter_run(ra_filter_t *filter, int value) {
} }
#endif #endif
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
void enable_led(bool en) { // Turn LED On or Off void enable_led(bool en) { // Turn LED On or Off
int duty = en ? led_duty : 0; int duty = en ? led_duty : 0;
if (en && isStreaming && (led_duty > CONFIG_LED_MAX_INTENSITY)) { if (en && isStreaming && (led_duty > CONFIG_LED_MAX_INTENSITY)) {
duty = CONFIG_LED_MAX_INTENSITY; duty = CONFIG_LED_MAX_INTENSITY;
} }
ledcWrite(LED_LEDC_GPIO, duty); ledcWrite(LED_GPIO_NUM, duty);
//ledc_set_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL, duty); //ledc_set_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL, duty);
//ledc_update_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL); //ledc_update_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL);
log_i("Set LED intensity to %d", duty); log_i("Set LED intensity to %d", duty);
@ -162,7 +158,7 @@ static esp_err_t capture_handler(httpd_req_t *req) {
int64_t fr_start = esp_timer_get_time(); int64_t fr_start = esp_timer_get_time();
#endif #endif
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
enable_led(true); enable_led(true);
vTaskDelay(150 / portTICK_PERIOD_MS); // The LED needs to be turned on ~150ms before the call to esp_camera_fb_get() vTaskDelay(150 / portTICK_PERIOD_MS); // The LED needs to be turned on ~150ms before the call to esp_camera_fb_get()
fb = esp_camera_fb_get(); // or it won't be visible in the frame. A better way to do this is needed. fb = esp_camera_fb_get(); // or it won't be visible in the frame. A better way to do this is needed.
@ -230,7 +226,7 @@ static esp_err_t stream_handler(httpd_req_t *req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60"); httpd_resp_set_hdr(req, "X-Framerate", "60");
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
isStreaming = true; isStreaming = true;
enable_led(true); enable_led(true);
#endif #endif
@ -293,7 +289,7 @@ static esp_err_t stream_handler(httpd_req_t *req) {
); );
} }
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
isStreaming = false; isStreaming = false;
enable_led(false); enable_led(false);
#endif #endif
@ -393,7 +389,7 @@ static esp_err_t cmd_handler(httpd_req_t *req) {
} else if (!strcmp(variable, "ae_level")) { } else if (!strcmp(variable, "ae_level")) {
res = s->set_ae_level(s, val); res = s->set_ae_level(s, val);
} }
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
else if (!strcmp(variable, "led_intensity")) { else if (!strcmp(variable, "led_intensity")) {
led_duty = val; led_duty = val;
if (isStreaming) { if (isStreaming) {
@ -481,7 +477,7 @@ static esp_err_t status_handler(httpd_req_t *req) {
p += sprintf(p, "\"vflip\":%u,", s->status.vflip); p += sprintf(p, "\"vflip\":%u,", s->status.vflip);
p += sprintf(p, "\"dcw\":%u,", s->status.dcw); p += sprintf(p, "\"dcw\":%u,", s->status.dcw);
p += sprintf(p, "\"colorbar\":%u", s->status.colorbar); p += sprintf(p, "\"colorbar\":%u", s->status.colorbar);
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
p += sprintf(p, ",\"led_intensity\":%u", led_duty); p += sprintf(p, ",\"led_intensity\":%u", led_duty);
#else #else
p += sprintf(p, ",\"led_intensity\":%d", -1); p += sprintf(p, ",\"led_intensity\":%d", -1);
@ -843,10 +839,10 @@ void startCameraServer() {
} }
} }
void setupLedFlash(int pin) { void setupLedFlash() {
#if CONFIG_LED_ILLUMINATOR_ENABLED #if defined(LED_GPIO_NUM)
ledcAttach(pin, 5000, 8); ledcAttach(LED_GPIO_NUM, 5000, 8);
#else #else
log_i("LED flash is disabled -> CONFIG_LED_ILLUMINATOR_ENABLED = 0"); log_i("LED flash is disabled -> LED_GPIO_NUM undefined");
#endif #endif
} }

View file

@ -0,0 +1,34 @@
#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// ===================
// Select camera model
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_CAMS3_UNIT // Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM
//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM
#include "camera_pins.h"
#endif // BOARD_CONFIG_H

View file

@ -86,6 +86,8 @@ void setup() {
ESP.restart(); ESP.restart();
} }
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("Setup complete. Broadcasting messages every 5 seconds."); Serial.println("Setup complete. Broadcasting messages every 5 seconds.");
} }

View file

@ -104,6 +104,8 @@ void setup() {
ESP.restart(); ESP.restart();
} }
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
// Register the new peer callback // Register the new peer callback
ESP_NOW.onNewPeer(register_new_master, nullptr); ESP_NOW.onNewPeer(register_new_master, nullptr);

View file

@ -75,7 +75,12 @@
// The following struct is used to send data to the peer device. // The following struct is used to send data to the peer device.
// We use the attribute "packed" to ensure that the struct is not padded (all data // We use the attribute "packed" to ensure that the struct is not padded (all data
// is contiguous in the memory and without gaps). // is contiguous in the memory and without gaps).
// The maximum size of the complete message is 250 bytes (ESP_NOW_MAX_DATA_LEN). // The maximum size of the payload is 250 bytes (ESP_NOW_MAX_DATA_LEN) for ESP-NOW v1.0.
// For ESP-NOW v2.0, the maximum size of the payload is 1470 bytes (ESP_NOW_MAX_DATA_LEN_V2).
// You can use ESP_NOW.getMaxDataLen() after calling ESP_NOW.begin() to get the maximum size
// of the data that can be sent.
// Read about the compatibility between ESP-NOW v1.0 and v2.0 in the ESP-IDF documentation:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html#frame-format
typedef struct { typedef struct {
uint32_t count; uint32_t count;
@ -276,6 +281,8 @@ void setup() {
fail_reboot(); fail_reboot();
} }
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
if (!broadcast_peer.begin()) { if (!broadcast_peer.begin()) {
Serial.println("Failed to initialize broadcast peer"); Serial.println("Failed to initialize broadcast peer");
fail_reboot(); fail_reboot();

View file

@ -64,6 +64,7 @@ void setup() {
// Start the ESP-NOW communication // Start the ESP-NOW communication
Serial.println("ESP-NOW communication starting..."); Serial.println("ESP-NOW communication starting...");
NowSerial.begin(115200); NowSerial.begin(115200);
Serial.printf("ESP-NOW version: %d, max data length: %d\n", ESP_NOW.getVersion(), ESP_NOW.getMaxDataLen());
Serial.println("You can now send data to the peer device using the Serial Monitor.\n"); Serial.println("You can now send data to the peer device using the Serial Monitor.\n");
} }

View file

@ -145,7 +145,10 @@ static void _esp_now_tx_cb(const uint8_t *mac_addr, esp_now_send_status_t status
} }
} }
ESP_NOW_Class::ESP_NOW_Class() {} ESP_NOW_Class::ESP_NOW_Class() {
max_data_len = 0;
version = 0;
}
ESP_NOW_Class::~ESP_NOW_Class() {} ESP_NOW_Class::~ESP_NOW_Class() {}
@ -160,6 +163,23 @@ bool ESP_NOW_Class::begin(const uint8_t *pmk) {
return false; return false;
} }
// Unfortunately we can't get the ESP-NOW version before initializing the Wi-Fi
uint32_t esp_now_version;
err = esp_now_get_version(&esp_now_version);
if (err != ESP_OK) {
log_w("esp_now_get_version failed! Assuming ESP-NOW v1.0");
esp_now_version = 1;
}
if (esp_now_version == 1) {
max_data_len = ESP_NOW_MAX_DATA_LEN;
} else {
max_data_len = ESP_NOW_MAX_DATA_LEN_V2;
}
version = esp_now_version;
log_i("ESP-NOW version: %lu, max_data_len: %lu", version, max_data_len);
_esp_now_has_begun = true; _esp_now_has_begun = true;
memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM); memset(_esp_now_peers, 0, sizeof(ESP_NOW_Peer *) * ESP_NOW_MAX_TOTAL_PEER_NUM);
@ -217,7 +237,7 @@ bool ESP_NOW_Class::end() {
return true; return true;
} }
int ESP_NOW_Class::getTotalPeerCount() { int ESP_NOW_Class::getTotalPeerCount() const {
if (!_esp_now_has_begun) { if (!_esp_now_has_begun) {
return -1; return -1;
} }
@ -230,7 +250,7 @@ int ESP_NOW_Class::getTotalPeerCount() {
return num.total_num; return num.total_num;
} }
int ESP_NOW_Class::getEncryptedPeerCount() { int ESP_NOW_Class::getEncryptedPeerCount() const {
if (!_esp_now_has_begun) { if (!_esp_now_has_begun) {
return -1; return -1;
} }
@ -243,16 +263,38 @@ int ESP_NOW_Class::getEncryptedPeerCount() {
return num.encrypt_num; return num.encrypt_num;
} }
int ESP_NOW_Class::getMaxDataLen() const {
if (max_data_len == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the max data length.");
return -1;
}
return max_data_len;
}
int ESP_NOW_Class::getVersion() const {
if (version == 0) {
log_e("ESP-NOW not initialized. Please call begin() first to get the version.");
return -1;
}
return version;
}
int ESP_NOW_Class::availableForWrite() { int ESP_NOW_Class::availableForWrite() {
return ESP_NOW_MAX_DATA_LEN; int available = getMaxDataLen();
if (available < 0) {
return 0;
}
return available;
} }
size_t ESP_NOW_Class::write(const uint8_t *data, size_t len) { size_t ESP_NOW_Class::write(const uint8_t *data, size_t len) {
if (!_esp_now_has_begun) { if (!_esp_now_has_begun) {
return 0; return 0;
} }
if (len > ESP_NOW_MAX_DATA_LEN) { if (len > max_data_len) {
len = ESP_NOW_MAX_DATA_LEN; len = max_data_len;
} }
esp_err_t result = esp_now_send(nullptr, data, len); esp_err_t result = esp_now_send(nullptr, data, len);
if (result == ESP_OK) { if (result == ESP_OK) {
@ -391,8 +433,15 @@ size_t ESP_NOW_Peer::send(const uint8_t *data, int len) {
log_e("Peer not added."); log_e("Peer not added.");
return 0; return 0;
} }
if (len > ESP_NOW_MAX_DATA_LEN) {
len = ESP_NOW_MAX_DATA_LEN; int max_data_len = ESP_NOW.getMaxDataLen();
if (max_data_len < 0) {
log_e("Error getting max data length.");
return 0;
}
if (len > max_data_len) {
len = max_data_len;
} }
esp_err_t result = esp_now_send(mac, data, len); esp_err_t result = esp_now_send(mac, data, len);
if (result == ESP_OK) { if (result == ESP_OK) {

View file

@ -23,8 +23,10 @@ public:
bool begin(const uint8_t *pmk = nullptr /* 16 bytes */); bool begin(const uint8_t *pmk = nullptr /* 16 bytes */);
bool end(); bool end();
int getTotalPeerCount(); int getTotalPeerCount() const;
int getEncryptedPeerCount(); int getEncryptedPeerCount() const;
int getMaxDataLen() const;
int getVersion() const;
int availableForWrite(); int availableForWrite();
size_t write(const uint8_t *data, size_t len); size_t write(const uint8_t *data, size_t len);
@ -34,6 +36,10 @@ public:
void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg); void onNewPeer(void (*cb)(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg), void *arg);
bool removePeer(ESP_NOW_Peer &peer); bool removePeer(ESP_NOW_Peer &peer);
protected:
size_t max_data_len;
uint32_t version;
}; };
class ESP_NOW_Peer { class ESP_NOW_Peer {

View file

@ -70,8 +70,25 @@ bool ESP_NOW_Serial_Class::begin(unsigned long baud) {
//xSemaphoreTake(tx_sem, 0); //xSemaphoreTake(tx_sem, 0);
xSemaphoreGive(tx_sem); xSemaphoreGive(tx_sem);
} }
setRxBufferSize(1024); //default if not preset
setTxBufferSize(1024); //default if not preset size_t buf_size = 0;
if (ESP_NOW.getVersion() == 2) {
// ESP-NOW v2.0 has a larger maximum data length, so we need to increase the buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(4096);
buf_size &= setTxBufferSize(4096);
} else {
// ESP-NOW v1.0 has a smaller maximum data length, so we can use the default buffer sizes
// to hold around 3-4 packets
buf_size = setRxBufferSize(1024);
buf_size &= setTxBufferSize(1024);
}
if (buf_size == 0) {
log_e("Failed to set buffer size");
return false;
}
return true; return true;
} }
@ -164,7 +181,6 @@ void ESP_NOW_Serial_Class::onReceive(const uint8_t *data, size_t len, bool broad
//Print //Print
int ESP_NOW_Serial_Class::availableForWrite() { int ESP_NOW_Serial_Class::availableForWrite() {
//return ESP_NOW_MAX_DATA_LEN;
if (tx_ring_buf == nullptr) { if (tx_ring_buf == nullptr) {
return 0; return 0;
} }
@ -189,7 +205,7 @@ bool ESP_NOW_Serial_Class::checkForTxData() {
//do we have something that failed the last time? //do we have something that failed the last time?
resend_count = 0; resend_count = 0;
if (queued_buff == nullptr) { if (queued_buff == nullptr) {
queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW_MAX_DATA_LEN); queued_buff = (uint8_t *)xRingbufferReceiveUpTo(tx_ring_buf, &queued_size, 0, ESP_NOW.getMaxDataLen());
} else { } else {
log_d(MACSTR " : PREVIOUS", MAC2STR(addr())); log_d(MACSTR " : PREVIOUS", MAC2STR(addr()));
} }

View file

@ -27,6 +27,7 @@ static const char serverIndex[] PROGMEM =
</body> </body>
</html>)"; </html>)";
static const char successResponse[] PROGMEM = "<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting..."; static const char successResponse[] PROGMEM = "<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...";
static const char *csrfHeaders[2] = {"Origin", "Host"};
class HTTPUpdateServer { class HTTPUpdateServer {
public: public:
@ -56,6 +57,9 @@ public:
_username = username; _username = username;
_password = password; _password = password;
// collect headers for CSRF verification
_server->collectHeaders(csrfHeaders, 2);
// handler for the /update form page // handler for the /update form page
_server->on(path.c_str(), HTTP_GET, [&]() { _server->on(path.c_str(), HTTP_GET, [&]() {
if (_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str())) { if (_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str())) {
@ -69,6 +73,10 @@ public:
path.c_str(), HTTP_POST, path.c_str(), HTTP_POST,
[&]() { [&]() {
if (!_authenticated) { if (!_authenticated) {
if (_username == emptyString || _password == emptyString) {
_server->send(200, F("text/html"), String(F("Update error: Wrong origin received!")));
return;
}
return _server->requestAuthentication(); return _server->requestAuthentication();
} }
if (Update.hasError()) { if (Update.hasError()) {
@ -100,6 +108,17 @@ public:
return; return;
} }
String origin = _server->header(String(csrfHeaders[0]));
String host = _server->header(String(csrfHeaders[1]));
String expectedOrigin = String("http://") + host;
if (origin != expectedOrigin) {
if (_serial_output) {
Serial.printf("Wrong origin received! Expected: %s, Received: %s\n", expectedOrigin.c_str(), origin.c_str());
}
_authenticated = false;
return;
}
if (_serial_output) { if (_serial_output) {
Serial.printf("Update: %s\n", upload.filename.c_str()); Serial.printf("Update: %s\n", upload.filename.c_str());
} }

View file

@ -22,6 +22,10 @@ using namespace fs;
SDFS::SDFS(FSImplPtr impl) : FS(impl), _pdrv(0xFF) {} SDFS::SDFS(FSImplPtr impl) : FS(impl), _pdrv(0xFF) {}
SDFS::~SDFS() {
end();
}
bool SDFS::begin(uint8_t ssPin, SPIClass &spi, uint32_t frequency, const char *mountpoint, uint8_t max_files, bool format_if_empty) { bool SDFS::begin(uint8_t ssPin, SPIClass &spi, uint32_t frequency, const char *mountpoint, uint8_t max_files, bool format_if_empty) {
if (_pdrv != 0xFF) { if (_pdrv != 0xFF) {
return true; return true;

View file

@ -26,6 +26,7 @@ protected:
public: public:
SDFS(FSImplPtr impl); SDFS(FSImplPtr impl);
~SDFS();
bool begin( bool begin(
uint8_t ssPin = SS, SPIClass &spi = SPI, uint32_t frequency = 4000000, const char *mountpoint = "/sd", uint8_t max_files = 5, bool format_if_empty = false uint8_t ssPin = SS, SPIClass &spi = SPI, uint32_t frequency = 4000000, const char *mountpoint = "/sd", uint8_t max_files = 5, bool format_if_empty = false
); );

View file

@ -8,10 +8,17 @@
#define SSID_FORMAT "ESP32-%06lX" // 12 chars total #define SSID_FORMAT "ESP32-%06lX" // 12 chars total
//#define PASSWORD "test123456" // generate if remarked //#define PASSWORD "test123456" // generate if remarked
// Set the username and password for firmware upload
const char *authUser = "........";
const char *authPass = "........";
WebServer server(80); WebServer server(80);
Ticker tkSecond; Ticker tkSecond;
uint8_t otaDone = 0; uint8_t otaDone = 0;
const char *csrfHeaders[2] = {"Origin", "Host"};
static bool authenticated = false;
const char *alphanum = "0123456789!@#$%^&*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *alphanum = "0123456789!@#$%^&*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String generatePass(uint8_t str_len) { String generatePass(uint8_t str_len) {
String buff; String buff;
@ -38,6 +45,9 @@ void apMode() {
} }
void handleUpdateEnd() { void handleUpdateEnd() {
if (!authenticated) {
return server.requestAuthentication();
}
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
if (Update.hasError()) { if (Update.hasError()) {
server.send(502, "text/plain", Update.errorString()); server.send(502, "text/plain", Update.errorString());
@ -45,6 +55,7 @@ void handleUpdateEnd() {
server.sendHeader("Refresh", "10"); server.sendHeader("Refresh", "10");
server.sendHeader("Location", "/"); server.sendHeader("Location", "/");
server.send(307); server.send(307);
delay(500);
ESP.restart(); ESP.restart();
} }
} }
@ -56,18 +67,34 @@ void handleUpdate() {
} }
HTTPUpload &upload = server.upload(); HTTPUpload &upload = server.upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
authenticated = server.authenticate(authUser, authPass);
if (!authenticated) {
Serial.println("Authentication fail!");
otaDone = 0;
return;
}
String origin = server.header(String(csrfHeaders[0]));
String host = server.header(String(csrfHeaders[1]));
String expectedOrigin = String("http://") + host;
if (origin != expectedOrigin) {
Serial.printf("Wrong origin received! Expected: %s, Received: %s\n", expectedOrigin.c_str(), origin.c_str());
authenticated = false;
otaDone = 0;
return;
}
Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize); Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
if (!Update.begin(fsize)) { if (!Update.begin(fsize)) {
otaDone = 0; otaDone = 0;
Update.printError(Serial); Update.printError(Serial);
} }
} else if (upload.status == UPLOAD_FILE_WRITE) { } else if (authenticated && upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial); Update.printError(Serial);
} else { } else {
otaDone = 100 * Update.progress() / Update.size(); otaDone = 100 * Update.progress() / Update.size();
} }
} else if (upload.status == UPLOAD_FILE_END) { } else if (authenticated && upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { if (Update.end(true)) {
Serial.printf("Update Success: %u bytes\nRebooting...\n", upload.totalSize); Serial.printf("Update Success: %u bytes\nRebooting...\n", upload.totalSize);
} else { } else {
@ -78,6 +105,7 @@ void handleUpdate() {
} }
void webServerInit() { void webServerInit() {
server.collectHeaders(csrfHeaders, 2);
server.on( server.on(
"/update", HTTP_POST, "/update", HTTP_POST,
[]() { []() {
@ -92,6 +120,9 @@ void webServerInit() {
server.send_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len); server.send_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len);
}); });
server.onNotFound([]() { server.onNotFound([]() {
if (!server.authenticate(authUser, authPass)) {
return server.requestAuthentication();
}
server.send(200, "text/html", indexHtml); server.send(200, "text/html", indexHtml);
}); });
server.begin(); server.begin();

View file

@ -12,10 +12,17 @@ const char *host = "esp32-webupdate";
const char *ssid = "........"; const char *ssid = "........";
const char *password = "........"; const char *password = "........";
// Set the username and password for firmware upload
const char *authUser = "........";
const char *authPass = "........";
WebServer server(80); WebServer server(80);
const char *serverIndex = const char *serverIndex =
"<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>"; "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
const char *csrfHeaders[2] = {"Origin", "Host"};
static bool authenticated = false;
void setup(void) { void setup(void) {
Serial.begin(115200); Serial.begin(115200);
Serial.println(); Serial.println();
@ -24,37 +31,63 @@ void setup(void) {
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() == WL_CONNECTED) { if (WiFi.waitForConnectResult() == WL_CONNECTED) {
MDNS.begin(host); MDNS.begin(host);
server.collectHeaders(csrfHeaders, 2);
server.on("/", HTTP_GET, []() { server.on("/", HTTP_GET, []() {
if (!server.authenticate(authUser, authPass)) {
return server.requestAuthentication();
}
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex); server.send(200, "text/html", serverIndex);
}); });
server.on( server.on(
"/update", HTTP_POST, "/update", HTTP_POST,
[]() { []() {
if (!authenticated) {
return server.requestAuthentication();
}
server.sendHeader("Connection", "close"); server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); if (Update.hasError()) {
server.send(200, "text/plain", "FAIL");
} else {
server.send(200, "text/plain", "Success! Rebooting...");
delay(500);
ESP.restart(); ESP.restart();
}
}, },
[]() { []() {
HTTPUpload &upload = server.upload(); HTTPUpload &upload = server.upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
Serial.setDebugOutput(true); Serial.setDebugOutput(true);
authenticated = server.authenticate(authUser, authPass);
if (!authenticated) {
Serial.println("Authentication fail!");
return;
}
String origin = server.header(String(csrfHeaders[0]));
String host = server.header(String(csrfHeaders[1]));
String expectedOrigin = String("http://") + host;
if (origin != expectedOrigin) {
Serial.printf("Wrong origin received! Expected: %s, Received: %s\n", expectedOrigin.c_str(), origin.c_str());
authenticated = false;
return;
}
Serial.printf("Update: %s\n", upload.filename.c_str()); Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin()) { //start with max available size if (!Update.begin()) { //start with max available size
Update.printError(Serial); Update.printError(Serial);
} }
} else if (upload.status == UPLOAD_FILE_WRITE) { } else if (authenticated && upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial); Update.printError(Serial);
} }
} else if (upload.status == UPLOAD_FILE_END) { } else if (authenticated && upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else { } else {
Update.printError(Serial); Update.printError(Serial);
} }
Serial.setDebugOutput(false); Serial.setDebugOutput(false);
} else { } else if (authenticated) {
Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status); Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status);
} }
} }

View file

@ -246,29 +246,67 @@ extern "C" {
extern esp_err_t esp_hosted_init(); extern esp_err_t esp_hosted_init();
extern esp_err_t esp_hosted_deinit(); extern esp_err_t esp_hosted_deinit();
}; };
typedef struct {
uint8_t pin_clk;
uint8_t pin_cmd;
uint8_t pin_d0;
uint8_t pin_d1;
uint8_t pin_d2;
uint8_t pin_d3;
uint8_t pin_reset;
} sdio_pin_config_t;
static bool hosted_initialized = false; static bool hosted_initialized = false;
static sdio_pin_config_t sdio_pin_config = {
#ifdef BOARD_HAS_SDIO_ESP_HOSTED
.pin_clk = BOARD_SDIO_ESP_HOSTED_CLK,
.pin_cmd = BOARD_SDIO_ESP_HOSTED_CMD,
.pin_d0 = BOARD_SDIO_ESP_HOSTED_D0,
.pin_d1 = BOARD_SDIO_ESP_HOSTED_D1,
.pin_d2 = BOARD_SDIO_ESP_HOSTED_D2,
.pin_d3 = BOARD_SDIO_ESP_HOSTED_D3,
.pin_reset = BOARD_SDIO_ESP_HOSTED_RESET
#else
.pin_clk = CONFIG_ESP_SDIO_PIN_CLK,
.pin_cmd = CONFIG_ESP_SDIO_PIN_CMD,
.pin_d0 = CONFIG_ESP_SDIO_PIN_D0,
.pin_d1 = CONFIG_ESP_SDIO_PIN_D1,
.pin_d2 = CONFIG_ESP_SDIO_PIN_D2,
.pin_d3 = CONFIG_ESP_SDIO_PIN_D3,
.pin_reset = CONFIG_ESP_SDIO_GPIO_RESET_SLAVE
#endif
};
bool WiFiGenericClass::setPins(int8_t clk, int8_t cmd, int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t rst) {
if (clk < 0 || cmd < 0 || d0 < 0 || d1 < 0 || d2 < 0 || d3 < 0 || rst < 0) {
log_e("All SDIO pins must be defined");
return false;
}
if (hosted_initialized) {
log_e("SDIO pins must be set before WiFi is initialized");
return false;
}
sdio_pin_config.pin_clk = clk;
sdio_pin_config.pin_cmd = cmd;
sdio_pin_config.pin_d0 = d0;
sdio_pin_config.pin_d1 = d1;
sdio_pin_config.pin_d2 = d2;
sdio_pin_config.pin_d3 = d3;
sdio_pin_config.pin_reset = rst;
return true;
}
static bool wifiHostedInit() { static bool wifiHostedInit() {
if (!hosted_initialized) { if (!hosted_initialized) {
hosted_initialized = true; hosted_initialized = true;
struct esp_hosted_sdio_config conf = INIT_DEFAULT_HOST_SDIO_CONFIG(); struct esp_hosted_sdio_config conf = INIT_DEFAULT_HOST_SDIO_CONFIG();
#ifdef BOARD_HAS_SDIO_ESP_HOSTED conf.pin_clk.pin = sdio_pin_config.pin_clk;
conf.pin_clk.pin = BOARD_SDIO_ESP_HOSTED_CLK; conf.pin_cmd.pin = sdio_pin_config.pin_cmd;
conf.pin_cmd.pin = BOARD_SDIO_ESP_HOSTED_CMD; conf.pin_d0.pin = sdio_pin_config.pin_d0;
conf.pin_d0.pin = BOARD_SDIO_ESP_HOSTED_D0; conf.pin_d1.pin = sdio_pin_config.pin_d1;
conf.pin_d1.pin = BOARD_SDIO_ESP_HOSTED_D1; conf.pin_d2.pin = sdio_pin_config.pin_d2;
conf.pin_d2.pin = BOARD_SDIO_ESP_HOSTED_D2; conf.pin_d3.pin = sdio_pin_config.pin_d3;
conf.pin_d3.pin = BOARD_SDIO_ESP_HOSTED_D3; conf.pin_reset.pin = sdio_pin_config.pin_reset;
conf.pin_reset.pin = BOARD_SDIO_ESP_HOSTED_RESET;
#else
conf.pin_clk.pin = CONFIG_ESP_SDIO_PIN_CLK;
conf.pin_cmd.pin = CONFIG_ESP_SDIO_PIN_CMD;
conf.pin_d0.pin = CONFIG_ESP_SDIO_PIN_D0;
conf.pin_d1.pin = CONFIG_ESP_SDIO_PIN_D1;
conf.pin_d2.pin = CONFIG_ESP_SDIO_PIN_D2;
conf.pin_d3.pin = CONFIG_ESP_SDIO_PIN_D3;
conf.pin_reset.pin = CONFIG_ESP_SDIO_GPIO_RESET_SLAVE;
#endif
// esp_hosted_sdio_set_config() will fail on second attempt but here temporarily to not cause exception on reinit // esp_hosted_sdio_set_config() will fail on second attempt but here temporarily to not cause exception on reinit
if (esp_hosted_sdio_set_config(&conf) != ESP_OK || esp_hosted_init() != ESP_OK) { if (esp_hosted_sdio_set_config(&conf) != ESP_OK || esp_hosted_init() != ESP_OK) {
log_e("esp_hosted_init failed!"); log_e("esp_hosted_init failed!");
@ -279,13 +317,13 @@ static bool wifiHostedInit() {
} }
// Attach pins to PeriMan here // Attach pins to PeriMan here
// Slave chip model is CONFIG_IDF_SLAVE_TARGET // Slave chip model is CONFIG_IDF_SLAVE_TARGET
// CONFIG_ESP_SDIO_PIN_CMD // sdio_pin_config.pin_clk
// CONFIG_ESP_SDIO_PIN_CLK // sdio_pin_config.pin_cmd
// CONFIG_ESP_SDIO_PIN_D0 // sdio_pin_config.pin_d0
// CONFIG_ESP_SDIO_PIN_D1 // sdio_pin_config.pin_d1
// CONFIG_ESP_SDIO_PIN_D2 // sdio_pin_config.pin_d2
// CONFIG_ESP_SDIO_PIN_D3 // sdio_pin_config.pin_d3
// CONFIG_ESP_SDIO_GPIO_RESET_SLAVE // sdio_pin_config.pin_reset
return true; return true;
} }

View file

@ -82,6 +82,11 @@ class WiFiGenericClass {
public: public:
WiFiGenericClass(); WiFiGenericClass();
#if CONFIG_ESP_WIFI_REMOTE_ENABLED
// Set SDIO pins for connection to external ESP MCU
static bool setPins(int8_t clk, int8_t cmd, int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t rst);
#endif
wifi_event_id_t onEvent(WiFiEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); wifi_event_id_t onEvent(WiFiEventCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
wifi_event_id_t onEvent(WiFiEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); wifi_event_id_t onEvent(WiFiEventFuncCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);
wifi_event_id_t onEvent(WiFiEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX); wifi_event_id_t onEvent(WiFiEventSysCb cbEvent, arduino_event_id_t event = ARDUINO_EVENT_MAX);

View file

@ -1,3 +1,4 @@
#include <algorithm>
#include "ZigbeeColorDimmableLight.h" #include "ZigbeeColorDimmableLight.h"
#if CONFIG_ZB_ENABLED #if CONFIG_ZB_ENABLED
@ -127,7 +128,8 @@ bool ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red,
espXyColor_t xy_color = espRgbColorToXYColor(_current_color); espXyColor_t xy_color = espRgbColorToXYColor(_current_color);
espHsvColor_t hsv_color = espRgbColorToHsvColor(_current_color); espHsvColor_t hsv_color = espRgbColorToHsvColor(_current_color);
uint8_t hue = (uint8_t)hsv_color.h; uint8_t hue = std::min((uint8_t)hsv_color.h, (uint8_t)254); // Clamp to 0-254
uint8_t saturation = std::min((uint8_t)hsv_color.s, (uint8_t)254); // Clamp to 0-254
log_v("Updating light state: %d, level: %d, color: %d, %d, %d", state, level, red, green, blue); log_v("Updating light state: %d, level: %d, color: %d, %d, %d", state, level, red, green, blue);
/* Update light clusters */ /* Update light clusters */
@ -174,7 +176,7 @@ bool ZigbeeColorDimmableLight::setLight(bool state, uint8_t level, uint8_t red,
} }
//set saturation //set saturation
ret = esp_zb_zcl_set_attribute_val( ret = esp_zb_zcl_set_attribute_val(
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID, &hsv_color.s, false _endpoint, ESP_ZB_ZCL_CLUSTER_ID_COLOR_CONTROL, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID, &saturation, false
); );
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) { if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set light saturation: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret)); log_e("Failed to set light saturation: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));

View file

@ -339,3 +339,19 @@ tools.dfu-util.cmd=dfu-util
tools.dfu-util.upload.params.verbose=-d tools.dfu-util.upload.params.verbose=-d
tools.dfu-util.upload.params.quiet= tools.dfu-util.upload.params.quiet=
tools.dfu-util.upload.pattern="{path}/{cmd}" --device {vid.0}:{pid.0} -D "{build.path}/{build.project_name}.bin" -Q tools.dfu-util.upload.pattern="{path}/{cmd}" --device {vid.0}:{pid.0} -D "{build.path}/{build.project_name}.bin" -Q
## --------------------------------------------------------------------------
## esptool_py_app_only is used to upload only the application image
## It won't upload the bootloader or any other binary except for the main application
## --------------------------------------------------------------------------
tools.esptool_py_app_only.path={runtime.tools.esptool_py.path}
tools.esptool_py_app_only.cmd=esptool
tools.esptool_py_app_only.cmd.windows=esptool.exe
tools.esptool_py_app_only.upload.protocol=serial
tools.esptool_py_app_only.upload.params.verbose=
tools.esptool_py_app_only.upload.params.quiet=
tools.esptool_py_app_only.upload.pattern_args=--chip {build.mcu} --port "{serial.port}" --baud {upload.speed} {upload.flags} --before default_reset --after hard_reset write_flash --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size {build.flash_size} {build.flash_offset} "{build.path}/{build.project_name}.bin" {upload.extra_flags}
tools.esptool_py_app_only.upload.pattern="{path}/{cmd}" {tools.esptool_py_app_only.upload.pattern_args}

View file

@ -220,8 +220,14 @@ env.Append(
), ),
get_bootloader_image(variants_dir), get_bootloader_image(variants_dir),
), ),
("0x8000", join(env.subst("$BUILD_DIR"), "partitions.bin")), (
("0xe000", join(FRAMEWORK_DIR, "tools", "partitions", "boot_app0.bin")), board_config.get("upload.arduino.partitions_bin", "0x8000"),
join(env.subst("$BUILD_DIR"), "partitions.bin"),
),
(
board_config.get("upload.arduino.boot_app0", "0xe000"),
join(FRAMEWORK_DIR, "tools", "partitions", "boot_app0.bin"),
),
] ]
+ [(offset, join(FRAMEWORK_DIR, img)) for offset, img in board_config.get("upload.arduino.flash_extra_images", [])], + [(offset, join(FRAMEWORK_DIR, img)) for offset, img in board_config.get("upload.arduino.flash_extra_images", [])],
) )

View file

@ -0,0 +1,79 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include "soc/soc_caps.h"
#define USB_VID 0x303A
#define USB_PID 0x82E5
#define USB_MANUFACTURER "Smart Bee Designs LLC"
#define USB_PRODUCT "FED4"
#define USB_SERIAL ""
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 SDA2 = 20;
static const uint8_t SCL2 = 19;
static const uint8_t SS = 47;
static const uint8_t MOSI = 11;
static const uint8_t MISO = 13;
static const uint8_t SCK = 12;
static const uint8_t SDCS = 10; // sd cs pin
static const uint8_t DSCS = 14; //display cs pin
static const uint8_t A1 = 1;
static const uint8_t A2 = 2;
static const uint8_t A3 = 3;
static const uint8_t A4 = 4;
static const uint8_t A5 = 5;
static const uint8_t A6 = 6;
static const uint8_t D1 = 1;
static const uint8_t D2 = 2;
static const uint8_t D3 = 3;
static const uint8_t D4 = 4;
static const uint8_t D5 = 5;
static const uint8_t D6 = 6;
static const uint8_t D8 = 8;
static const uint8_t D13 = 13;
static const uint8_t D9 = 9;
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 BOOT_BTN = 0;
static const uint8_t VBAT_VOLTAGE = 7;
static const uint8_t LDO2 = 47;
static const uint8_t STATUS_RGB = 35;
static const uint8_t RGB_STRIP = 36;
static const uint8_t INTERRUPT_PIN = 18;
static const uint8_t USER_BTN_1 = 14;
static const uint8_t USER_BTN_2 = 39;
static const uint8_t USER_BTN_3 = 40;
static const uint8_t AMP_DIN = 39;
static const uint8_t AMP_SD = 42;
static const uint8_t AMP_BCLK = 45;
static const uint8_t AMP_LRCLK = 48;
static const uint8_t MSBY = 15;
static const uint8_t TRRS_1 = 4;
static const uint8_t TRRS_2 = 2;
static const uint8_t TRRS_3 = 3;
#define PIN_RGB_LED STATUS_RGB
// BUILTIN_LED can be used in new Arduino API digitalWrite() like in Blink.ino
static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + PIN_RGB_LED;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API rgbLedWrite()
#define RGB_BUILTIN LED_BUILTIN
#define RGB_BRIGHTNESS 64
#endif /* Pins_Arduino_h */

View file

@ -0,0 +1,14 @@
// custom_ota_override.cpp
// This function overrides the weak definition of `verifyRollbackLater()` in the kode dot board.
extern "C" {
// Declare the weak function symbol to override it
bool verifyRollbackLater() __attribute__((weak));
}
// Custom implementation of verifyRollbackLater()
// Returning `true` prevents the OTA image from being automatically marked as valid.
// This ensures that the system will roll back to the previous image unless it is explicitly validated later.
bool verifyRollbackLater() {
return true;
}

View file

@ -0,0 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
otadata, data, ota, 0x10000, 0x2000,
ota_0, app, ota_0, 0x20000, 0x3E0000,
ota_1, app, ota_1, 0x400000, 0x800000,
storage, data, spiffs, 0xC00000, 0x400000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x6000
3 phy_init data phy 0xf000 0x1000
4 otadata data ota 0x10000 0x2000
5 ota_0 app ota_0 0x20000 0x3E0000
6 ota_1 app ota_1 0x400000 0x800000
7 storage data spiffs 0xC00000 0x400000

View file

@ -0,0 +1,107 @@
/*
KodeDot ESP32-S3R8 Variant
Pin definition file for the Arduino-ESP32 core
* External 2 × 10 connector simple aliases PIN1 PIN20
* On-board QSPI LCD 410×502 @40 MHz (SPI3_HOST)
* micro-SD on SPI2_HOST
* Dual-I²C: external (GPIO37/36) + internal-sensors (GPIO48/47)
* USB VID/PID 0x303A:0x1001
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include <stdbool.h>
/*──────────────── USB device descriptor ────────────────*/
#define USB_VID 0x303A // Espressif Systems VID
#define USB_PID 0x1001 // Product ID: KodeDot-S3
/*──────────────── UART0 (Arduino Serial) ────────────────*/
static const uint8_t TX = 43; // U0TXD PIN16 on the 2×10 header
static const uint8_t RX = 44; // U0RXD PIN18 on the 2×10 header
/*──────────────── I²C buses ─────────────────────────────*/
/* External expansion bus → header pins 11/13 */
static const uint8_t SCL = 37; // GPIO37 PIN12
static const uint8_t SDA = 36; // GPIO36 PIN14
/* Internal sensor/touch bus (not on header) */
#define INT_I2C_SCL 47 // GPIO47
#define INT_I2C_SDA 48 // GPIO48
/*──────────────── SPI2 micro-SD ───────────────────────*/
static const uint8_t SS = 15; // SD_CS
static const uint8_t MOSI = 16; // SD_MOSI
static const uint8_t MISO = 18; // SD_MISO
static const uint8_t SCK = 17; // SD_CLK
#define BOARD_HAS_SD_SPI
#define SD_CS SS
/*──────────────── QSPI LCD (SPI3_HOST) ─────────────────–
* Controller: ST7789 / 4-line SPI (no D/C pin)
* Resolution: 410×502 px, 16 bpp, RGB color-space
* Clock: 40 MHz
*/
#define BOARD_HAS_SPI_LCD
#define LCD_MODEL ST7789
#define LCD_WIDTH 410
#define LCD_HEIGHT 502
#define LCD_HOST SPI3_HOST
#define LCD_SCK 35 // GPIO35 • QSPI_CLK
#define LCD_MOSI 33 // GPIO33 • QSPI_IO0 (D0)
#define LCD_IO1 34 // GPIO34 • QSPI_IO1 (D1)
#define LCD_IO2 37 // GPIO37 • QSPI_IO2 (D2)
#define LCD_IO3 36 // GPIO36 • QSPI_IO3 (D3)
#define LCD_CS 10 // GPIO10
#define LCD_RST 9 // GPIO09
#define LCD_DC -1 // not used in 4-line SPI
/* Optional: back-light enable shares the NeoPixel pin */
#define LCD_BL 5 // GPIO05 (same as NEOPIXEL)
/*──────────────── Analog / Touch pads ────────────────*/
static const uint8_t A0 = 11; // PIN4 GPIO11 / TOUCH11 / ADC2_CH0
static const uint8_t A1 = 12; // PIN6 GPIO12 / TOUCH12 / ADC2_CH1
static const uint8_t A2 = 13; // PIN8 GPIO13 / TOUCH13 / ADC2_CH2
static const uint8_t A3 = 14; // PIN10 GPIO14 / TOUCH14 / ADC2_CH3
static const uint8_t T0 = A0, T1 = A1, T2 = A2, T3 = A3;
/*──────────────── On-board controls & indicator ─────────*/
#define BUTTON_TOP 0 // GPIO00 BOOT • active-LOW
#define BUTTON_BOTTOM 6 // GPIO06 • active-LOW
#define NEOPIXEL_PIN 5 // GPIO05 WS2812
#define LED_BUILTIN NEOPIXEL_PIN
/*──────────────── JTAG (also on connector) ──────────────*/
#define MTCK 39 // PIN11 GPIO39
#define MTDO 40 // PIN13 GPIO40
#define MTDI 41 // PIN15 GPIO41
#define MTMS 42 // PIN17 GPIO42
/*──────────────── 2×10 header: simple aliases ───────────
NOTE: power pins (1 = 5 V, 2 = 3 V3, 19/20 = GND) are **not**
exposed as GPIO numbers they remain undefined here. */
#define PIN3 1 // GPIO01 / TOUCH1 / ADC1_CH0
#define PIN4 11 // GPIO11 / TOUCH11 / ADC2_CH0
#define PIN5 2 // GPIO02 / TOUCH2 / ADC1_CH1
#define PIN6 12 // GPIO12 / TOUCH12 / ADC2_CH1
#define PIN7 3 // GPIO03 / TOUCH3 / ADC1_CH2
#define PIN8 13 // GPIO13 / TOUCH13 / ADC2_CH2
#define PIN9 4 // GPIO04 / TOUCH4 / ADC1_CH3
#define PIN10 14 // GPIO14 / TOUCH14 / ADC2_CH3
#define PIN11 39 // MTCK
#define PIN12 37 // SCL (external I²C)
#define PIN13 40 // MTDO
#define PIN14 36 // SDA (external I²C)
#define PIN15 41 // MTDI
#define PIN16 43 // TX (U0TXD)
#define PIN17 42 // MTMS
#define PIN18 44 // RX (U0RXD)
/* PIN1, PIN2, PIN19, PIN20 are power/ground and deliberately
left undefined they are **not** usable as GPIO. */
#endif /* Pins_Arduino_h */

View file

@ -0,0 +1,50 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
// Reference: RAK3112 Module Datasheet
// https://docs.rakwireless.com/product-categories/wisduo/rak3112-module/datasheet/
// Note:GPIO33,GPIO34,GPIO35.GPIO36,GPIO37 is not available in the 8MB and 16MB Octal PSRAM version
#define USB_VID 0x303a
#define USB_PID 0x1001
#define LED_GREEN 46
#define LED_BLUE 45
static const uint8_t LED_BUILTIN = LED_GREEN;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
static const uint8_t BAT_VOLT = 21;
static const uint8_t TX = 43;
static const uint8_t RX = 44;
static const uint8_t SDA = 9;
static const uint8_t SCL = 40;
#define WIRE1_PIN_DEFINED
static const uint8_t SDA1 = 17;
static const uint8_t SCL1 = 18;
static const uint8_t SS = 12;
static const uint8_t MOSI = 11;
static const uint8_t MISO = 10;
static const uint8_t SCK = 13;
#define LORA_ANT_SWITCH 4 // Antenna switch power control pin
#define LORA_SCK 5 // SX1262 SCK
#define LORA_MISO 3 // SX1262 MISO
#define LORA_MOSI 6 // SX1262 MOSI
#define LORA_CS 7 // SX1262 CS
#define LORA_RST 8 // SX1262 RST
#define LORA_DIO1 47 //SX1262 DIO1
#define LORA_BUSY 48
#define LORA_IRQ LORA_DIO1
#endif /* Pins_Arduino_h */

Binary file not shown.

View file

@ -0,0 +1,283 @@
#define DISPLAY_ENABLED
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <WiFiAP.h>
#include <Update.h>
#include <Wire.h>
#ifdef DISPLAY_ENABLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel rgb_led_1 = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
#endif
#include "esp_partition.h"
#include "esp_ota_ops.h"
#include "esp_system.h"
String ssid;
uint8_t mac[6];
// Create an instance of the server
WebServer server(80);
bool displayEnabled;
const int BUTTON_PIN = 0; // GPIO for the button
volatile unsigned long lastPressTime = 0; // Time of last button press
volatile bool doublePressDetected = false; // Flag for double press
const unsigned long doublePressInterval = 500; // Max. time (in ms) between two presses for double press
volatile int pressCount = 0; // Counts the button presses
const unsigned char epd_bitmap_wifi[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xff, 0x00, 0x00,
0x00, 0x3f, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x7c, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xf0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x78, 0x00,
0x03, 0xc0, 0x00, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x7f, 0xe0, 0x0e, 0x00,
0x0c, 0x01, 0xff, 0xf0, 0x06, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x02, 0x00, 0x00, 0x0f, 0x80, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x07, 0x80, 0x00, 0x00, 0x38, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x00, 0xc0, 0x00,
0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00,
0x00, 0x01, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x78, 0x00, 0x00, 0x00, 0x03, 0x80, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'checkmark', 44x44px
const unsigned char epd_bitmap_checkmark[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x00,
0x00, 0x0f, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x0f, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xc7, 0x80, 0x00, 0x00, 0x00, 0x03, 0xef, 0x00, 0x00, 0x00,
0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
void IRAM_ATTR handleButtonPress() {
unsigned long currentTime = millis(); // Get current time
// Debounce: If the current press is too close to the last one, ignore it
if (currentTime - lastPressTime > 50) {
pressCount++; // Count the button press
// Check if this is the second press within the double-press interval
if (pressCount == 2 && (currentTime - lastPressTime <= doublePressInterval)) {
doublePressDetected = true; // Double press detected
pressCount = 0; // Reset counter
}
lastPressTime = currentTime; // Update the time of the last press
}
}
// Function to switch the boot partition to OTA1
void setBootPartitionToOTA0() {
const esp_partition_t *ota0_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
if (ota0_partition) {
// Set OTA1 as new boot partition
esp_ota_set_boot_partition(ota0_partition);
Serial.println("Boot partition changed to OTA0. Restarting...");
// Restart to boot from the new partition
esp_restart();
} else {
Serial.println("OTA1 partition not found!");
}
}
void setupDisplay() {
displayEnabled = display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
if (displayEnabled) {
display.display();
delay(100);
display.clearDisplay();
}
}
void displayStatusBar(int progress) {
display.clearDisplay();
display.setCursor(24, 8);
display.println("Sketch wird");
display.setCursor(22, 22);
display.println("hochgeladen!");
display.fillRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, BLACK); // Clear status bar area
display.drawRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, WHITE); // Draw border
int filledWidth = (progress * SCREEN_WIDTH - 4) / 100; // Calculate progress width
display.fillRect(1, SCREEN_HEIGHT - 23, filledWidth - 4, 6, WHITE); // Fill progress bar
display.setCursor((SCREEN_WIDTH / 2) - 12, SCREEN_HEIGHT - 10);
display.setTextSize(1);
display.setTextColor(WHITE, BLACK);
display.print(progress);
display.println(" %");
display.display();
}
void displayWelcomeScreen() {
display.clearDisplay();
// Draw WiFi symbol
display.drawBitmap(0, 12, epd_bitmap_wifi, 44, 44, WHITE);
// Display SSID text
display.setCursor(40, 13);
display.setTextSize(1);
display.setTextColor(WHITE, BLACK);
display.println("Verbinde dich"); // "Connect"
display.setCursor(60, 27);
display.println("mit:"); // "with"
// Display SSID
display.setCursor(40, 43);
display.setTextSize(1); // Larger text for SSID
display.print(ssid);
display.display();
}
void displaySuccessScreen() {
display.clearDisplay();
// Draw WiFi symbol
display.drawBitmap(0, 12, epd_bitmap_checkmark, 44, 44, WHITE);
// Display SSID text
display.setCursor(48, 22);
display.setTextSize(1);
display.setTextColor(WHITE, BLACK);
display.println("Erfolgreich"); // "Successfully"
display.setCursor(48, 36);
display.println("hochgeladen!"); // "uploaded!"
display.display();
}
void wipeDisplay() {
display.clearDisplay();
display.println("");
display.display();
}
void setupWiFi() {
WiFi.macAddress(mac);
char macLastFour[5];
snprintf(macLastFour, sizeof(macLastFour), "%02X%02X", mac[4], mac[5]);
ssid = "senseBox:" + String(macLastFour);
// Define the IP address, gateway, and subnet mask
IPAddress local_IP(192, 168, 1, 1); // The new IP address
IPAddress gateway(192, 168, 1, 1); // Gateway address (can be the same as the AP's IP)
IPAddress subnet(255, 255, 255, 0); // Subnet mask
// Set the IP address, gateway, and subnet mask of the access point
WiFi.softAPConfig(local_IP, gateway, subnet);
// Start the access point
WiFi.softAP(ssid.c_str());
}
void setupOTA() {
// Handle updating process
server.on(
"/sketch", HTTP_POST,
[]() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
},
[]() {
HTTPUpload &upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.setDebugOutput(true);
size_t fsize = UPDATE_SIZE_UNKNOWN;
if (server.clientContentLength() > 0) {
fsize = server.clientContentLength();
}
Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(fsize)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
} else {
int progress = (Update.progress() * 100) / Update.size();
displayStatusBar(progress); // Update progress on status bar
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
displaySuccessScreen();
delay(3000);
wipeDisplay();
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
yield();
}
);
}
void setup() {
// Start Serial communication
Serial.begin(115200);
rgb_led_1.begin();
rgb_led_1.setBrightness(30);
rgb_led_1.setPixelColor(0, rgb_led_1.Color(51, 51, 255));
rgb_led_1.show();
// Configure button pin as input
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Interrupt for the button
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonPress, FALLING);
#ifdef DISPLAY_ENABLED
setupDisplay();
#endif
setupWiFi();
// Set the ESP32 as an access point
setupOTA();
server.begin();
}
void loop() {
// Handle client requests
server.handleClient();
#ifdef DISPLAY_ENABLED
displayWelcomeScreen();
#endif
if (doublePressDetected) {
Serial.println("Doppeldruck erkannt!"); // "Double press detected!"
setBootPartitionToOTA0();
#ifdef DISPLAY_ENABLED
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(WHITE, BLACK);
display.println("");
display.display();
delay(50);
#endif
// Restart to boot from the new partition
esp_restart();
}
}

View file

@ -1,29 +1,10 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Ha Thach (tinyusb.org) for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "esp32-hal-gpio.h" #include "esp32-hal-gpio.h"
#include "pins_arduino.h" #include "pins_arduino.h"
#include "esp_partition.h"
#include "esp_system.h"
#include "esp_ota_ops.h"
#include "esp_log.h"
#include <esp_chip_info.h>
extern "C" { extern "C" {
@ -41,12 +22,51 @@ void initVariant(void) {
pinMode(PIN_XB1_ENABLE, OUTPUT); pinMode(PIN_XB1_ENABLE, OUTPUT);
digitalWrite(PIN_XB1_ENABLE, LOW); digitalWrite(PIN_XB1_ENABLE, LOW);
//enable UART by default //enable UART only for chip without PSRAM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
if (chip_info.revision <= 0) {
pinMode(PIN_UART_ENABLE, OUTPUT); pinMode(PIN_UART_ENABLE, OUTPUT);
digitalWrite(PIN_UART_ENABLE, LOW); digitalWrite(PIN_UART_ENABLE, LOW);
}
//enable PD-Sensor by default //enable PD-Sensor by default
pinMode(PD_ENABLE, OUTPUT); pinMode(PD_ENABLE, OUTPUT);
digitalWrite(PD_ENABLE, HIGH); digitalWrite(PD_ENABLE, HIGH);
// define button pin
const int PIN_BUTTON = 0;
pinMode(PIN_BUTTON, INPUT_PULLUP);
// keep button pressed
unsigned long pressStartTime = 0;
bool buttonPressed = false;
// Wait 5 seconds for the button to be pressed
unsigned long startTime = millis();
// Check if button is pressed
while (millis() - startTime < 5000) {
if (digitalRead(PIN_BUTTON) == LOW) {
if (!buttonPressed) {
// The button was pressed
buttonPressed = true;
}
} else if (buttonPressed) {
// When the button is pressed and then released, boot into the OTA1 partition
const esp_partition_t *ota1_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
if (ota1_partition) {
esp_err_t err = esp_ota_set_boot_partition(ota1_partition);
if (err == ESP_OK) {
esp_restart(); // restart, to boot OTA1 partition
} else {
ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
}
}
// Abort after releasing the button
break;
}
}
} }
} }