Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fce9637

Browse files
authoredJan 17, 2024
Merge branch 'master' into feat_two_stage_ssltls_protocol_support
2 parents 9f88f19 + c0c687c commit fce9637

File tree

34 files changed

+2385
-206
lines changed

34 files changed

+2385
-206
lines changed
 

‎CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ set(CORE_SRCS
5050
cores/esp32/Esp.cpp
5151
cores/esp32/FunctionalInterrupt.cpp
5252
cores/esp32/HardwareSerial.cpp
53+
cores/esp32/HEXBuilder.cpp
5354
cores/esp32/IPAddress.cpp
5455
cores/esp32/libb64/cdecode.c
5556
cores/esp32/libb64/cencode.c
5657
cores/esp32/main.cpp
5758
cores/esp32/MD5Builder.cpp
5859
cores/esp32/Print.cpp
60+
cores/esp32/SHA1Builder.cpp
5961
cores/esp32/stdlib_noniso.c
6062
cores/esp32/Stream.cpp
6163
cores/esp32/StreamString.cpp

‎boards.txt

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17897,6 +17897,178 @@ heltec_wireless_stick_lite.menu.EraseFlash.all.upload.erase_cmd=-e
1789717897

1789817898
##############################################################
1789917899

17900+
heltec_wireless_tracker.name=Heltec Wireless Tracker
17901+
heltec_wireless_tracker.vid.0=0x303a
17902+
heltec_wireless_tracker.pid.0=0x1001
17903+
17904+
heltec_wireless_tracker.bootloader.tool=esptool_py
17905+
heltec_wireless_tracker.bootloader.tool.default=esptool_py
17906+
17907+
heltec_wireless_tracker.upload.tool=esptool_py
17908+
heltec_wireless_tracker.upload.tool.default=esptool_py
17909+
heltec_wireless_tracker.upload.tool.network=esp_ota
17910+
17911+
heltec_wireless_tracker.upload.maximum_size=3342336
17912+
heltec_wireless_tracker.upload.maximum_data_size=327680
17913+
heltec_wireless_tracker.upload.flags=
17914+
heltec_wireless_tracker.upload.extra_flags=
17915+
heltec_wireless_tracker.upload.use_1200bps_touch=false
17916+
heltec_wireless_tracker.upload.wait_for_upload_port=false
17917+
17918+
heltec_wireless_tracker.serial.disableDTR=false
17919+
heltec_wireless_tracker.serial.disableRTS=false
17920+
17921+
heltec_wireless_tracker.build.tarch=xtensa
17922+
heltec_wireless_tracker.build.bootloader_addr=0x0
17923+
heltec_wireless_tracker.build.target=esp32s3
17924+
heltec_wireless_tracker.build.mcu=esp32s3
17925+
heltec_wireless_tracker.build.core=esp32
17926+
heltec_wireless_tracker.build.variant=heltec_wireless_tracker
17927+
heltec_wireless_tracker.build.board=HELTEC_WIRELESS_TRACKER
17928+
17929+
heltec_wireless_tracker.build.usb_mode=1
17930+
heltec_wireless_tracker.build.cdc_on_boot=0
17931+
heltec_wireless_tracker.build.msc_on_boot=0
17932+
heltec_wireless_tracker.build.dfu_on_boot=0
17933+
heltec_wireless_tracker.build.f_cpu=240000000L
17934+
heltec_wireless_tracker.build.flash_size=8MB
17935+
heltec_wireless_tracker.build.flash_freq=80m
17936+
heltec_wireless_tracker.build.flash_mode=dio
17937+
heltec_wireless_tracker.build.boot=qio
17938+
heltec_wireless_tracker.build.boot_freq=80m
17939+
heltec_wireless_tracker.build.partitions=default_8MB
17940+
heltec_wireless_tracker.build.loop_core=
17941+
heltec_wireless_tracker.build.event_core=
17942+
heltec_wireless_tracker.build.psram_type=qspi
17943+
heltec_wireless_tracker.build.memory_type={build.boot}_{build.psram_type}
17944+
17945+
heltec_wireless_tracker.menu.LoopCore.1=Core 1
17946+
heltec_wireless_tracker.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1
17947+
heltec_wireless_tracker.menu.LoopCore.0=Core 0
17948+
heltec_wireless_tracker.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0
17949+
17950+
heltec_wireless_tracker.menu.EventsCore.1=Core 1
17951+
heltec_wireless_tracker.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
17952+
heltec_wireless_tracker.menu.EventsCore.0=Core 0
17953+
heltec_wireless_tracker.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0
17954+
17955+
heltec_wireless_tracker.menu.USBMode.hwcdc=Hardware CDC and JTAG
17956+
heltec_wireless_tracker.menu.USBMode.hwcdc.build.usb_mode=1
17957+
heltec_wireless_tracker.menu.USBMode.default=USB-OTG (TinyUSB)
17958+
heltec_wireless_tracker.menu.USBMode.default.build.usb_mode=0
17959+
17960+
heltec_wireless_tracker.menu.CDCOnBoot.default=Enabled
17961+
heltec_wireless_tracker.menu.CDCOnBoot.default.build.cdc_on_boot=1
17962+
heltec_wireless_tracker.menu.CDCOnBoot.cdc=Enabled
17963+
heltec_wireless_tracker.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
17964+
17965+
heltec_wireless_tracker.menu.MSCOnBoot.default=Disabled
17966+
heltec_wireless_tracker.menu.MSCOnBoot.default.build.msc_on_boot=0
17967+
heltec_wireless_tracker.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode)
17968+
heltec_wireless_tracker.menu.MSCOnBoot.msc.build.msc_on_boot=1
17969+
17970+
heltec_wireless_tracker.menu.DFUOnBoot.default=Disabled
17971+
heltec_wireless_tracker.menu.DFUOnBoot.default.build.dfu_on_boot=0
17972+
heltec_wireless_tracker.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode)
17973+
heltec_wireless_tracker.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
17974+
17975+
heltec_wireless_tracker.menu.UploadMode.default=UART0 / Hardware CDC
17976+
heltec_wireless_tracker.menu.UploadMode.default.upload.use_1200bps_touch=false
17977+
heltec_wireless_tracker.menu.UploadMode.default.upload.wait_for_upload_port=false
17978+
heltec_wireless_tracker.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
17979+
heltec_wireless_tracker.menu.UploadMode.cdc.upload.use_1200bps_touch=true
17980+
heltec_wireless_tracker.menu.UploadMode.cdc.upload.wait_for_upload_port=true
17981+
17982+
heltec_wireless_tracker.menu.CPUFreq.240=240MHz (WiFi)
17983+
heltec_wireless_tracker.menu.CPUFreq.240.build.f_cpu=240000000L
17984+
heltec_wireless_tracker.menu.CPUFreq.160=160MHz (WiFi)
17985+
heltec_wireless_tracker.menu.CPUFreq.160.build.f_cpu=160000000L
17986+
heltec_wireless_tracker.menu.CPUFreq.80=80MHz (WiFi)
17987+
heltec_wireless_tracker.menu.CPUFreq.80.build.f_cpu=80000000L
17988+
heltec_wireless_tracker.menu.CPUFreq.40=40MHz
17989+
heltec_wireless_tracker.menu.CPUFreq.40.build.f_cpu=40000000L
17990+
heltec_wireless_tracker.menu.CPUFreq.20=20MHz
17991+
heltec_wireless_tracker.menu.CPUFreq.20.build.f_cpu=20000000L
17992+
heltec_wireless_tracker.menu.CPUFreq.10=10MHz
17993+
heltec_wireless_tracker.menu.CPUFreq.10.build.f_cpu=10000000L
17994+
17995+
heltec_wireless_tracker.menu.UploadSpeed.921600=921600
17996+
heltec_wireless_tracker.menu.UploadSpeed.921600.upload.speed=921600
17997+
heltec_wireless_tracker.menu.UploadSpeed.115200=115200
17998+
heltec_wireless_tracker.menu.UploadSpeed.115200.upload.speed=115200
17999+
heltec_wireless_tracker.menu.UploadSpeed.256000.windows=256000
18000+
heltec_wireless_tracker.menu.UploadSpeed.256000.upload.speed=256000
18001+
heltec_wireless_tracker.menu.UploadSpeed.230400.windows.upload.speed=256000
18002+
heltec_wireless_tracker.menu.UploadSpeed.230400=230400
18003+
heltec_wireless_tracker.menu.UploadSpeed.230400.upload.speed=230400
18004+
heltec_wireless_tracker.menu.UploadSpeed.460800.linux=460800
18005+
heltec_wireless_tracker.menu.UploadSpeed.460800.macosx=460800
18006+
heltec_wireless_tracker.menu.UploadSpeed.460800.upload.speed=460800
18007+
heltec_wireless_tracker.menu.UploadSpeed.512000.windows=512000
18008+
heltec_wireless_tracker.menu.UploadSpeed.512000.upload.speed=512000
18009+
18010+
heltec_wireless_tracker.menu.DebugLevel.none=None
18011+
heltec_wireless_tracker.menu.DebugLevel.none.build.code_debug=0
18012+
heltec_wireless_tracker.menu.DebugLevel.error=Error
18013+
heltec_wireless_tracker.menu.DebugLevel.error.build.code_debug=1
18014+
heltec_wireless_tracker.menu.DebugLevel.warn=Warn
18015+
heltec_wireless_tracker.menu.DebugLevel.warn.build.code_debug=2
18016+
heltec_wireless_tracker.menu.DebugLevel.info=Info
18017+
heltec_wireless_tracker.menu.DebugLevel.info.build.code_debug=3
18018+
heltec_wireless_tracker.menu.DebugLevel.debug=Debug
18019+
heltec_wireless_tracker.menu.DebugLevel.debug.build.code_debug=4
18020+
heltec_wireless_tracker.menu.DebugLevel.verbose=Verbose
18021+
heltec_wireless_tracker.menu.DebugLevel.verbose.build.code_debug=5
18022+
18023+
heltec_wireless_tracker.menu.LORAWAN_REGION.0=REGION_EU868
18024+
heltec_wireless_tracker.menu.LORAWAN_REGION.0.build.band=REGION_EU868
18025+
heltec_wireless_tracker.menu.LORAWAN_REGION.1=REGION_EU433
18026+
heltec_wireless_tracker.menu.LORAWAN_REGION.1.build.band=REGION_EU433
18027+
heltec_wireless_tracker.menu.LORAWAN_REGION.2=REGION_CN470
18028+
heltec_wireless_tracker.menu.LORAWAN_REGION.2.build.band=REGION_CN470
18029+
heltec_wireless_tracker.menu.LORAWAN_REGION.3=REGION_US915
18030+
heltec_wireless_tracker.menu.LORAWAN_REGION.3.build.band=REGION_US915
18031+
heltec_wireless_tracker.menu.LORAWAN_REGION.4=REGION_AU915
18032+
heltec_wireless_tracker.menu.LORAWAN_REGION.4.build.band=REGION_AU915
18033+
heltec_wireless_tracker.menu.LORAWAN_REGION.5=REGION_CN779
18034+
heltec_wireless_tracker.menu.LORAWAN_REGION.5.build.band=REGION_CN779
18035+
heltec_wireless_tracker.menu.LORAWAN_REGION.6=REGION_AS923
18036+
heltec_wireless_tracker.menu.LORAWAN_REGION.6.build.band=REGION_AS923
18037+
heltec_wireless_tracker.menu.LORAWAN_REGION.7=REGION_KR920
18038+
heltec_wireless_tracker.menu.LORAWAN_REGION.7.build.band=REGION_KR920
18039+
heltec_wireless_tracker.menu.LORAWAN_REGION.8=REGION_IN865
18040+
heltec_wireless_tracker.menu.LORAWAN_REGION.8.build.band=REGION_IN865
18041+
heltec_wireless_tracker.menu.LORAWAN_REGION.9=REGION_US915_HYBRID
18042+
heltec_wireless_tracker.menu.LORAWAN_REGION.9.build.band=REGION_US915_HYBRID
18043+
18044+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.0=None
18045+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.0.build.LoRaWanDebugLevel=0
18046+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.1=Freq
18047+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.1.build.LoRaWanDebugLevel=1
18048+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.2=Freq && DIO
18049+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.2.build.LoRaWanDebugLevel=2
18050+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.3=Freq && DIO && PW
18051+
heltec_wireless_tracker.menu.LoRaWanDebugLevel.3.build.LoRaWanDebugLevel=3
18052+
18053+
heltec_wireless_tracker.menu.LORAWAN_DEVEUI.0=CUSTOM
18054+
heltec_wireless_tracker.menu.LORAWAN_DEVEUI.0.build.LORAWAN_DEVEUI_AUTO=0
18055+
heltec_wireless_tracker.menu.LORAWAN_DEVEUI.1=Generate By ChipID
18056+
heltec_wireless_tracker.menu.LORAWAN_DEVEUI.1.build.LORAWAN_DEVEUI_AUTO=1
18057+
18058+
heltec_wireless_tracker.menu.LORAWAN_PREAMBLE_LENGTH.0=8(default)
18059+
heltec_wireless_tracker.menu.LORAWAN_PREAMBLE_LENGTH.0.build.LORAWAN_PREAMBLE_LENGTH=8
18060+
heltec_wireless_tracker.menu.LORAWAN_PREAMBLE_LENGTH.1=16(For M00 and M00L)
18061+
heltec_wireless_tracker.menu.LORAWAN_PREAMBLE_LENGTH.1.build.LORAWAN_PREAMBLE_LENGTH=16
18062+
18063+
heltec_wireless_tracker.build.defines=-D{build.band} -DLoRaWAN_DEBUG_LEVEL={build.LoRaWanDebugLevel} -DACTIVE_REGION=LORAMAC_{build.band} -DLORAWAN_PREAMBLE_LENGTH={build.LORAWAN_PREAMBLE_LENGTH} -DLORAWAN_DEVEUI_AUTO={build.LORAWAN_DEVEUI_AUTO} -D{build.board}
18064+
18065+
heltec_wireless_tracker.menu.EraseFlash.none=Disabled
18066+
heltec_wireless_tracker.menu.EraseFlash.none.upload.erase_cmd=
18067+
heltec_wireless_tracker.menu.EraseFlash.all=Enabled
18068+
heltec_wireless_tracker.menu.EraseFlash.all.upload.erase_cmd=-e
18069+
18070+
##############################################################
18071+
1790018072
espectro32.name=ESPectro32
1790118073

1790218074
espectro32.bootloader.tool=esptool_py
@@ -29743,3 +29915,119 @@ nano_nora.menu.USBMode.hwcdc.build.openocdscript=esp32s3-builtin.cfg
2974329915
nano_nora.menu.USBMode.hwcdc.build.debugconfig=esp32s3-arduino.json
2974429916

2974529917
##############################################################
29918+
29919+
makergo_c3_supermini.name=MakerGO ESP32 C3 SuperMini
29920+
makergo_c3_supermini.vid.0=0x303a
29921+
makergo_c3_supermini.pid.0=0x1001
29922+
29923+
makergo_c3_supermini.bootloader.tool=esptool_py
29924+
makergo_c3_supermini.bootloader.tool.default=esptool_py
29925+
29926+
makergo_c3_supermini.upload.tool=esptool_py
29927+
makergo_c3_supermini.upload.tool.default=esptool_py
29928+
makergo_c3_supermini.upload.tool.network=esp_ota
29929+
29930+
makergo_c3_supermini.upload.maximum_size=1310720
29931+
makergo_c3_supermini.upload.maximum_data_size=327680
29932+
makergo_c3_supermini.upload.flags=
29933+
makergo_c3_supermini.upload.extra_flags=
29934+
makergo_c3_supermini.upload.use_1200bps_touch=false
29935+
makergo_c3_supermini.upload.wait_for_upload_port=false
29936+
29937+
makergo_c3_supermini.serial.disableDTR=true
29938+
makergo_c3_supermini.serial.disableRTS=true
29939+
29940+
makergo_c3_supermini.build.tarch=riscv32
29941+
makergo_c3_supermini.build.target=esp
29942+
makergo_c3_supermini.build.mcu=esp32c3
29943+
makergo_c3_supermini.build.core=esp32
29944+
makergo_c3_supermini.build.variant=makergo_c3_supermini
29945+
makergo_c3_supermini.build.board=MAKERGO_C3_SUPERMINI
29946+
makergo_c3_supermini.build.bootloader_addr=0x0
29947+
29948+
makergo_c3_supermini.build.cdc_on_boot=1
29949+
makergo_c3_supermini.build.f_cpu=160000000L
29950+
makergo_c3_supermini.build.flash_size=4MB
29951+
makergo_c3_supermini.build.flash_freq=80m
29952+
makergo_c3_supermini.build.flash_mode=dio
29953+
makergo_c3_supermini.build.boot=qio
29954+
makergo_c3_supermini.build.partitions=default
29955+
makergo_c3_supermini.build.defines=
29956+
29957+
makergo_c3_supermini.menu.CDCOnBoot.default=Enabled
29958+
makergo_c3_supermini.menu.CDCOnBoot.default.build.cdc_on_boot=1
29959+
makergo_c3_supermini.menu.CDCOnBoot.dis_cdc=Disabled
29960+
makergo_c3_supermini.menu.CDCOnBoot.dis_cdc.build.cdc_on_boot=0
29961+
29962+
makergo_c3_supermini.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
29963+
makergo_c3_supermini.menu.PartitionScheme.default.build.partitions=default
29964+
makergo_c3_supermini.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
29965+
makergo_c3_supermini.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
29966+
makergo_c3_supermini.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
29967+
makergo_c3_supermini.menu.PartitionScheme.no_ota.build.partitions=no_ota
29968+
makergo_c3_supermini.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
29969+
makergo_c3_supermini.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
29970+
makergo_c3_supermini.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
29971+
makergo_c3_supermini.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
29972+
makergo_c3_supermini.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
29973+
makergo_c3_supermini.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
29974+
makergo_c3_supermini.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
29975+
makergo_c3_supermini.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
29976+
makergo_c3_supermini.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
29977+
makergo_c3_supermini.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
29978+
makergo_c3_supermini.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
29979+
makergo_c3_supermini.menu.PartitionScheme.huge_app.build.partitions=huge_app
29980+
makergo_c3_supermini.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
29981+
29982+
29983+
makergo_c3_supermini.menu.CPUFreq.160=160MHz (WiFi)
29984+
makergo_c3_supermini.menu.CPUFreq.160.build.f_cpu=160000000L
29985+
makergo_c3_supermini.menu.CPUFreq.80=80MHz (WiFi)
29986+
makergo_c3_supermini.menu.CPUFreq.80.build.f_cpu=80000000L
29987+
makergo_c3_supermini.menu.CPUFreq.40=40MHz
29988+
makergo_c3_supermini.menu.CPUFreq.40.build.f_cpu=40000000L
29989+
makergo_c3_supermini.menu.CPUFreq.20=20MHz
29990+
makergo_c3_supermini.menu.CPUFreq.20.build.f_cpu=20000000L
29991+
makergo_c3_supermini.menu.CPUFreq.10=10MHz
29992+
makergo_c3_supermini.menu.CPUFreq.10.build.f_cpu=10000000L
29993+
29994+
29995+
makergo_c3_supermini.menu.FlashFreq.80=80MHz
29996+
makergo_c3_supermini.menu.FlashFreq.80.build.flash_freq=80m
29997+
makergo_c3_supermini.menu.FlashFreq.40=40MHz
29998+
makergo_c3_supermini.menu.FlashFreq.40.build.flash_freq=40m
29999+
30000+
makergo_c3_supermini.menu.UploadSpeed.921600=921600
30001+
makergo_c3_supermini.menu.UploadSpeed.921600.upload.speed=921600
30002+
makergo_c3_supermini.menu.UploadSpeed.115200=115200
30003+
makergo_c3_supermini.menu.UploadSpeed.115200.upload.speed=115200
30004+
makergo_c3_supermini.menu.UploadSpeed.256000.windows=256000
30005+
makergo_c3_supermini.menu.UploadSpeed.256000.upload.speed=256000
30006+
makergo_c3_supermini.menu.UploadSpeed.230400.windows.upload.speed=256000
30007+
makergo_c3_supermini.menu.UploadSpeed.230400=230400
30008+
makergo_c3_supermini.menu.UploadSpeed.230400.upload.speed=230400
30009+
makergo_c3_supermini.menu.UploadSpeed.460800.linux=460800
30010+
makergo_c3_supermini.menu.UploadSpeed.460800.macosx=460800
30011+
makergo_c3_supermini.menu.UploadSpeed.460800.upload.speed=460800
30012+
makergo_c3_supermini.menu.UploadSpeed.512000.windows=512000
30013+
makergo_c3_supermini.menu.UploadSpeed.512000.upload.speed=512000
30014+
30015+
makergo_c3_supermini.menu.DebugLevel.none=None
30016+
makergo_c3_supermini.menu.DebugLevel.none.build.code_debug=0
30017+
makergo_c3_supermini.menu.DebugLevel.error=Error
30018+
makergo_c3_supermini.menu.DebugLevel.error.build.code_debug=1
30019+
makergo_c3_supermini.menu.DebugLevel.warn=Warn
30020+
makergo_c3_supermini.menu.DebugLevel.warn.build.code_debug=2
30021+
makergo_c3_supermini.menu.DebugLevel.info=Info
30022+
makergo_c3_supermini.menu.DebugLevel.info.build.code_debug=3
30023+
makergo_c3_supermini.menu.DebugLevel.debug=Debug
30024+
makergo_c3_supermini.menu.DebugLevel.debug.build.code_debug=4
30025+
makergo_c3_supermini.menu.DebugLevel.verbose=Verbose
30026+
makergo_c3_supermini.menu.DebugLevel.verbose.build.code_debug=5
30027+
30028+
makergo_c3_supermini.menu.EraseFlash.none=Disabled
30029+
makergo_c3_supermini.menu.EraseFlash.none.upload.erase_cmd=
30030+
makergo_c3_supermini.menu.EraseFlash.all=Enabled
30031+
makergo_c3_supermini.menu.EraseFlash.all.upload.erase_cmd=-e
30032+
30033+
##############################################################

‎cores/esp32/HEXBuilder.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
3+
This file is part of the esp32 core for Arduino environment.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include <Arduino.h>
21+
#include <HEXBuilder.h>
22+
23+
static uint8_t hex_char_to_byte(uint8_t c)
24+
{
25+
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
26+
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
27+
(c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0x10; // unknown char is 16
28+
}
29+
30+
size_t HEXBuilder::hex2bytes(unsigned char * out, size_t maxlen, String &in) {
31+
return hex2bytes(out, maxlen, in.c_str());
32+
}
33+
34+
size_t HEXBuilder::hex2bytes(unsigned char * out, size_t maxlen, const char * in) {
35+
size_t len = 0;
36+
for(;*in;in++) {
37+
uint8_t c = hex_char_to_byte(*in);
38+
// Silently skip anything unknown.
39+
if (c > 15)
40+
continue;
41+
42+
if (len & 1) {
43+
if (len/2 < maxlen)
44+
out[len/2] |= c;
45+
} else {
46+
if (len/2 < maxlen)
47+
out[len/2] = c<<4;
48+
}
49+
len++;
50+
}
51+
return (len + 1)/2;
52+
}
53+
54+
size_t HEXBuilder::bytes2hex(char * out, size_t maxlen, const unsigned char * in, size_t len) {
55+
for(size_t i = 0; i < len; i++) {
56+
if (i*2 + 1 < maxlen) {
57+
sprintf(out + (i * 2), "%02x", in[i]);
58+
}
59+
}
60+
return len * 2 + 1;
61+
}
62+
63+
String HEXBuilder::bytes2hex(const unsigned char * in, size_t len) {
64+
size_t maxlen = len * 2 + 1;
65+
char * out = (char *) malloc(maxlen);
66+
if (!out) return String();
67+
bytes2hex(out, maxlen, in, len);
68+
String ret = String(out);
69+
free(out);
70+
return ret;
71+
}

‎cores/esp32/HEXBuilder.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
3+
This file is part of the esp32 core for Arduino environment.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef HEXBuilder_h
21+
#define HEXBuilder_h
22+
23+
#include <WString.h>
24+
#include <Stream.h>
25+
26+
class HEXBuilder {
27+
public:
28+
static size_t hex2bytes(unsigned char * out, size_t maxlen, String & in);
29+
static size_t hex2bytes(unsigned char * out, size_t maxlen, const char * in);
30+
31+
static String bytes2hex(const unsigned char * in, size_t len);
32+
static size_t bytes2hex(char * out, size_t maxlen, const unsigned char * in, size_t len);
33+
};
34+
#endif

‎cores/esp32/HardwareSerial.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ _eventTask(NULL)
114114

115115
HardwareSerial::~HardwareSerial()
116116
{
117-
end(true); // explicit Full UART termination
117+
end(); // explicit Full UART termination
118118
#if !CONFIG_DISABLE_HAL_LOCKS
119119
if(_lock != NULL){
120120
vSemaphoreDelete(_lock);
@@ -329,16 +329,22 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
329329
// map logical pins to GPIO numbers
330330
rxPin = digitalPinToGPIONumber(rxPin);
331331
txPin = digitalPinToGPIONumber(txPin);
332+
// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
333+
// it will detach previous UART attached pins
332334

333-
if(_uart) {
334-
// in this case it is a begin() over a previous begin() - maybe to change baud rate
335-
// thus do not disable debug output
336-
end(false); // disables IDF UART driver and UART event Task + sets _uart to NULL
335+
// indicates that uartbegin() has to initilize a new IDF driver
336+
if (_testUartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd)) {
337+
_destroyEventTask(); // when IDF uart driver must be restarted, _eventTask must finish too
337338
}
338339

339340
// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
340341
// it will detach previous UART attached pins
341342
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd);
343+
if (_uart == NULL) {
344+
log_e("UART driver failed to start. Please check the logs.");
345+
HSERIAL_MUTEX_UNLOCK();
346+
return;
347+
}
342348
if (!baud) {
343349
// using baud rate as zero, forces it to try to detect the current baud rate in place
344350
uartStartDetectBaudrate(_uart);
@@ -348,11 +354,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
348354
yield();
349355
}
350356

351-
end(false); // disables IDF UART driver and UART event Task + sets _uart to NULL
352-
353357
if(detectedBaudRate) {
354358
delay(100); // Give some time...
355359
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd);
360+
if (_uart == NULL) {
361+
log_e("UART driver failed to start. Please check the logs.");
362+
HSERIAL_MUTEX_UNLOCK();
363+
return;
364+
}
356365
} else {
357366
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
358367
_uart = NULL;
@@ -389,22 +398,17 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
389398
uartSetBaudRate(_uart, baud);
390399
}
391400

392-
void HardwareSerial::end(bool fullyTerminate)
401+
void HardwareSerial::end()
393402
{
394403
// default Serial.end() will completely disable HardwareSerial,
395404
// including any tasks or debug message channel (log_x()) - but not for IDF log messages!
396-
if(fullyTerminate) {
397-
_onReceiveCB = NULL;
398-
_onReceiveErrorCB = NULL;
399-
if (uartGetDebug() == _uart_nr) {
400-
uartSetDebug(0);
401-
}
402-
_rxFIFOFull = 0;
403-
uartEnd(_uart_nr); // fully detach all pins and delete the UART driver
404-
} else {
405-
// do not invalidate callbacks, detach pins, invalidate DBG output
406-
uart_driver_delete(_uart_nr);
405+
_onReceiveCB = NULL;
406+
_onReceiveErrorCB = NULL;
407+
if (uartGetDebug() == _uart_nr) {
408+
uartSetDebug(0);
407409
}
410+
_rxFIFOFull = 0;
411+
uartEnd(_uart_nr); // fully detach all pins and delete the UART driver
408412
_destroyEventTask(); // when IDF uart driver is deleted, _eventTask must finish too
409413
_uart = NULL;
410414
}
@@ -564,3 +568,4 @@ size_t HardwareSerial::setTxBufferSize(size_t new_size) {
564568
_txBufferSize = new_size;
565569
return _txBufferSize;
566570
}
571+

‎cores/esp32/HardwareSerial.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class HardwareSerial: public Stream
252252
// invert will invert RX/TX polarity
253253
// rxfifo_full_thrhd if the UART Flow Control Threshold in the UART FIFO (max 127)
254254
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
255-
void end(bool fullyTerminate = true);
255+
void end(void);
256256
void updateBaudRate(unsigned long baud);
257257
int available(void);
258258
int availableForWrite(void);

‎cores/esp32/HashBuilder.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef HashBuilder_h
16+
#define HashBuilder_h
17+
18+
#include <WString.h>
19+
#include <Stream.h>
20+
21+
#include "HEXBuilder.h"
22+
23+
class HashBuilder : public HEXBuilder
24+
{
25+
public:
26+
virtual ~HashBuilder() {}
27+
virtual void begin() = 0;
28+
29+
virtual void add(uint8_t* data, size_t len) = 0;
30+
virtual void add(const char* data)
31+
{
32+
add((uint8_t*)data, strlen(data));
33+
}
34+
virtual void add(char* data)
35+
{
36+
add((const char*)data);
37+
}
38+
virtual void add(String data)
39+
{
40+
add(data.c_str());
41+
}
42+
43+
virtual void addHexString(const char* data) = 0;
44+
virtual void addHexString(char* data)
45+
{
46+
addHexString((const char*)data);
47+
}
48+
virtual void addHexString(String data)
49+
{
50+
addHexString(data.c_str());
51+
}
52+
53+
virtual bool addStream(Stream& stream, const size_t maxLen) = 0;
54+
virtual void calculate() = 0;
55+
virtual void getBytes(uint8_t* output) = 0;
56+
virtual void getChars(char* output) = 0;
57+
virtual String toString() = 0;
58+
};
59+
60+
#endif

‎cores/esp32/MD5Builder.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,30 @@
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1818
*/
19+
1920
#include <Arduino.h>
21+
#include <HEXBuilder.h>
2022
#include <MD5Builder.h>
2123

22-
static uint8_t hex_char_to_byte(uint8_t c)
23-
{
24-
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) :
25-
(c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) :
26-
(c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0;
27-
}
28-
2924
void MD5Builder::begin(void)
3025
{
3126
memset(_buf, 0x00, ESP_ROM_MD5_DIGEST_LEN);
3227
esp_rom_md5_init(&_ctx);
3328
}
3429

35-
void MD5Builder::add(uint8_t * data, uint16_t len)
30+
void MD5Builder::add(uint8_t * data, size_t len)
3631
{
3732
esp_rom_md5_update(&_ctx, data, len);
3833
}
3934

4035
void MD5Builder::addHexString(const char * data)
4136
{
42-
uint16_t i, len = strlen(data);
37+
size_t len = strlen(data);
4338
uint8_t * tmp = (uint8_t*)malloc(len/2);
4439
if(tmp == NULL) {
4540
return;
4641
}
47-
for(i=0; i<len; i+=2) {
48-
uint8_t high = hex_char_to_byte(data[i]);
49-
uint8_t low = hex_char_to_byte(data[i+1]);
50-
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F);
51-
}
42+
hex2bytes(tmp, len/2, data);
5243
add(tmp, len/2);
5344
free(tmp);
5445
}
@@ -105,9 +96,7 @@ void MD5Builder::getBytes(uint8_t * output)
10596

10697
void MD5Builder::getChars(char * output)
10798
{
108-
for(uint8_t i = 0; i < ESP_ROM_MD5_DIGEST_LEN; i++) {
109-
sprintf(output + (i * 2), "%02x", _buf[i]);
110-
}
99+
bytes2hex(output, ESP_ROM_MD5_DIGEST_LEN*2+1, _buf, ESP_ROM_MD5_DIGEST_LEN);
111100
}
112101

113102
String MD5Builder::toString(void)

‎cores/esp32/MD5Builder.h

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/*
1+
/*
22
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
3-
This file is part of the esp8266 core for Arduino environment.
4-
3+
This file is part of the esp32 core for Arduino environment.
4+
55
This library is free software; you can redistribute it and/or
66
modify it under the terms of the GNU Lesser General Public
77
License as published by the Free Software Foundation; either
@@ -15,51 +15,39 @@
1515
You should have received a copy of the GNU Lesser General Public
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Modified 10 Jan 2024 by Lucas Saavedra Vaz (Use abstract class HashBuilder)
1820
*/
19-
#ifndef __ESP8266_MD5_BUILDER__
20-
#define __ESP8266_MD5_BUILDER__
21+
#ifndef MD5Builder_h
22+
#define MD5Builder_h
2123

2224
#include <WString.h>
2325
#include <Stream.h>
2426

2527
#include "esp_system.h"
2628
#include "esp_rom_md5.h"
2729

28-
class MD5Builder
30+
#include "HashBuilder.h"
31+
32+
class MD5Builder : public HashBuilder
2933
{
3034
private:
3135
md5_context_t _ctx;
3236
uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN];
3337
public:
34-
void begin(void);
35-
void add(uint8_t * data, uint16_t len);
36-
void add(const char * data)
37-
{
38-
add((uint8_t*)data, strlen(data));
39-
}
40-
void add(char * data)
41-
{
42-
add((const char*)data);
43-
}
44-
void add(String data)
45-
{
46-
add(data.c_str());
47-
}
48-
void addHexString(const char * data);
49-
void addHexString(char * data)
50-
{
51-
addHexString((const char*)data);
52-
}
53-
void addHexString(String data)
54-
{
55-
addHexString(data.c_str());
56-
}
57-
bool addStream(Stream & stream, const size_t maxLen);
58-
void calculate(void);
59-
void getBytes(uint8_t * output);
60-
void getChars(char * output);
61-
String toString(void);
62-
};
38+
void begin(void) override;
6339

40+
using HashBuilder::add;
41+
void add(uint8_t * data, size_t len) override;
42+
43+
using HashBuilder::addHexString;
44+
void addHexString(const char * data) override;
45+
46+
bool addStream(Stream & stream, const size_t maxLen) override;
47+
void calculate(void) override;
48+
void getBytes(uint8_t * output) override;
49+
void getChars(char * output) override;
50+
String toString(void) override;
51+
};
6452

6553
#endif

‎cores/esp32/SHA1Builder.cpp

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
/*
2+
* FIPS-180-1 compliant SHA-1 implementation
3+
*
4+
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5+
* SPDX-License-Identifier: Apache-2.0
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
8+
* not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
* This file is part of mbed TLS (https://tls.mbed.org)
20+
* Modified for esp32 by Lucas Saavedra Vaz on 11 Jan 2024
21+
*/
22+
23+
#include <Arduino.h>
24+
#include <SHA1Builder.h>
25+
26+
// 32-bit integer manipulation macros (big endian)
27+
28+
#ifndef GET_UINT32_BE
29+
#define GET_UINT32_BE(n,b,i) \
30+
{ \
31+
(n) = ((uint32_t) (b)[(i) ] << 24) \
32+
| ((uint32_t) (b)[(i) + 1] << 16) \
33+
| ((uint32_t) (b)[(i) + 2] << 8) \
34+
| ((uint32_t) (b)[(i) + 3] ); \
35+
}
36+
#endif
37+
38+
#ifndef PUT_UINT32_BE
39+
#define PUT_UINT32_BE(n,b,i) \
40+
{ \
41+
(b)[(i) ] = (uint8_t) ((n) >> 24); \
42+
(b)[(i) + 1] = (uint8_t) ((n) >> 16); \
43+
(b)[(i) + 2] = (uint8_t) ((n) >> 8); \
44+
(b)[(i) + 3] = (uint8_t) ((n) ); \
45+
}
46+
#endif
47+
48+
// Constants
49+
50+
static const uint8_t sha1_padding[64] =
51+
{
52+
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
56+
};
57+
58+
// Private methods
59+
60+
void SHA1Builder::process(const uint8_t* data)
61+
{
62+
uint32_t temp, W[16], A, B, C, D, E;
63+
64+
GET_UINT32_BE(W[ 0], data, 0);
65+
GET_UINT32_BE(W[ 1], data, 4);
66+
GET_UINT32_BE(W[ 2], data, 8);
67+
GET_UINT32_BE(W[ 3], data, 12);
68+
GET_UINT32_BE(W[ 4], data, 16);
69+
GET_UINT32_BE(W[ 5], data, 20);
70+
GET_UINT32_BE(W[ 6], data, 24);
71+
GET_UINT32_BE(W[ 7], data, 28);
72+
GET_UINT32_BE(W[ 8], data, 32);
73+
GET_UINT32_BE(W[ 9], data, 36);
74+
GET_UINT32_BE(W[10], data, 40);
75+
GET_UINT32_BE(W[11], data, 44);
76+
GET_UINT32_BE(W[12], data, 48);
77+
GET_UINT32_BE(W[13], data, 52);
78+
GET_UINT32_BE(W[14], data, 56);
79+
GET_UINT32_BE(W[15], data, 60);
80+
81+
#define sha1_S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
82+
83+
#define sha1_R(t) \
84+
( \
85+
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
86+
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
87+
(W[t & 0x0F] = sha1_S(temp,1)) \
88+
)
89+
90+
#define sha1_P(a,b,c,d,e,x) \
91+
{ \
92+
e += sha1_S(a,5) + sha1_F(b,c,d) + sha1_K + x; b = sha1_S(b,30); \
93+
}
94+
95+
A = state[0];
96+
B = state[1];
97+
C = state[2];
98+
D = state[3];
99+
E = state[4];
100+
101+
#define sha1_F(x,y,z) (z ^ (x & (y ^ z)))
102+
#define sha1_K 0x5A827999
103+
104+
sha1_P(A, B, C, D, E, W[0]);
105+
sha1_P(E, A, B, C, D, W[1]);
106+
sha1_P(D, E, A, B, C, W[2]);
107+
sha1_P(C, D, E, A, B, W[3]);
108+
sha1_P(B, C, D, E, A, W[4]);
109+
sha1_P(A, B, C, D, E, W[5]);
110+
sha1_P(E, A, B, C, D, W[6]);
111+
sha1_P(D, E, A, B, C, W[7]);
112+
sha1_P(C, D, E, A, B, W[8]);
113+
sha1_P(B, C, D, E, A, W[9]);
114+
sha1_P(A, B, C, D, E, W[10]);
115+
sha1_P(E, A, B, C, D, W[11]);
116+
sha1_P(D, E, A, B, C, W[12]);
117+
sha1_P(C, D, E, A, B, W[13]);
118+
sha1_P(B, C, D, E, A, W[14]);
119+
sha1_P(A, B, C, D, E, W[15]);
120+
sha1_P(E, A, B, C, D, sha1_R(16));
121+
sha1_P(D, E, A, B, C, sha1_R(17));
122+
sha1_P(C, D, E, A, B, sha1_R(18));
123+
sha1_P(B, C, D, E, A, sha1_R(19));
124+
125+
#undef sha1_K
126+
#undef sha1_F
127+
128+
#define sha1_F(x,y,z) (x ^ y ^ z)
129+
#define sha1_K 0x6ED9EBA1
130+
131+
sha1_P(A, B, C, D, E, sha1_R(20));
132+
sha1_P(E, A, B, C, D, sha1_R(21));
133+
sha1_P(D, E, A, B, C, sha1_R(22));
134+
sha1_P(C, D, E, A, B, sha1_R(23));
135+
sha1_P(B, C, D, E, A, sha1_R(24));
136+
sha1_P(A, B, C, D, E, sha1_R(25));
137+
sha1_P(E, A, B, C, D, sha1_R(26));
138+
sha1_P(D, E, A, B, C, sha1_R(27));
139+
sha1_P(C, D, E, A, B, sha1_R(28));
140+
sha1_P(B, C, D, E, A, sha1_R(29));
141+
sha1_P(A, B, C, D, E, sha1_R(30));
142+
sha1_P(E, A, B, C, D, sha1_R(31));
143+
sha1_P(D, E, A, B, C, sha1_R(32));
144+
sha1_P(C, D, E, A, B, sha1_R(33));
145+
sha1_P(B, C, D, E, A, sha1_R(34));
146+
sha1_P(A, B, C, D, E, sha1_R(35));
147+
sha1_P(E, A, B, C, D, sha1_R(36));
148+
sha1_P(D, E, A, B, C, sha1_R(37));
149+
sha1_P(C, D, E, A, B, sha1_R(38));
150+
sha1_P(B, C, D, E, A, sha1_R(39));
151+
152+
#undef sha1_K
153+
#undef sha1_F
154+
155+
#define sha1_F(x,y,z) ((x & y) | (z & (x | y)))
156+
#define sha1_K 0x8F1BBCDC
157+
158+
sha1_P(A, B, C, D, E, sha1_R(40));
159+
sha1_P(E, A, B, C, D, sha1_R(41));
160+
sha1_P(D, E, A, B, C, sha1_R(42));
161+
sha1_P(C, D, E, A, B, sha1_R(43));
162+
sha1_P(B, C, D, E, A, sha1_R(44));
163+
sha1_P(A, B, C, D, E, sha1_R(45));
164+
sha1_P(E, A, B, C, D, sha1_R(46));
165+
sha1_P(D, E, A, B, C, sha1_R(47));
166+
sha1_P(C, D, E, A, B, sha1_R(48));
167+
sha1_P(B, C, D, E, A, sha1_R(49));
168+
sha1_P(A, B, C, D, E, sha1_R(50));
169+
sha1_P(E, A, B, C, D, sha1_R(51));
170+
sha1_P(D, E, A, B, C, sha1_R(52));
171+
sha1_P(C, D, E, A, B, sha1_R(53));
172+
sha1_P(B, C, D, E, A, sha1_R(54));
173+
sha1_P(A, B, C, D, E, sha1_R(55));
174+
sha1_P(E, A, B, C, D, sha1_R(56));
175+
sha1_P(D, E, A, B, C, sha1_R(57));
176+
sha1_P(C, D, E, A, B, sha1_R(58));
177+
sha1_P(B, C, D, E, A, sha1_R(59));
178+
179+
#undef sha1_K
180+
#undef sha1_F
181+
182+
#define sha1_F(x,y,z) (x ^ y ^ z)
183+
#define sha1_K 0xCA62C1D6
184+
185+
sha1_P(A, B, C, D, E, sha1_R(60));
186+
sha1_P(E, A, B, C, D, sha1_R(61));
187+
sha1_P(D, E, A, B, C, sha1_R(62));
188+
sha1_P(C, D, E, A, B, sha1_R(63));
189+
sha1_P(B, C, D, E, A, sha1_R(64));
190+
sha1_P(A, B, C, D, E, sha1_R(65));
191+
sha1_P(E, A, B, C, D, sha1_R(66));
192+
sha1_P(D, E, A, B, C, sha1_R(67));
193+
sha1_P(C, D, E, A, B, sha1_R(68));
194+
sha1_P(B, C, D, E, A, sha1_R(69));
195+
sha1_P(A, B, C, D, E, sha1_R(70));
196+
sha1_P(E, A, B, C, D, sha1_R(71));
197+
sha1_P(D, E, A, B, C, sha1_R(72));
198+
sha1_P(C, D, E, A, B, sha1_R(73));
199+
sha1_P(B, C, D, E, A, sha1_R(74));
200+
sha1_P(A, B, C, D, E, sha1_R(75));
201+
sha1_P(E, A, B, C, D, sha1_R(76));
202+
sha1_P(D, E, A, B, C, sha1_R(77));
203+
sha1_P(C, D, E, A, B, sha1_R(78));
204+
sha1_P(B, C, D, E, A, sha1_R(79));
205+
206+
#undef sha1_K
207+
#undef sha1_F
208+
209+
state[0] += A;
210+
state[1] += B;
211+
state[2] += C;
212+
state[3] += D;
213+
state[4] += E;
214+
}
215+
216+
// Public methods
217+
218+
void SHA1Builder::begin(void)
219+
{
220+
total[0] = 0;
221+
total[1] = 0;
222+
223+
state[0] = 0x67452301;
224+
state[1] = 0xEFCDAB89;
225+
state[2] = 0x98BADCFE;
226+
state[3] = 0x10325476;
227+
state[4] = 0xC3D2E1F0;
228+
229+
memset(buffer, 0x00, sizeof(buffer));
230+
memset(hash, 0x00, sizeof(hash));
231+
}
232+
233+
void SHA1Builder::add(uint8_t* data, size_t len)
234+
{
235+
size_t fill;
236+
uint32_t left;
237+
238+
if(len == 0)
239+
{
240+
return;
241+
}
242+
243+
left = total[0] & 0x3F;
244+
fill = 64 - left;
245+
246+
total[0] += (uint32_t) len;
247+
total[0] &= 0xFFFFFFFF;
248+
249+
if(total[0] < (uint32_t) len)
250+
{
251+
total[1]++;
252+
}
253+
254+
if(left && len >= fill)
255+
{
256+
memcpy((void *) (buffer + left), data, fill);
257+
process(buffer);
258+
data += fill;
259+
len -= fill;
260+
left = 0;
261+
}
262+
263+
while(len >= 64)
264+
{
265+
process(data);
266+
data += 64;
267+
len -= 64;
268+
}
269+
270+
if(len > 0) {
271+
memcpy((void *) (buffer + left), data, len);
272+
}
273+
}
274+
275+
void SHA1Builder::addHexString(const char * data)
276+
{
277+
uint16_t len = strlen(data);
278+
uint8_t * tmp = (uint8_t*)malloc(len/2);
279+
if(tmp == NULL) {
280+
return;
281+
}
282+
hex2bytes(tmp, len/2, data);
283+
add(tmp, len/2);
284+
free(tmp);
285+
}
286+
287+
bool SHA1Builder::addStream(Stream & stream, const size_t maxLen)
288+
{
289+
const int buf_size = 512;
290+
int maxLengthLeft = maxLen;
291+
uint8_t * buf = (uint8_t*) malloc(buf_size);
292+
293+
if(!buf) {
294+
return false;
295+
}
296+
297+
int bytesAvailable = stream.available();
298+
while((bytesAvailable > 0) && (maxLengthLeft > 0)) {
299+
300+
// determine number of bytes to read
301+
int readBytes = bytesAvailable;
302+
if(readBytes > maxLengthLeft) {
303+
readBytes = maxLengthLeft ; // read only until max_len
304+
}
305+
if(readBytes > buf_size) {
306+
readBytes = buf_size; // not read more the buffer can handle
307+
}
308+
309+
// read data and check if we got something
310+
int numBytesRead = stream.readBytes(buf, readBytes);
311+
if(numBytesRead< 1) {
312+
free(buf);
313+
return false;
314+
}
315+
316+
// Update SHA1 with buffer payload
317+
add(buf, numBytesRead);
318+
319+
// update available number of bytes
320+
maxLengthLeft -= numBytesRead;
321+
bytesAvailable = stream.available();
322+
}
323+
free(buf);
324+
return true;
325+
}
326+
327+
void SHA1Builder::calculate(void)
328+
{
329+
uint32_t last, padn;
330+
uint32_t high, low;
331+
uint8_t msglen[8];
332+
333+
high = (total[0] >> 29) | (total[1] << 3);
334+
low = (total[0] << 3);
335+
336+
PUT_UINT32_BE(high, msglen, 0);
337+
PUT_UINT32_BE(low, msglen, 4);
338+
339+
last = total[0] & 0x3F;
340+
padn = (last < 56) ? (56 - last) : (120 - last);
341+
342+
add((uint8_t*)sha1_padding, padn);
343+
add(msglen, 8);
344+
345+
PUT_UINT32_BE(state[0], hash, 0);
346+
PUT_UINT32_BE(state[1], hash, 4);
347+
PUT_UINT32_BE(state[2], hash, 8);
348+
PUT_UINT32_BE(state[3], hash, 12);
349+
PUT_UINT32_BE(state[4], hash, 16);
350+
}
351+
352+
void SHA1Builder::getBytes(uint8_t * output)
353+
{
354+
memcpy(output, hash, SHA1_HASH_SIZE);
355+
}
356+
357+
void SHA1Builder::getChars(char * output)
358+
{
359+
bytes2hex(output, SHA1_HASH_SIZE*2+1, hash, SHA1_HASH_SIZE);
360+
}
361+
362+
String SHA1Builder::toString(void)
363+
{
364+
char out[(SHA1_HASH_SIZE * 2) + 1];
365+
getChars(out);
366+
return String(out);
367+
}

‎cores/esp32/SHA1Builder.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef SHA1Builder_h
16+
#define SHA1Builder_h
17+
18+
#include <WString.h>
19+
#include <Stream.h>
20+
21+
#include "HashBuilder.h"
22+
23+
#define SHA1_HASH_SIZE 20
24+
25+
class SHA1Builder : public HashBuilder
26+
{
27+
private:
28+
uint32_t total[2]; /* number of bytes processed */
29+
uint32_t state[5]; /* intermediate digest state */
30+
unsigned char buffer[64]; /* data block being processed */
31+
uint8_t hash[SHA1_HASH_SIZE]; /* SHA-1 result */
32+
33+
void process(const uint8_t* data);
34+
35+
public:
36+
void begin() override;
37+
38+
using HashBuilder::add;
39+
void add(uint8_t* data, size_t len) override;
40+
41+
using HashBuilder::addHexString;
42+
void addHexString(const char* data) override;
43+
44+
bool addStream(Stream& stream, const size_t maxLen) override;
45+
void calculate() override;
46+
void getBytes(uint8_t* output) override;
47+
void getChars(char* output) override;
48+
String toString() override;
49+
};
50+
51+
#endif

‎cores/esp32/esp32-hal-uart.c

Lines changed: 148 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD
1+
// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -33,19 +33,25 @@
3333
#include "hal/gpio_hal.h"
3434
#include "esp_rom_gpio.h"
3535

36-
static int s_uart_debug_nr = 0;
36+
static int s_uart_debug_nr = 0; // UART number for debug output
3737

3838
struct uart_struct_t {
3939

4040
#if !CONFIG_DISABLE_HAL_LOCKS
41-
SemaphoreHandle_t lock;
41+
SemaphoreHandle_t lock; // UART lock
4242
#endif
4343

44-
uint8_t num;
45-
bool has_peek;
46-
uint8_t peek_byte;
47-
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
48-
int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs
44+
uint8_t num; // UART number for IDF driver API
45+
bool has_peek; // flag to indicate that there is a peek byte pending to be read
46+
uint8_t peek_byte; // peek byte that has been read but not consumed
47+
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
48+
// configuration data:: Arduino API tipical data
49+
int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs
50+
uint32_t _baudrate, _config; // UART baudrate and config
51+
// UART ESP32 specific data
52+
uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes
53+
bool _inverted; // UART inverted signal
54+
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
4955
};
5056

5157
#if CONFIG_DISABLE_HAL_LOCKS
@@ -54,12 +60,12 @@ struct uart_struct_t {
5460
#define UART_MUTEX_UNLOCK()
5561

5662
static uart_t _uart_bus_array[] = {
57-
{0, false, 0, NULL, -1, -1, -1, -1},
63+
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
5864
#if SOC_UART_NUM > 1
59-
{1, false, 0, NULL, -1, -1, -1, -1},
65+
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
6066
#endif
6167
#if SOC_UART_NUM > 2
62-
{2, false, 0, NULL, -1, -1, -1, -1},
68+
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
6369
#endif
6470
};
6571

@@ -69,12 +75,12 @@ static uart_t _uart_bus_array[] = {
6975
#define UART_MUTEX_UNLOCK() if(uart->lock != NULL) xSemaphoreGive(uart->lock)
7076

7177
static uart_t _uart_bus_array[] = {
72-
{NULL, 0, false, 0, NULL, -1, -1, -1, -1},
78+
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7379
#if SOC_UART_NUM > 1
74-
{NULL, 1, false, 0, NULL, -1, -1, -1, -1},
80+
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7581
#endif
7682
#if SOC_UART_NUM > 2
77-
{NULL, 2, false, 0, NULL, -1, -1, -1, -1},
83+
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7884
#endif
7985
};
8086

@@ -97,7 +103,12 @@ static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
97103
// detaches pins and sets Peripheral Manager and UART information
98104
if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) {
99105
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO);
100-
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
106+
// avoids causing BREAK in the UART line
107+
if (uart->_inverted) {
108+
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
109+
} else {
110+
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_HIGH, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
111+
}
101112
uart->_rxPin = -1; // -1 means unassigned/detached
102113
if (!perimanClearPinBus(rxPin)) {
103114
retCode = false;
@@ -355,28 +366,121 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr
355366
return retCode;
356367
}
357368

358-
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd)
369+
// This helper function will return true if a new IDF UART driver needs to be restarted and false if the current one can continue its execution
370+
bool _testUartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd)
359371
{
360372
if(uart_nr >= SOC_UART_NUM) {
361-
return NULL;
373+
return false; // no new driver has to be installed
362374
}
363375
uart_t* uart = &_uart_bus_array[uart_nr];
364-
376+
// verify if is necessary to restart the UART driver
365377
if (uart_is_driver_installed(uart_nr)) {
366-
uartEnd(uart_nr);
378+
// some parameters can't be changed unless we end the UART driver
379+
if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) {
380+
return true; // the current IDF UART driver must be terminated and a new driver shall be installed
381+
} else {
382+
return false; // The current IDF UART driver can continue its execution
383+
}
384+
} else {
385+
return true; // no IDF UART driver is running and a new driver shall be installed
367386
}
387+
}
388+
389+
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd)
390+
{
391+
if(uart_nr >= SOC_UART_NUM) {
392+
log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
393+
return NULL; // no new driver was installed
394+
}
395+
uart_t* uart = &_uart_bus_array[uart_nr];
396+
log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin);
368397

369398
#if !CONFIG_DISABLE_HAL_LOCKS
370399
if(uart->lock == NULL) {
371400
uart->lock = xSemaphoreCreateMutex();
372401
if(uart->lock == NULL) {
373402
log_e("HAL LOCK error.");
374-
return NULL;
403+
return NULL; // no new driver was installed
375404
}
376405
}
377406
#endif
378-
UART_MUTEX_LOCK();
379407

408+
if (uart_is_driver_installed(uart_nr)) {
409+
log_v("UART%d Driver already installed.", uart_nr);
410+
// some parameters can't be changed unless we end the UART driver
411+
if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) {
412+
log_v("UART%d changing buffer sizes or inverted signal or rxfifo_full_thrhd. IDF driver will be restarted", uart_nr);
413+
uartEnd(uart_nr);
414+
} else {
415+
bool retCode = true;
416+
UART_MUTEX_LOCK();
417+
//User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins
418+
if (uart->_baudrate != baudrate) {
419+
if (ESP_OK != uart_set_baudrate(uart_nr, baudrate)) {
420+
log_e("UART%d changing baudrate failed.", uart_nr);
421+
retCode = false;
422+
} else {
423+
log_v("UART%d changed baudrate to %d", uart_nr, baudrate);
424+
uart->_baudrate = baudrate;
425+
}
426+
}
427+
uart_word_length_t data_bits = (config & 0xc) >> 2;
428+
uart_parity_t parity = config & 0x3;
429+
uart_stop_bits_t stop_bits = (config & 0x30) >> 4;
430+
if (retCode && (uart->_config & 0xc) >> 2 != data_bits) {
431+
if (ESP_OK != uart_set_word_length(uart_nr, data_bits)) {
432+
log_e("UART%d changing data length failed.", uart_nr);
433+
retCode = false;
434+
} else {
435+
log_v("UART%d changed data length to %d", uart_nr, data_bits + 5);
436+
}
437+
}
438+
if (retCode && (uart->_config & 0x3) != parity) {
439+
if (ESP_OK != uart_set_parity(uart_nr, parity)) {
440+
log_e("UART%d changing parity failed.", uart_nr);
441+
retCode = false;
442+
} else {
443+
log_v("UART%d changed parity to %s", uart_nr, parity == 0 ? "NONE" : parity == 2 ? "EVEN" : "ODD");
444+
}
445+
}
446+
if (retCode && (uart->_config & 0xc30) >> 4 != stop_bits) {
447+
if (ESP_OK != uart_set_stop_bits(uart_nr, stop_bits)) {
448+
log_e("UART%d changing stop bits failed.", uart_nr);
449+
retCode = false;
450+
} else {
451+
log_v("UART%d changed stop bits to %d", uart_nr, stop_bits == 3 ? 2 : 1);
452+
}
453+
}
454+
if (retCode) uart->_config = config;
455+
if (retCode && rxPin > 0 && uart->_rxPin != rxPin) {
456+
retCode &= _uartDetachPins(uart_nr, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
457+
retCode &= _uartAttachPins(uart_nr, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
458+
if (!retCode) {
459+
log_e("UART%d changing RX pin failed.", uart_nr);
460+
} else {
461+
log_v("UART%d changed RX pin to %d", uart_nr, rxPin);
462+
}
463+
}
464+
if (retCode && txPin > 0 && uart->_txPin != txPin) {
465+
retCode &= _uartDetachPins(uart_nr, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
466+
retCode &= _uartAttachPins(uart_nr, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
467+
if (!retCode) {
468+
log_e("UART%d changing TX pin failed.", uart_nr);
469+
} else {
470+
log_v("UART%d changed TX pin to %d", uart_nr, txPin);
471+
}
472+
}
473+
UART_MUTEX_UNLOCK();
474+
if (retCode) {
475+
// UART driver was already working, just return the uart_t structure, syaing that no new driver was installed
476+
return uart;
477+
}
478+
// if we reach this point, it means that we need to restart the UART driver
479+
uartEnd(uart_nr);
480+
}
481+
} else {
482+
log_v("UART%d not installed. Starting installation", uart_nr);
483+
}
380484
uart_config_t uart_config;
381485
uart_config.data_bits = (config & 0xc) >> 2;
382486
uart_config.parity = (config & 0x3);
@@ -386,7 +490,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
386490
uart_config.baud_rate = baudrate;
387491
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6
388492
uart_config.source_clk = UART_SCLK_DEFAULT;
493+
494+
UART_MUTEX_LOCK();
389495
bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0);
496+
390497
if (retCode) retCode &= ESP_OK == uart_param_config(uart_nr, &uart_config);
391498

392499
// Is it right or the idea is to swap rx and tx pins?
@@ -395,19 +502,31 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
395502
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV);
396503
}
397504

505+
if (retCode) {
506+
uart->_baudrate = baudrate;
507+
uart->_config = config;
508+
uart->_inverted = inverted;
509+
uart->_rxfifo_full_thrhd = rxfifo_full_thrhd;
510+
uart->_rx_buffer_size = rx_buffer_size;
511+
uart->_tx_buffer_size = tx_buffer_size;
512+
uart->_ctsPin = -1;
513+
uart->_rtsPin = -1;
514+
uart->has_peek = false;
515+
uart->peek_byte = 0;
516+
}
398517
UART_MUTEX_UNLOCK();
518+
399519
// uartSetPins detaches previous pins if new ones are used over a previous begin()
400520
if (retCode) retCode &= uartSetPins(uart_nr, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
401-
402-
if (retCode) uartFlush(uart);
403-
else {
521+
if (!retCode) {
404522
uartEnd(uart_nr);
405523
uart = NULL;
406524
log_e("UART%d initialization error.", uart->num);
525+
} else {
526+
uartFlush(uart);
527+
log_v("UART%d initialization done.", uart->num);
407528
}
408-
409-
log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin);
410-
return uart;
529+
return uart; // a new driver was installed
411530
}
412531

413532
// This function code is under testing - for now just keep it here
@@ -658,6 +777,7 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
658777
if(uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq) == ESP_OK){
659778
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate, sclk_freq);
660779
}
780+
uart->_baudrate = baud_rate;
661781
UART_MUTEX_UNLOCK();
662782
}
663783

@@ -1025,3 +1145,4 @@ int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize)
10251145
}
10261146

10271147
#endif /* SOC_UART_SUPPORTED */
1148+

‎cores/esp32/esp32-hal-uart.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extern "C" {
3232
struct uart_struct_t;
3333
typedef struct uart_struct_t uart_t;
3434

35+
bool _testUartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd);
3536
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd);
3637
void uartEnd(uint8_t uart_num);
3738

‎docs/en/api/preferences.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,45 @@ Arduino-esp32 Preferences API
177177

178178
**Note**
179179
* A message providing the reason for a failed call is sent to the arduino-esp32 ``log_e`` facility.
180+
181+
182+
``isKey``
183+
*************
184+
185+
Check if a key-value pair from the currently open namespace exists.
186+
187+
.. code-block:: arduino
188+
189+
bool isKey(const char * key)
190+
..
191+
192+
**Parameters**
193+
* ``key`` (Required)
194+
- the name of the key to be checked.
195+
196+
**Returns**
197+
* ``true`` if key-value pair exists; ``false`` otherwise.
198+
199+
**Note**
200+
* Attempting to check a key without a namespace being open will return false.
201+
202+
203+
``getType``
204+
*************
205+
206+
Returns the type of a key-value pair from the currently open namespace.
207+
208+
.. code-block:: arduino
209+
210+
PreferenceType getType(const char * key)
211+
..
212+
213+
**Parameters**
214+
* ``key`` (Required)
215+
- the name of the key to be checked.
216+
217+
**Returns**
218+
* PreferenceType element contaning the type of the key-value pair or PT_INVALID on error.
180219

181220

182221
``putChar, putUChar``

‎docs/en/esp-idf_component.rst

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,17 @@ After the setup you can save and exit:
7373
- Close confirmation window [Enter] or [Space] or [Esc]
7474
- Quit [Q]
7575

76-
Option 1. Using Arduino setup() and loop()
77-
******************************************
76+
As the Arduino libraries use C++ features, you will need to swap some file extensions from ``.c`` to ``.cpp``:
7877

7978
- In main folder rename file `main.c` to `main.cpp`.
79+
- In main folder open file `CMakeLists.txt` and change `main.c` to `main.cpp` as described below.
8080

81-
- In main folder open file `CMakeList.txt` and change `main.c` to `main.cpp` as described below.
81+
Option 1. Using Arduino setup() and loop()
82+
******************************************
8283

83-
- Your main.cpp should be formatted like any other sketch.
84+
Your main.cpp should be formatted like any other sketch. Don't forget to include ``Arduino.h``.
8485

85-
.. code-block:: c
86+
.. code-block:: cpp
8687
8788
//file: main.cpp
8889
#include "Arduino.h"
@@ -102,14 +103,14 @@ Option 1. Using Arduino setup() and loop()
102103
Option 2. Using ESP-IDF appmain()
103104
*********************************
104105

105-
In main.c or main.cpp you need to implement ``app_main()`` and call ``initArduino();`` in it.
106+
In main.cpp you need to implement ``app_main()`` and call ``initArduino();`` in it.
106107

107108
Keep in mind that setup() and loop() will not be called in this case.
108109
Furthermore the ``app_main()`` is single execution as a normal function so if you need an infinite loop as in Arduino place it there.
109110

110111
.. code-block:: cpp
111112
112-
//file: main.c or main.cpp
113+
//file: main.cpp
113114
#include "Arduino.h"
114115
115116
extern "C" void app_main()
@@ -141,7 +142,7 @@ Build, flash and monitor
141142

142143
- After a successful flash, you may need to press the RST button again
143144

144-
- To terminate the serial monitor press [Ctrl] + [ ] ]
145+
- To terminate the serial monitor press ``Ctrl`` + ``]``
145146

146147
Logging To Serial
147148
-----------------
@@ -179,7 +180,7 @@ Download the library:
179180

180181
.. code-block:: bash
181182
182-
cd ~/esp/esp-idf/components/arduino-esp32/
183+
cd ~/esp/esp-idf/components/arduino/
183184
git clone --recursive git@github.com:Author/new_library.git libraries/new_library
184185
185186
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <HEXBuilder.h>
2+
3+
void setup() {
4+
Serial.begin(115200);
5+
while (!Serial) { delay(10); }
6+
Serial.println("\n\n\nStart.");
7+
8+
// Convert a HEX string like 6c6c6f20576f726c64 to a binary buffer
9+
{
10+
const char * out = "Hello World";
11+
const char * hexin = "48656c6c6f20576f726c6400"; // As the string above is \0 terminated too
12+
13+
unsigned char buff[256];
14+
size_t len = HEXBuilder::hex2bytes(buff, sizeof(buff), hexin);
15+
16+
if (len != 1 + strlen(out))
17+
Serial.println("Odd - length 1 is wrong");
18+
19+
if (memcmp(buff, out, len) != 0)
20+
Serial.println("Odd - decode 1 went wrong");
21+
22+
// Safe to print this binary buffer -- as we've included a \0 in the hex sequence.
23+
Serial.printf("IN: <%s>\nOUT <%s\\0>\n", hexin, buff);
24+
};
25+
26+
{
27+
String helloHEX = "48656c6c6f20576f726c64";
28+
const char hello[] = "Hello World";
29+
30+
unsigned char buff[256];
31+
size_t len = HEXBuilder::hex2bytes(buff, sizeof(buff), helloHEX);
32+
33+
if (len != strlen(hello))
34+
Serial.println("Odd - length 2 is wrong");
35+
36+
if (strcmp((char *) buff, hello) != 0)
37+
Serial.println("Odd - decode 2 went wrong");
38+
}
39+
40+
{
41+
const unsigned char helloBytes[] = { 0x48, 0x56, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 };
42+
String helloHEX = "48566c6c6f20576f726c64";
43+
44+
45+
String out = HEXBuilder::bytes2hex(helloBytes, sizeof(helloBytes));
46+
if (out.length() != 2 * sizeof(helloBytes))
47+
Serial.println("Odd - length 3 is wrong");
48+
49+
// we need to ignore case - as a hex string can be spelled in uppercase and lowercase
50+
if (!out.equalsIgnoreCase(helloHEX)) {
51+
Serial.println("Odd - decode 3 went wrong");
52+
}
53+
}
54+
55+
{
56+
const unsigned char helloBytes[] = { 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 };
57+
const char helloHex[] = "6c6c6f20576f726c64";
58+
59+
char buff[256];
60+
size_t len = HEXBuilder::bytes2hex(buff, sizeof(buff), helloBytes, sizeof(helloBytes));
61+
if (len != 1 + 2 * sizeof(helloBytes))
62+
Serial.println("Odd - length 4 is wrong");
63+
64+
// we need to ignore case - as a hex string can be spelled in uppercase and lowercase
65+
if (strcasecmp(buff, helloHex))
66+
Serial.println("Odd - decode 4 went wrong");
67+
}
68+
Serial.println("Done.");
69+
}
70+
71+
void loop() {}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include <MD5Builder.h>
2+
3+
// Occasionally it is useful to compare a password that the user
4+
// has entered to a build in string. However this means that the
5+
// password ends up `in the clear' in the firmware and in your
6+
// source code.
7+
//
8+
// MD5Builder helps you obfuscate this (it is not terribly secure, MD5
9+
// has been phased out as insecure eons ago) by letting you create an
10+
// MD5 of the data the user entered; and then compare this to an MD5
11+
// string that you have put in your code.
12+
13+
void setup() {
14+
Serial.begin(115200);
15+
while (!Serial) { delay(10); }
16+
Serial.println("\n\n\nStart.");
17+
18+
// Check if a password obfuscated in an MD5 actually
19+
// matches the original string.
20+
//
21+
// echo -n "Hello World" | openssl md5
22+
{
23+
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
24+
String password = "Hello World";
25+
26+
MD5Builder md;
27+
28+
md.begin();
29+
md.add(password);
30+
md.calculate();
31+
32+
String result = md.toString();
33+
34+
if (!md5.equalsIgnoreCase(result))
35+
Serial.println("Odd - failing MD5 on String");
36+
else
37+
Serial.println("OK!");
38+
}
39+
40+
// Check that this also work if we add the password not as
41+
// a normal string - but as a string with the HEX values.
42+
{
43+
String passwordAsHex = "48656c6c6f20576f726c64";
44+
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
45+
46+
MD5Builder md;
47+
48+
md.begin();
49+
md.addHexString(passwordAsHex);
50+
md.calculate();
51+
52+
String result = md.toString();
53+
54+
if (!md5.equalsIgnoreCase(result)) {
55+
Serial.println("Odd - failing MD5 on hex string");
56+
Serial.println(md5);
57+
Serial.println(result);
58+
}
59+
else
60+
Serial.println("OK!");
61+
62+
}
63+
64+
// Check that this also work if we add the password as
65+
// an unsigned byte array.
66+
{
67+
uint8_t password[] = { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 };
68+
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
69+
MD5Builder md;
70+
71+
md.begin();
72+
md.add(password, sizeof(password));
73+
md.calculate();
74+
75+
String result = md.toString();
76+
77+
if (!md5.equalsIgnoreCase(result))
78+
Serial.println("Odd - failing MD5 on byte array");
79+
else
80+
Serial.println("OK!");
81+
82+
// And also check that we can compare this as pure, raw, bytes
83+
uint8_t raw[16] = { 0xb1, 0x0a, 0x8d, 0xb1, 0x64, 0xe0, 0x75, 0x41,
84+
0x05, 0xb7, 0xa9, 0x9b, 0xe7, 0x2e, 0x3f, 0xe5
85+
};
86+
uint8_t res[16];
87+
md.getBytes(res);
88+
if (memcmp(raw, res, 16))
89+
Serial.println("Odd - failing MD5 on byte array when compared as bytes");
90+
else
91+
Serial.println("OK!");
92+
93+
}
94+
}
95+
96+
void loop() {}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include <SHA1Builder.h>
2+
3+
// Occasionally it is useful to compare a password that the user
4+
// has entered to a build in string. However this means that the
5+
// password ends up `in the clear' in the firmware and in your
6+
// source code.
7+
//
8+
// SHA1Builder helps you obfuscate this (This is not much more secure.
9+
// SHA1 is past its retirement age and long obsolte/insecure, but it helps
10+
// a little) by letting you create an (unsalted!) SHA1 of the data the
11+
// user entered; and then compare this to an SHA1 string that you have put
12+
// in your code.
13+
14+
void setup() {
15+
Serial.begin(115200);
16+
while (!Serial) { delay(10); }
17+
Serial.println("\n\n\nStart.");
18+
19+
// Check if a password obfuscated in an SHA1 actually
20+
// matches the original string.
21+
//
22+
// echo -n "Hello World" | openssl sha1
23+
{
24+
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
25+
String password = "Hello World";
26+
27+
SHA1Builder sha;
28+
29+
sha.begin();
30+
sha.add(password);
31+
sha.calculate();
32+
33+
String result = sha.toString();
34+
35+
if (!sha1_str.equalsIgnoreCase(result))
36+
Serial.println("Odd - failing SHA1 on String");
37+
else
38+
Serial.println("OK!");
39+
}
40+
41+
// Check that this also work if we add the password not as
42+
// a normal string - but as a string with the HEX values.
43+
{
44+
String passwordAsHex = "48656c6c6f20576f726c64";
45+
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
46+
47+
SHA1Builder sha;
48+
49+
sha.begin();
50+
sha.addHexString(passwordAsHex);
51+
sha.calculate();
52+
53+
String result = sha.toString();
54+
55+
if (!sha1_str.equalsIgnoreCase(result)) {
56+
Serial.println("Odd - failing SHA1 on hex string");
57+
Serial.println(sha1_str);
58+
Serial.println(result);
59+
}
60+
else
61+
Serial.println("OK!");
62+
63+
}
64+
65+
// Check that this also work if we add the password as
66+
// an unsigned byte array.
67+
{
68+
uint8_t password[] = { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 };
69+
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
70+
SHA1Builder sha;
71+
72+
sha.begin();
73+
sha.add(password, sizeof(password));
74+
sha.calculate();
75+
76+
String result = sha.toString();
77+
78+
if (!sha1_str.equalsIgnoreCase(result))
79+
Serial.println("Odd - failing SHA1 on byte array");
80+
else
81+
Serial.println("OK!");
82+
83+
// And also check that we can compare this as pure, raw, bytes
84+
uint8_t raw[20] = { 0x0a, 0x4d, 0x55, 0xa8, 0xd7, 0x78, 0xe5, 0x02, 0x2f, 0xab,
85+
0x70, 0x19, 0x77, 0xc5, 0xd8, 0x40, 0xbb, 0xc4, 0x86, 0xd0
86+
};
87+
uint8_t res[20];
88+
sha.getBytes(res);
89+
if (memcmp(raw, res, 20))
90+
Serial.println("Odd - failing SHA1 on byte array when compared as bytes");
91+
else
92+
Serial.println("OK!");
93+
94+
}
95+
}
96+
97+
void loop() {}

‎libraries/WebServer/examples/HttpAuthCallback/.skip.esp32h2

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <WiFi.h>
2+
#include <ESPmDNS.h>
3+
#include <ArduinoOTA.h>
4+
#include <WebServer.h>
5+
6+
const char* ssid = "........";
7+
const char* password = "........";
8+
9+
WebServer server(80);
10+
11+
typedef struct credentials_t {
12+
String username;
13+
String password;
14+
} credentials_t;
15+
16+
credentials_t passwdfile[] = {
17+
{ "admin", "esp32" },
18+
{ "fred", "41234123" },
19+
{ "charlie", "sdfsd" },
20+
{ "alice", "vambdnkuhj" },
21+
{ "bob", "svcdbjhws12" },
22+
};
23+
const size_t N_CREDENTIALS = sizeof(passwdfile) / sizeof(credentials_t);
24+
25+
String * credentialsHandler(HTTPAuthMethod mode, String username, String params[])
26+
{
27+
for (int i = 0; i < N_CREDENTIALS; i++) {
28+
if (username == passwdfile[i].username)
29+
return new String(passwdfile[i].password);
30+
}
31+
return NULL;
32+
}
33+
34+
void setup() {
35+
Serial.begin(115200);
36+
while (!Serial) { delay(10); }
37+
WiFi.mode(WIFI_STA);
38+
WiFi.begin(ssid, password);
39+
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
40+
Serial.println("WiFi Connect Failed! Rebooting...");
41+
delay(1000);
42+
ESP.restart();
43+
}
44+
ArduinoOTA.begin();
45+
46+
server.on("/", []() {
47+
if (!server.authenticate(&credentialsHandler)) {
48+
server.requestAuthentication();
49+
return;
50+
}
51+
server.send(200, "text/plain", "Login OK");
52+
});
53+
server.begin();
54+
55+
Serial.print("Open http://");
56+
Serial.print(WiFi.localIP());
57+
Serial.println("/ in your browser to see it working");
58+
}
59+
60+
void loop() {
61+
ArduinoOTA.handle();
62+
server.handleClient();
63+
delay(2);//allow the cpu to switch to other tasks
64+
}

‎libraries/WebServer/examples/HttpAuthCallbackInline/.skip.esp32h2

Whitespace-only changes.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <WiFi.h>
2+
#include <ESPmDNS.h>
3+
#include <ArduinoOTA.h>
4+
#include <WebServer.h>
5+
6+
const char* ssid = "........";
7+
const char* password = "........";
8+
9+
WebServer server(80);
10+
11+
typedef struct credentials_t {
12+
char * username;
13+
char * password;
14+
} credentials_t;
15+
16+
credentials_t passwdfile[] = {
17+
{ "admin", "esp32" },
18+
{ "fred", "41234123" },
19+
{ "charlie", "sdfsd" },
20+
{ "alice", "vambdnkuhj" },
21+
{ "bob", "svcdbjhws12" },
22+
{ NULL, NULL }
23+
};
24+
25+
void setup() {
26+
Serial.begin(115200);
27+
while (!Serial) { delay(10); }
28+
WiFi.mode(WIFI_STA);
29+
WiFi.begin(ssid, password);
30+
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
31+
Serial.println("WiFi Connect Failed! Rebooting...");
32+
delay(1000);
33+
ESP.restart();
34+
}
35+
ArduinoOTA.begin();
36+
37+
server.on("/", []() {
38+
if (!server.authenticate([](HTTPAuthMethod mode, String username, String params[]) -> String * {
39+
// Scan the password list for the username and return the password if
40+
// we find the username.
41+
//
42+
for (credentials_t * entry = passwdfile; entry->username; entry++) {
43+
if (username == entry->username) {
44+
return new String(entry->password);
45+
};
46+
};
47+
// we've not found the user in the list.
48+
return NULL;
49+
}))
50+
{
51+
server.requestAuthentication();
52+
return;
53+
}
54+
server.send(200, "text/plain", "Login OK");
55+
});
56+
server.begin();
57+
58+
Serial.print("Open http://");
59+
Serial.print(WiFi.localIP());
60+
Serial.println("/ in your browser to see it working");
61+
}
62+
63+
void loop() {
64+
ArduinoOTA.handle();
65+
server.handleClient();
66+
delay(2);//allow the cpu to switch to other tasks
67+
}

‎libraries/WebServer/examples/HttpBasicAuthSHA1/.skip.esp32h2

Whitespace-only changes.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <WiFi.h>
2+
#include <ESPmDNS.h>
3+
#include <ArduinoOTA.h>
4+
#include <WebServer.h>
5+
6+
// Rather than specify the password as plaintext; we
7+
// provide it as an (unsalted!) SHA1 hash. This is not
8+
// much more secure (SHA1 is past its retirement age,
9+
// and long obsolte/insecure) - but it helps a little.
10+
11+
const char* ssid = "........";
12+
const char* password = "........";
13+
14+
WebServer server(80);
15+
16+
// Passwords as plaintext - human readable and easily visible in
17+
// the sourcecode and in the firmware/binary.
18+
const char* www_username = "admin";
19+
const char* www_password = "esp32";
20+
21+
// The sha1 of 'esp32' (without the trailing \0) expressed as 20
22+
// bytes of hex. Created by for example 'echo -n esp32 | openssl sha1'
23+
// or http://www.sha1-online.com.
24+
const char* www_username_hex = "hexadmin";
25+
const char* www_password_hex = "8cb124f8c277c16ec0b2ee00569fd151a08e342b";
26+
27+
// The same; but now expressed as a base64 string (e.g. as commonly used
28+
// by webservers). Created by ` echo -n esp32 | openssl sha1 -binary | openssl base64`
29+
const char* www_username_base64 = "base64admin";
30+
const char* www_password_base64 = "jLEk+MJ3wW7Asu4AVp/RUaCONCs=";
31+
32+
void setup() {
33+
Serial.begin(115200);
34+
while (!Serial) { delay(10); }
35+
WiFi.mode(WIFI_STA);
36+
WiFi.begin(ssid, password);
37+
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
38+
Serial.println("WiFi Connect Failed! Rebooting...");
39+
delay(1000);
40+
ESP.restart();
41+
}
42+
ArduinoOTA.begin();
43+
44+
server.on("/", []() {
45+
if (server.authenticate(www_username, www_password)) {
46+
server.send(200, "text/plain", "Login against cleartext password OK");
47+
return;
48+
}
49+
if (server.authenticateBasicSHA1(www_username_hex, www_password_hex)) {
50+
server.send(200, "text/plain", "Login against HEX of the SHA1 of the password OK");
51+
return;
52+
}
53+
if (server.authenticateBasicSHA1(www_username_base64, www_password_base64)) {
54+
server.send(200, "text/plain", "Login against Base64 of the SHA1 of the password OK");
55+
return;
56+
}
57+
Serial.println("No/failed authentication");
58+
return server.requestAuthentication();
59+
});
60+
61+
server.begin();
62+
63+
Serial.print("Open http://");
64+
Serial.print(WiFi.localIP());
65+
Serial.println("/ in your browser to see it working");
66+
}
67+
68+
void loop() {
69+
ArduinoOTA.handle();
70+
server.handleClient();
71+
delay(2);//allow the cpu to switch to other tasks
72+
}

‎libraries/WebServer/examples/HttpBasicAuthSHA1orBearerToken/.skip.esp32h2

Whitespace-only changes.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include <WiFi.h>
2+
#include <ESPmDNS.h>
3+
#include <ArduinoOTA.h>
4+
#include <WebServer.h>
5+
#include <SHA1Builder.h>
6+
7+
// We have two options - we either come in with a bearer
8+
// token - i.e. a special header or API token; or we
9+
// get a normal HTTP style basic auth prompt.
10+
//
11+
// To do a bearer fetch - use something like Swagger or with curl:
12+
//
13+
// curl https://myesp.com/ -H "Authorization: Bearer SecritToken"
14+
//
15+
// We avoid hardcoding this "SecritToken" into the code by
16+
// using a SHA1 instead (which is not paricularly secure).
17+
18+
// Create the secret token SHA1 with:
19+
// echo -n SecritToken | openssl sha1
20+
21+
String secret_token_hex = "d2cce6b472959484a21c3194080c609b8a2c910b";
22+
23+
// Wifi credentials
24+
25+
const char* ssid = "........";
26+
const char* password = "........";
27+
28+
WebServer server(80);
29+
30+
// Rather than specify the admin password as plaintext; we
31+
// provide it as an (unsalted!) SHA1 hash. This is not
32+
// much more secure (SHA1 is past its retirement age,
33+
// and long obsolte/insecure) - but it helps a little.
34+
35+
// The sha1 of 'esp32' (without the trailing \0) expressed as 20
36+
// bytes of hex. Created by for example 'echo -n esp32 | openssl sha1'
37+
// or http://www.sha1-online.com.
38+
const char* www_username_hex = "admin";
39+
const char* www_password_hex = "8cb124f8c277c16ec0b2ee00569fd151a08e342b";
40+
41+
static unsigned char _bearer[20];
42+
43+
String* check_bearer_or_auth(HTTPAuthMethod mode, String authReq, String params[]) {
44+
// we expect authReq to be "bearer some-secret"
45+
String lcAuthReq = authReq;
46+
lcAuthReq.toLowerCase();
47+
if (mode == OTHER_AUTH && (lcAuthReq.startsWith("bearer "))) {
48+
String secret = authReq.substring(7);
49+
secret.trim();
50+
51+
uint8_t sha1[20];
52+
SHA1Builder sha_builder;
53+
54+
sha_builder.begin();
55+
sha_builder.add((uint8_t*) secret.c_str(), secret.length());
56+
sha_builder.calculate();
57+
sha_builder.getBytes(sha1);
58+
59+
if (memcmp(_bearer, sha1, sizeof(_bearer)) == 0) {
60+
Serial.println("Bearer token matches");
61+
return new String("anything non null");
62+
} else {
63+
Serial.println("Bearer token does not match");
64+
}
65+
} else if (mode == BASIC_AUTH) {
66+
bool ret = server.authenticateBasicSHA1(www_username_hex, www_password_hex);
67+
if (ret) {
68+
Serial.println("Basic auth succeeded");
69+
return new String(params[0]);
70+
} else {
71+
Serial.println("Basic auth failed");
72+
}
73+
}
74+
75+
// No auth found
76+
return NULL;
77+
};
78+
79+
void setup() {
80+
Serial.begin(115200);
81+
while (!Serial) { delay(10); }
82+
WiFi.mode(WIFI_STA);
83+
WiFi.begin(ssid, password);
84+
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
85+
Serial.println("WiFi Connect Failed! Rebooting...");
86+
delay(1000);
87+
ESP.restart();
88+
}
89+
ArduinoOTA.begin();
90+
91+
// Convert token to a convenient binary representation.
92+
size_t len = HEXBuilder::hex2bytes(_bearer, sizeof(_bearer), secret_token_hex);
93+
if (len != 20)
94+
Serial.println("Bearer token does not look like a valid SHA1 hex string ?!");
95+
96+
server.on("/", []() {
97+
if (!server.authenticate(&check_bearer_or_auth)) {
98+
Serial.println("No/failed authentication");
99+
return server.requestAuthentication();
100+
}
101+
Serial.println("Authentication succeeded");
102+
server.send(200, "text/plain", "Login OK");
103+
return;
104+
});
105+
106+
server.begin();
107+
108+
Serial.print("Open http://");
109+
Serial.print(WiFi.localIP());
110+
Serial.println("/ in your browser to see it working");
111+
}
112+
113+
void loop() {
114+
ArduinoOTA.handle();
115+
server.handleClient();
116+
delay(2);//allow the cpu to switch to other tasks
117+
}

‎libraries/WebServer/src/WebServer.cpp

Lines changed: 187 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include <Arduino.h>
2525
#include <esp32-hal-log.h>
26+
#include <libb64/cdecode.h>
2627
#include <libb64/cencode.h>
2728
#include "esp_random.h"
2829
#include "WiFiServer.h"
@@ -31,7 +32,8 @@
3132
#include "FS.h"
3233
#include "detail/RequestHandlersImpl.h"
3334
#include "MD5Builder.h"
34-
35+
#include "SHA1Builder.h"
36+
#include "base64.h"
3537

3638
static const char AUTHORIZATION_HEADER[] = "Authorization";
3739
static const char qop_auth[] PROGMEM = "qop=auth";
@@ -40,7 +42,6 @@ static const char WWW_Authenticate[] = "WWW-Authenticate";
4042
static const char Content_Length[] = "Content-Length";
4143
static const char ETAG_HEADER[] = "If-None-Match";
4244

43-
4445
WebServer::WebServer(IPAddress addr, int port)
4546
: _corsEnabled(false)
4647
, _server(addr, port)
@@ -128,91 +129,185 @@ static String md5str(String &in){
128129
return md5.toString();
129130
}
130131

131-
bool WebServer::authenticate(const char * username, const char * password){
132-
if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) {
133-
String authReq = header(FPSTR(AUTHORIZATION_HEADER));
134-
if(authReq.startsWith(F("Basic"))){
135-
authReq = authReq.substring(6);
136-
authReq.trim();
137-
char toencodeLen = strlen(username)+strlen(password)+1;
138-
char *toencode = (char *)malloc(toencodeLen + 1);
139-
if(toencode == NULL){
140-
authReq = "";
141-
return false;
142-
}
143-
char *encoded = (char *)malloc(base64_encode_expected_len(toencodeLen)+1);
144-
if(encoded == NULL){
145-
authReq = "";
146-
free(toencode);
147-
return false;
148-
}
149-
sprintf(toencode, "%s:%s", username, password);
150-
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) {
151-
authReq = "";
152-
free(toencode);
153-
free(encoded);
154-
return true;
155-
}
156-
free(toencode);
157-
free(encoded);;
158-
} else if(authReq.startsWith(F("Digest"))) {
159-
authReq = authReq.substring(7);
160-
log_v("%s", authReq.c_str());
161-
String _username = _extractParam(authReq,F("username=\""),'\"');
162-
if(!_username.length() || _username != String(username)) {
163-
authReq = "";
164-
return false;
165-
}
166-
// extracting required parameters for RFC 2069 simpler Digest
167-
String _realm = _extractParam(authReq, F("realm=\""),'\"');
168-
String _nonce = _extractParam(authReq, F("nonce=\""),'\"');
169-
String _uri = _extractParam(authReq, F("uri=\""),'\"');
170-
String _response = _extractParam(authReq, F("response=\""),'\"');
171-
String _opaque = _extractParam(authReq, F("opaque=\""),'\"');
172-
173-
if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length())) {
174-
authReq = "";
175-
return false;
176-
}
177-
if((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm)) {
178-
authReq = "";
179-
return false;
180-
}
181-
// parameters for the RFC 2617 newer Digest
182-
String _nc,_cnonce;
183-
if(authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) {
184-
_nc = _extractParam(authReq, F("nc="), ',');
185-
_cnonce = _extractParam(authReq, F("cnonce=\""),'\"');
186-
}
187-
String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
188-
log_v("Hash of user:realm:pass=%s", _H1.c_str());
189-
String _H2 = "";
190-
if(_currentMethod == HTTP_GET){
191-
_H2 = md5str(String(F("GET:")) + _uri);
192-
}else if(_currentMethod == HTTP_POST){
193-
_H2 = md5str(String(F("POST:")) + _uri);
194-
}else if(_currentMethod == HTTP_PUT){
195-
_H2 = md5str(String(F("PUT:")) + _uri);
196-
}else if(_currentMethod == HTTP_DELETE){
197-
_H2 = md5str(String(F("DELETE:")) + _uri);
198-
}else{
199-
_H2 = md5str(String(F("GET:")) + _uri);
200-
}
201-
log_v("Hash of GET:uri=%s", _H2.c_str());
202-
String _responsecheck = "";
203-
if(authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) {
204-
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
205-
} else {
206-
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
207-
}
208-
log_v("The Proper response=%s", _responsecheck.c_str());
209-
if(_response == _responsecheck){
132+
bool WebServer::authenticateBasicSHA1(const char * _username, const char * _sha1Base64orHex) {
133+
return WebServer::authenticate([_username,_sha1Base64orHex](HTTPAuthMethod mode, String username, String params[])->String * {
134+
// rather than work on a password to compare with; we take the sha1 of the
135+
// password received over the wire and compare that to the base64 encoded
136+
// sha1 passed as _sha1base64. That way there is no need to have a
137+
// plaintext password in the code/binary (though note that SHA1 is well
138+
// past its retirement age). When that matches - we `cheat' by returning
139+
// the password we got in the first place; so the normal BasicAuth
140+
// can be completed. Note that this cannot work for a digest auth -
141+
// as there the password in the clear is part of the calculation.
142+
143+
if (params == nullptr) {
144+
log_e("Something went wrong. params is NULL");
145+
return NULL;
146+
}
147+
148+
uint8_t sha1[20];
149+
char sha1calc[48]; // large enough for base64 and Hex represenation
150+
String ret;
151+
SHA1Builder sha_builder;
152+
base64 b64;
153+
154+
log_v("Trying to authenticate user %s using SHA1.", username.c_str());
155+
sha_builder.begin();
156+
sha_builder.add((uint8_t*) params[0].c_str(), params[0].length());
157+
sha_builder.calculate();
158+
sha_builder.getBytes(sha1);
159+
160+
// we can either decode _sha1base64orHex and then compare the 20 bytes;
161+
// or encode the sha we calculated. We pick the latter as encoding of a
162+
// fixed array of 20 bytes is safer than operating on something external.
163+
if (strlen(_sha1Base64orHex) == 20 * 2) { // 2 chars per byte
164+
sha_builder.bytes2hex(sha1calc, sizeof(sha1calc), sha1, sizeof(sha1));
165+
log_v("Calculated SHA1 in hex: %s", sha1calc);
166+
} else {
167+
ret = b64.encode(sha1, sizeof(sha1));
168+
ret.toCharArray(sha1calc, sizeof(sha1calc));
169+
log_v("Calculated SHA1 in base64: %s", sha1calc);
170+
}
171+
172+
return ((username.equalsConstantTime(_username)) &&
173+
(String((char*)sha1calc).equalsConstantTime(_sha1Base64orHex)) &&
174+
(mode == BASIC_AUTH) /* to keep things somewhat time constant. */
175+
) ? new String(params[0]) : NULL;
176+
});
177+
}
178+
179+
bool WebServer::authenticate(const char * _username, const char * _password) {
180+
return WebServer::authenticate([_username,_password](HTTPAuthMethod mode, String username, String params[])->String * {
181+
return username.equalsConstantTime(_username) ? new String(_password) : NULL;
182+
});
183+
}
184+
185+
bool WebServer::authenticate(THandlerFunctionAuthCheck fn) {
186+
if (!hasHeader(FPSTR(AUTHORIZATION_HEADER))) {
187+
return false;
188+
}
189+
190+
String authReq = header(FPSTR(AUTHORIZATION_HEADER));
191+
if (authReq.startsWith(AuthTypeBasic)) {
192+
log_v("Trying to authenticate using Basic Auth");
193+
bool ret = false;
194+
195+
authReq = authReq.substring(6); // length of AuthTypeBasic including the space at the end.
196+
authReq.trim();
197+
198+
/* base64 encoded string is always shorter (or equal) in length */
199+
char* decoded = (authReq.length() < HTTP_MAX_BASIC_AUTH_LEN) ? new char[authReq.length()] : NULL;
200+
if (decoded) {
201+
char* p;
202+
if (base64_decode_chars(authReq.c_str(), authReq.length(), decoded) && (p = index(decoded, ':')) && p) {
210203
authReq = "";
211-
return true;
204+
/* Note: rfc7617 guarantees that there will not be an escaped colon in the username itself.
205+
* Note: base64_decode_chars() guarantees a terminating \0
206+
*/
207+
*p = '\0';
208+
char * _username = decoded, * _password = p + 1;
209+
String params[] = {
210+
_password,
211+
_srealm
212+
};
213+
String* password = fn(BASIC_AUTH, _username, params);
214+
215+
if (password) {
216+
ret = password->equalsConstantTime(_password);
217+
// we're more concerned about the password; as the attacker already
218+
// knows the _pasword. Arduino's string handling is simple; it reallocs
219+
// even when smaller; so a memset is enough (no capacity/size).
220+
memset((void *)password->c_str(), 0, password->length());
221+
delete password;
222+
}
212223
}
224+
delete[] decoded;
225+
}
226+
authReq = "";
227+
log_v("Authentication %s", ret ? "Success" : "Failed");
228+
return ret;
229+
} else if (authReq.startsWith(AuthTypeDigest)) {
230+
log_v("Trying to authenticate using Digest Auth");
231+
authReq = authReq.substring(7);
232+
log_v("%s", authReq.c_str());
233+
234+
// extracting required parameters for RFC 2069 simpler Digest
235+
String _username = _extractParam(authReq, F("username=\""), '\"');
236+
String _realm = _extractParam(authReq, F("realm=\""), '\"');
237+
String _uri = _extractParam(authReq, F("uri=\""), '\"');
238+
if (!_username.length())
239+
goto exf;
240+
241+
String params[] = {
242+
_realm,
243+
_uri
244+
};
245+
String* password = fn(DIGEST_AUTH, _username, params);
246+
if (!password)
247+
goto exf;
248+
249+
String _H1 = md5str(String(_username) + ':' + _realm + ':' + * password);
250+
// we're extra concerned; as digest request us to know the password
251+
// in the clear.
252+
memset((void *) password->c_str(), 0, password->length());
253+
delete password;
254+
_username = "";
255+
256+
String _nonce = _extractParam(authReq, F("nonce=\""), '\"');
257+
String _response = _extractParam(authReq, F("response=\""), '\"');
258+
String _opaque = _extractParam(authReq, F("opaque=\""), '\"');
259+
260+
if ((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length()))
261+
goto exf;
262+
263+
if ((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm))
264+
goto exf;
265+
266+
// parameters for the RFC 2617 newer Digest
267+
String _nc, _cnonce;
268+
if (authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) {
269+
_nc = _extractParam(authReq, F("nc="), ',');
270+
_cnonce = _extractParam(authReq, F("cnonce=\""), '\"');
271+
}
272+
273+
log_v("Hash of user:realm:pass=%s", _H1.c_str());
274+
String _H2 = "";
275+
if (_currentMethod == HTTP_GET) {
276+
_H2 = md5str(String(F("GET:")) + _uri);
277+
} else if (_currentMethod == HTTP_POST) {
278+
_H2 = md5str(String(F("POST:")) + _uri);
279+
} else if (_currentMethod == HTTP_PUT) {
280+
_H2 = md5str(String(F("PUT:")) + _uri);
281+
} else if (_currentMethod == HTTP_DELETE) {
282+
_H2 = md5str(String(F("DELETE:")) + _uri);
283+
} else {
284+
_H2 = md5str(String(F("GET:")) + _uri);
285+
}
286+
log_v("Hash of GET:uri=%s", _H2.c_str());
287+
String _responsecheck = "";
288+
if (authReq.indexOf(FPSTR(qop_auth)) != -1 || authReq.indexOf(FPSTR(qop_auth_quoted)) != -1) {
289+
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
290+
} else {
291+
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
213292
}
214293
authReq = "";
294+
295+
log_v("The Proper response=%s", _responsecheck.c_str());
296+
bool ret = _response == _responsecheck;
297+
log_v("Authentication %s", ret ? "Success" : "Failed");
298+
return ret;
299+
} else if (authReq.length()) {
300+
// OTHER_AUTH
301+
log_v("Trying to authenticate using Other Auth, authReq=%s", authReq.c_str());
302+
String* ret = fn(OTHER_AUTH, authReq, {});
303+
if (ret) {
304+
log_v("Authentication Success");
305+
return true;
306+
}
215307
}
308+
exf:
309+
authReq = "";
310+
log_v("Authentication Failed");
216311
return false;
217312
}
218313

@@ -232,11 +327,11 @@ void WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, co
232327
_srealm = String(realm);
233328
}
234329
if(mode == BASIC_AUTH) {
235-
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\"")));
330+
sendHeader(String(FPSTR(WWW_Authenticate)), AuthTypeBasic + String(F(" realm=\"")) + _srealm + String(F("\"")));
236331
} else {
237332
_snonce=_getRandomHexString();
238333
_sopaque=_getRandomHexString();
239-
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\"")));
334+
sendHeader(String(FPSTR(WWW_Authenticate)), AuthTypeDigest + String(F(" realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\"")));
240335
}
241336
using namespace mime;
242337
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
@@ -411,8 +506,8 @@ void WebServer::_prepareHeader(String& response, int code, const char* content_t
411506
}
412507
if (_corsEnabled) {
413508
sendHeader(String(FPSTR("Access-Control-Allow-Origin")), String("*"));
414-
sendHeader(String(FPSTR("Access-Control-Allow-Methods")), String("*"));
415-
sendHeader(String(FPSTR("Access-Control-Allow-Headers")), String("*"));
509+
sendHeader(String(FPSTR("Access-Control-Allow-Methods")), String("*"));
510+
sendHeader(String(FPSTR("Access-Control-Allow-Headers")), String("*"));
416511
}
417512
sendHeader(String(F("Connection")), String(F("close")));
418513

@@ -543,9 +638,9 @@ String WebServer::pathArg(unsigned int i) {
543638

544639
String WebServer::arg(String name) {
545640
for (int j = 0; j < _postArgsLen; ++j) {
546-
if ( _postArgs[j].key == name )
547-
return _postArgs[j].value;
548-
}
641+
if ( _postArgs[j].key == name )
642+
return _postArgs[j].value;
643+
}
549644
for (int i = 0; i < _currentArgCount; ++i) {
550645
if ( _currentArgs[i].key == name )
551646
return _currentArgs[i].value;
@@ -571,9 +666,9 @@ int WebServer::args() {
571666

572667
bool WebServer::hasArg(String name) {
573668
for (int j = 0; j < _postArgsLen; ++j) {
574-
if (_postArgs[j].key == name)
575-
return true;
576-
}
669+
if (_postArgs[j].key == name)
670+
return true;
671+
}
577672
for (int i = 0; i < _currentArgCount; ++i) {
578673
if (_currentArgs[i].key == name)
579674
return true;

‎libraries/WebServer/src/WebServer.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
3535
UPLOAD_FILE_ABORTED };
3636
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
37-
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
37+
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH, OTHER_AUTH };
3838

3939
#define HTTP_DOWNLOAD_UNIT_SIZE 1436
4040

@@ -46,6 +46,7 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
4646
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
4747
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
4848
#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection
49+
#define HTTP_MAX_BASIC_AUTH_LEN 256 // maximum length of a basic Auth base64 encoded username:password string
4950

5051
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
5152
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
@@ -82,12 +83,41 @@ class WebServer
8283
virtual void close();
8384
void stop();
8485

86+
const String AuthTypeDigest = F("Digest");
87+
const String AuthTypeBasic = F("Basic");
88+
89+
/* Callbackhandler for authentication. The extra parameters depend on the
90+
* HTTPAuthMethod mode:
91+
*
92+
* BASIC_AUTH enteredUsernameOrReq contains the username entered by the user
93+
* param[0] password entered (in the clear)
94+
* param[1] authentication realm.
95+
*
96+
* To return - the password the user entered password is compared to. Or Null on fail.
97+
*
98+
* DIGEST_AUTH enteredUsernameOrReq contains the username entered by the user
99+
* param[0] autenticaiton realm
100+
* param[1] authentication URI
101+
*
102+
* To return - the password of which the digest will be based on for comparison. Or NULL
103+
* to fail.
104+
*
105+
* OTHER_AUTH enteredUsernameOrReq rest of the auth line.
106+
* params empty array
107+
*
108+
* To return - NULL to fail; or any string.
109+
*/
110+
typedef std::function<String * (HTTPAuthMethod mode, String enteredUsernameOrReq, String extraParams[])> THandlerFunctionAuthCheck;
111+
112+
bool authenticate(THandlerFunctionAuthCheck fn);
85113
bool authenticate(const char * username, const char * password);
114+
bool authenticateBasicSHA1(const char * _username, const char * _sha1AsBase64orHex);
115+
86116
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );
87117

88118
typedef std::function<void(void)> THandlerFunction;
89119
void on(const Uri &uri, THandlerFunction fn);
90-
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
120+
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
91121
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads
92122
void addHandler(RequestHandler* handler);
93123
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );

‎tests/periman/periman.ino

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/* Peripheral Manager test
2+
*
3+
* This test is using Serial to check if the peripheral manager is able to
4+
* attach and detach peripherals correctly on shared pins.
5+
* Make sure that the peripheral names contain only letters, numbers and underscores.
6+
*
7+
* This test skips the following peripherals:
8+
* - USB: USB is not able to be detached
9+
* - SDMMC: SDMMC requires a card to be mounted before the pins are attached
10+
* - ETH: ETH requires a ethernet port to be connected before the pins are attached
11+
*/
12+
13+
#if SOC_I2S_SUPPORTED
14+
#include "ESP_I2S.h"
15+
#endif
16+
17+
#if SOC_I2C_SUPPORTED
18+
#include "Wire.h"
19+
#endif
20+
21+
#if SOC_GPSPI_SUPPORTED
22+
#include "SPI.h"
23+
#endif
24+
25+
/* Definitions */
26+
27+
#define UART1_RX_DEFAULT 4
28+
#define UART1_TX_DEFAULT 5
29+
30+
#define ADC1_DEFAULT A4
31+
32+
#if CONFIG_IDF_TARGET_ESP32
33+
# define ADC2_DEFAULT A5
34+
#else
35+
# define ADC2_DEFAULT A3
36+
#endif
37+
38+
#if CONFIG_IDF_TARGET_ESP32
39+
# define TOUCH1_DEFAULT T0
40+
# define TOUCH2_DEFAULT T2
41+
#else
42+
# define TOUCH1_DEFAULT T4
43+
# define TOUCH2_DEFAULT T5
44+
#endif
45+
46+
/* Global variables */
47+
48+
bool test_executed = false;
49+
String current_test;
50+
int8_t uart1_rx_pin;
51+
int8_t uart1_tx_pin;
52+
53+
/* Callback functions */
54+
55+
void onReceive_cb(void) {
56+
// This is a callback function that will be activated on UART RX events
57+
size_t available = Serial1.available();
58+
while (available --) {
59+
Serial.print((char)Serial1.read());
60+
}
61+
}
62+
63+
// This function is called by before each test is run
64+
void setup_test(String test_name, int8_t rx_pin = UART1_RX_DEFAULT, int8_t tx_pin = UART1_TX_DEFAULT) {
65+
log_v("Setting up %s test", test_name.c_str());
66+
67+
current_test = test_name;
68+
uart1_rx_pin = rx_pin;
69+
uart1_tx_pin = tx_pin;
70+
test_executed = false;
71+
72+
pinMode(uart1_rx_pin, INPUT_PULLUP);
73+
pinMode(uart1_tx_pin, OUTPUT);
74+
Serial1.setPins(uart1_rx_pin, uart1_tx_pin);
75+
uart_internal_loopback(1, uart1_rx_pin);
76+
delay(100);
77+
log_v("Running %s test", test_name.c_str());
78+
}
79+
80+
// This function is called after each test is run
81+
void teardown_test(void) {
82+
log_v("Tearing down %s test", current_test.c_str());
83+
if (test_executed) {
84+
pinMode(uart1_rx_pin, INPUT_PULLUP);
85+
pinMode(uart1_tx_pin, OUTPUT);
86+
Serial1.print(current_test);
87+
Serial1.println(" test: This should not be printed");
88+
Serial1.flush();
89+
90+
Serial1.setPins(uart1_rx_pin, uart1_tx_pin);
91+
uart_internal_loopback(1, uart1_rx_pin);
92+
delay(100);
93+
}
94+
95+
Serial1.print(current_test);
96+
Serial1.println(" test: This should be printed");
97+
Serial1.flush();
98+
99+
log_v("Finished %s test", current_test.c_str());
100+
}
101+
102+
/* Test functions */
103+
/* These functions must call "setup_test" and "teardown_test" and set "test_executed" to true
104+
* if the test is executed
105+
*/
106+
107+
void gpio_test(void) {
108+
setup_test("GPIO");
109+
test_executed = true;
110+
pinMode(uart1_rx_pin, INPUT);
111+
pinMode(uart1_tx_pin, OUTPUT);
112+
digitalRead(uart1_rx_pin);
113+
digitalWrite(uart1_tx_pin, HIGH);
114+
teardown_test();
115+
}
116+
117+
void sigmadelta_test(void) {
118+
setup_test("SigmaDelta");
119+
#if SOC_SDM_SUPPORTED
120+
test_executed = true;
121+
if (!sigmaDeltaAttach(uart1_rx_pin, 312500)) {
122+
Serial.println("SigmaDelta init failed");
123+
}
124+
if (!sigmaDeltaAttach(uart1_tx_pin, 312500)) {
125+
Serial.println("SigmaDelta init failed");
126+
}
127+
#endif
128+
teardown_test();
129+
}
130+
131+
void adc_oneshot_test(void) {
132+
#if !SOC_ADC_SUPPORTED
133+
setup_test("ADC_Oneshot");
134+
#else
135+
setup_test("ADC_Oneshot", ADC1_DEFAULT, ADC2_DEFAULT);
136+
test_executed = true;
137+
analogReadResolution(12);
138+
pinMode(ADC1_DEFAULT, INPUT);
139+
pinMode(ADC2_DEFAULT, INPUT);
140+
analogRead(ADC1_DEFAULT);
141+
analogRead(ADC2_DEFAULT);
142+
#endif
143+
teardown_test();
144+
}
145+
146+
#if SOC_ADC_SUPPORTED
147+
volatile bool adc_coversion_done = false;
148+
void ARDUINO_ISR_ATTR adcComplete() {
149+
adc_coversion_done = true;
150+
}
151+
#endif
152+
153+
void adc_continuous_test(void) {
154+
#if !SOC_ADC_SUPPORTED
155+
setup_test("ADC_Continuous");
156+
#else
157+
setup_test("ADC_Continuous", ADC1_DEFAULT, ADC2_DEFAULT);
158+
test_executed = true;
159+
uint8_t adc_pins[] = {ADC1_DEFAULT, ADC2_DEFAULT};
160+
uint8_t adc_pins_count = 2;
161+
adc_continuos_data_t * result = NULL;
162+
163+
analogContinuousSetWidth(12);
164+
analogContinuousSetAtten(ADC_11db);
165+
166+
analogContinuous(adc_pins, adc_pins_count, 6, 20000, &adcComplete);
167+
analogContinuousStart();
168+
169+
while (adc_coversion_done == false) {
170+
delay(1);
171+
}
172+
173+
if (!analogContinuousRead(&result, 0)) {
174+
Serial.println("ADC continuous read failed");
175+
}
176+
177+
analogContinuousStop();
178+
#endif
179+
teardown_test();
180+
}
181+
182+
void dac_test(void) {
183+
#if !SOC_DAC_SUPPORTED
184+
setup_test("DAC");
185+
#else
186+
setup_test("DAC", DAC1, DAC2);
187+
test_executed = true;
188+
dacWrite(DAC1, 255);
189+
dacWrite(DAC2, 255);
190+
#endif
191+
teardown_test();
192+
}
193+
194+
void ledc_test(void) {
195+
setup_test("LEDC");
196+
#if SOC_LEDC_SUPPORTED
197+
test_executed = true;
198+
if (!ledcAttach(uart1_rx_pin, 5000, 12)) {
199+
Serial.println("LEDC init failed");
200+
}
201+
if (!ledcAttach(uart1_tx_pin, 5000, 12)) {
202+
Serial.println("LEDC init failed");
203+
}
204+
#endif
205+
teardown_test();
206+
}
207+
208+
void rmt_test(void) {
209+
setup_test("RMT");
210+
#if SOC_RMT_SUPPORTED
211+
test_executed = true;
212+
if (!rmtInit(uart1_rx_pin, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) {
213+
Serial.println("RMT init failed");
214+
}
215+
if (!rmtInit(uart1_tx_pin, RMT_RX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) {
216+
Serial.println("RMT init failed");
217+
}
218+
#endif
219+
teardown_test();
220+
}
221+
222+
void i2s_test(void) {
223+
setup_test("I2S");
224+
#if SOC_I2S_SUPPORTED
225+
test_executed = true;
226+
I2SClass i2s;
227+
228+
i2s.setPins(uart1_rx_pin, uart1_tx_pin, -1);
229+
i2s.setTimeout(1000);
230+
if (!i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)) {
231+
Serial.println("I2S init failed");
232+
}
233+
#endif
234+
teardown_test();
235+
}
236+
237+
void i2c_test(void) {
238+
setup_test("I2C");
239+
#if SOC_I2C_SUPPORTED
240+
test_executed = true;
241+
if (!Wire.begin(uart1_rx_pin, uart1_tx_pin)) {
242+
Serial.println("I2C init failed");
243+
}
244+
#endif
245+
teardown_test();
246+
}
247+
248+
void spi_test(void) {
249+
setup_test("SPI");
250+
#if SOC_GPSPI_SUPPORTED
251+
test_executed = true;
252+
SPI.begin(uart1_rx_pin, uart1_tx_pin, -1, -1);
253+
#endif
254+
teardown_test();
255+
}
256+
257+
void touch_test(void) {
258+
#if !SOC_TOUCH_SENSOR_SUPPORTED
259+
setup_test("Touch");
260+
#else
261+
setup_test("Touch", TOUCH1_DEFAULT, TOUCH2_DEFAULT);
262+
test_executed = true;
263+
touchRead(TOUCH1_DEFAULT);
264+
touchRead(TOUCH2_DEFAULT);
265+
#endif
266+
teardown_test();
267+
}
268+
269+
/* Main functions */
270+
271+
void setup() {
272+
Serial.begin(115200);
273+
while(!Serial) { delay(10); }
274+
275+
Serial1.setPins(UART1_RX_DEFAULT, UART1_TX_DEFAULT);
276+
Serial1.begin(115200);
277+
while(!Serial1) { delay(10); }
278+
Serial1.onReceive(onReceive_cb);
279+
uart_internal_loopback(1, uart1_rx_pin);
280+
281+
gpio_test();
282+
sigmadelta_test();
283+
ledc_test();
284+
rmt_test();
285+
i2s_test();
286+
i2c_test();
287+
spi_test();
288+
adc_oneshot_test();
289+
adc_continuous_test();
290+
dac_test();
291+
touch_test();
292+
293+
// Print to Serial1 to avoid buffering issues
294+
Serial1.println("Peripheral Manager test done");
295+
}
296+
297+
void loop() {}

‎tests/periman/test_periman.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
def test_periman(dut):
2+
peripherals = ["GPIO", "SigmaDelta", "LEDC", "RMT", "I2S", "I2C", "SPI",
3+
"ADC_Oneshot", "ADC_Continuous", "DAC", "Touch"]
4+
5+
pattern = rb"(?:\b\w+\b test: This should(?: not)? be printed|Peripheral Manager test done)"
6+
7+
while True:
8+
try:
9+
res = dut.expect(pattern, timeout=10)
10+
except:
11+
assert False, f"Could not detect end of test"
12+
13+
console_output = res.group(0).decode("utf-8")
14+
peripheral = console_output.split()[0]
15+
16+
if "Peripheral Manager test done" in console_output:
17+
break
18+
19+
if peripheral in peripherals:
20+
if "not" in console_output:
21+
assert False, f"Peripheral {peripheral} printed when it should not"
22+
peripherals.remove(peripheral)
23+
else:
24+
assert False, f"Unknown peripheral: {peripheral}"
25+
26+
assert peripherals == [], f"Missing peripherals output: {peripherals}"

‎tests/uart/uart.ino

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ void start_serial(unsigned long baudrate = 115200) {
7878
// This function stops all the available test UARTs
7979
void stop_serial(bool hard_stop = false) {
8080
#if SOC_UART_NUM >= 2
81-
Serial1.end(hard_stop);
81+
Serial1.end(/*hard_stop*/);
8282
#endif
8383

8484
#if SOC_UART_NUM >= 3
85-
Serial2.end(hard_stop);
85+
Serial2.end(/*hard_stop*/);
8686
#endif
8787
}
8888

@@ -139,6 +139,19 @@ void task_delayed_msg(void *pvParameters) {
139139
// This function is automatically called by unity before each test is run
140140
void setUp(void) {
141141
start_serial(115200);
142+
#if SOC_UART_NUM == 2
143+
log_d("Setup internal loop-back from and back to Serial1 (UART1) TX >> Serial1 (UART1) RX");
144+
145+
Serial1.onReceive([]() {onReceive_cb(Serial1);});
146+
uart_internal_loopback(1, RX1);
147+
#elif SOC_UART_NUM == 3
148+
log_d("Setup internal loop-back between Serial1 (UART1) <<--->> Serial2 (UART2)");
149+
150+
Serial1.onReceive([]() {onReceive_cb(Serial1);});
151+
Serial2.onReceive([]() {onReceive_cb(Serial2);});
152+
uart_internal_loopback(1, RX2);
153+
uart_internal_loopback(2, RX1);
154+
#endif
142155
}
143156

144157
// This function is automatically called by unity after each test is run
@@ -393,7 +406,7 @@ void disabled_uart_calls_test(void) {
393406

394407
// This test checks if the pins can be changed and if the message can be transmitted and received correctly after the change
395408
void change_pins_test(void) {
396-
stop_serial();
409+
//stop_serial();
397410

398411
log_d("Disabling UART loopback");
399412

@@ -453,7 +466,7 @@ void auto_baudrate_test(void) {
453466
selected_serial = &Serial2;
454467
#endif
455468

456-
selected_serial->end(false);
469+
//selected_serial->end(false);
457470

458471
log_d("Starting delayed task to send message");
459472

‎variants/arduino_nano_nora/pins_arduino.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ static constexpr uint8_t A7 = 14;
7676

7777
#endif
7878

79+
// Aliases
80+
81+
static constexpr uint8_t LEDR = LED_RED;
82+
static constexpr uint8_t LEDG = LED_GREEN;
83+
static constexpr uint8_t LEDB = LED_BLUE;
84+
7985
// alternate pin functions
8086

8187
static constexpr uint8_t LED_BUILTIN = D13;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#ifndef Pins_Arduino_h
2+
#define Pins_Arduino_h
3+
4+
#include <stdint.h>
5+
#include "soc/soc_caps.h"
6+
7+
#define WIRELESS_TRACKER true
8+
9+
#define DISPLAY_HEIGHT 80
10+
#define DISPLAY_WIDTH 160
11+
12+
#define USB_VID 0x303a
13+
#define USB_PID 0x1001
14+
15+
static const uint8_t LED_BUILTIN = 18;
16+
#define BUILTIN_LED LED_BUILTIN // backward compatibility
17+
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
18+
19+
20+
static const uint8_t TX = 43;
21+
static const uint8_t RX = 44;
22+
23+
static const uint8_t SDA = 5;
24+
static const uint8_t SCL = 6;
25+
26+
static const uint8_t SS = 8;
27+
static const uint8_t MOSI = 10;
28+
static const uint8_t MISO = 11;
29+
static const uint8_t SCK = 9;
30+
31+
static const uint8_t A0 = 1;
32+
static const uint8_t A1 = 2;
33+
static const uint8_t A2 = 3;
34+
static const uint8_t A3 = 4;
35+
static const uint8_t A4 = 5;
36+
static const uint8_t A5 = 6;
37+
static const uint8_t A6 = 7;
38+
static const uint8_t A7 = 8;
39+
static const uint8_t A8 = 9;
40+
static const uint8_t A9 = 10;
41+
static const uint8_t A10 = 11;
42+
static const uint8_t A11 = 12;
43+
static const uint8_t A12 = 13;
44+
static const uint8_t A13 = 14;
45+
static const uint8_t A14 = 15;
46+
static const uint8_t A15 = 16;
47+
static const uint8_t A16 = 17;
48+
static const uint8_t A17 = 18;
49+
static const uint8_t A18 = 19;
50+
static const uint8_t A19 = 20;
51+
52+
static const uint8_t T1 = 1;
53+
static const uint8_t T2 = 2;
54+
static const uint8_t T3 = 3;
55+
static const uint8_t T4 = 4;
56+
static const uint8_t T5 = 5;
57+
static const uint8_t T6 = 6;
58+
static const uint8_t T7 = 7;
59+
static const uint8_t T8 = 8;
60+
static const uint8_t T9 = 9;
61+
static const uint8_t T10 = 10;
62+
static const uint8_t T11 = 11;
63+
static const uint8_t T12 = 12;
64+
static const uint8_t T13 = 13;
65+
static const uint8_t T14 = 14;
66+
67+
static const uint8_t Vext = 3;
68+
static const uint8_t LED = 18;
69+
70+
static const uint8_t ST7735_CS_PIN = 38;
71+
static const uint8_t ST7735_RST_PIN = 39;
72+
static const uint8_t ST7735_DC_PIN = 40;
73+
static const uint8_t ST7735_SCLK_PIN = 41;
74+
static const uint8_t ST7735_MOSI_PIN = 42;
75+
static const uint8_t ST7735_LED_K_PIN = 21;
76+
77+
#endif /* Pins_Arduino_h */
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef Pins_Arduino_h
2+
#define Pins_Arduino_h
3+
4+
#include <stdint.h>
5+
6+
#define TX1 0
7+
#define RX1 1
8+
9+
static const uint8_t LED_BUILTIN = 8;
10+
#define BUILTIN_LED LED_BUILTIN // backward compatibility
11+
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
12+
13+
static const uint8_t BOOT_BUILTIN = 9; // built-in boot button
14+
15+
static const uint8_t TX = 21;
16+
static const uint8_t RX = 20;
17+
18+
static const uint8_t SDA = 8;
19+
static const uint8_t SCL = 9;
20+
21+
static const uint8_t SS = 7;
22+
static const uint8_t MOSI = 6;
23+
static const uint8_t MISO = 5;
24+
static const uint8_t SCK = 4;
25+
26+
static const uint8_t A0 = 0;
27+
static const uint8_t A1 = 1;
28+
static const uint8_t A2 = 2;
29+
static const uint8_t A3 = 3;
30+
static const uint8_t A4 = 4;
31+
static const uint8_t A5 = 5;
32+
33+
#endif /* Pins_Arduino_h */
34+

0 commit comments

Comments
 (0)
Please sign in to comment.