forked from espressif/arduino-esp32
Compare commits
65 Commits
Author | SHA1 | Date | |
---|---|---|---|
15bbd0a187 | |||
02c3ec01cc | |||
cb5a490616 | |||
f257d6f126 | |||
aabbed0bbc | |||
a418058a66 | |||
96ad341451 | |||
2673b88582 | |||
67c99142d2 | |||
951c8bece5 | |||
4413dbbd87 | |||
ed53b6c8d4 | |||
2e53300da5 | |||
64c7f746fd | |||
1049be7d56 | |||
34c81be93b | |||
2fb2ef54ce | |||
49f525c91d | |||
b145e65975 | |||
951c32056a | |||
7a7bd37e51 | |||
a75602dc68 | |||
88789cd817 | |||
335cedf4f7 | |||
f9f70d2f73 | |||
5b207104aa | |||
1706af4656 | |||
bd54ee442b | |||
00214d5c2a | |||
381e88ec75 | |||
f87107dedb | |||
ce85cf03cc | |||
f2a20e8a38 | |||
c5bb8334d7 | |||
6de7f16f28 | |||
1688b7c179 | |||
36ff442698 | |||
93f10609f4 | |||
67583e84d6 | |||
108e467164 | |||
91bca6c074 | |||
204f360dce | |||
3f06a38f69 | |||
2f6f251400 | |||
e4acfbc54a | |||
79d53bdc4c | |||
f3f6dad14a | |||
317be68cef | |||
1f4dd7f131 | |||
8be2f7b1cc | |||
9f827a66d5 | |||
e1cdbd7816 | |||
7a35be3e7e | |||
078671d273 | |||
541cef9149 | |||
6dfaf6cdd4 | |||
92ce408f4c | |||
453af3800c | |||
44c11981d2 | |||
9eea85f9ff | |||
24b76cbb14 | |||
4a55ff970d | |||
a62979d8a0 | |||
1f59c5abec | |||
0730e0ec93 |
27
.github/workflows/test_selfhosted_runner.yml
vendored
Normal file
27
.github/workflows/test_selfhosted_runner.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Test Github action on self hosted RPI runnes
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Dummy test - self hosted GHR
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Test message 1
|
||||
run: echo "This is test message"
|
||||
- name: Test message 2
|
||||
run: echo "This is test message2"
|
||||
- name: List directory
|
||||
run: ls
|
||||
- name: Create copy of README
|
||||
run: cp README.md README2.md
|
||||
- name: Read README2
|
||||
run: cat README2.md
|
||||
- name: Delete README2
|
||||
run: rm README2.md
|
@ -7,6 +7,7 @@ set(CORE_SRCS
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
cores/esp32/esp32-hal-i2c-slave.c
|
||||
cores/esp32/esp32-hal-ledc.c
|
||||
cores/esp32/esp32-hal-matrix.c
|
||||
cores/esp32/esp32-hal-misc.c
|
||||
@ -32,6 +33,7 @@ set(CORE_SRCS
|
||||
cores/esp32/stdlib_noniso.c
|
||||
cores/esp32/Stream.cpp
|
||||
cores/esp32/StreamString.cpp
|
||||
cores/esp32/HWCDC.cpp
|
||||
cores/esp32/USB.cpp
|
||||
cores/esp32/USBCDC.cpp
|
||||
cores/esp32/USBMSC.cpp
|
||||
@ -173,7 +175,7 @@ set(includedirs
|
||||
set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
|
||||
set(priv_includes cores/esp32/libb64)
|
||||
set(requires spi_flash mbedtls mdns esp_adc_cal wifi_provisioning nghttp)
|
||||
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc)
|
||||
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc esp_hid)
|
||||
|
||||
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
|
||||
|
||||
|
@ -43,7 +43,7 @@ You can use [Arduino-ESP32 Online Documentation](https://docs.espressif.com/proj
|
||||
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
|
||||
|
||||
### Issue/Bug report template
|
||||
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [for reference](https://github.com/espressif/arduino-esp32/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22for%20reference%22%20).
|
||||
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
|
||||
|
||||
Finally, if you are sure no one else had the issue, follow the [issue template](docs/ISSUE_TEMPLATE.md) while reporting any issue.
|
||||
|
||||
|
340
boards.txt
340
boards.txt
@ -21,12 +21,16 @@ menu.EventsCore=Events Run On
|
||||
##############################################################
|
||||
|
||||
esp32c3.name=ESP32C3 Dev Module
|
||||
esp32c3.vid.0=0x303a
|
||||
esp32c3.pid.0=0x1001
|
||||
|
||||
esp32c3.upload.tool=esptool_py
|
||||
esp32c3.upload.maximum_size=1310720
|
||||
esp32c3.upload.maximum_data_size=327680
|
||||
esp32c3.upload.flags=
|
||||
esp32c3.upload.extra_flags=
|
||||
esp32c3.upload.use_1200bps_touch=false
|
||||
esp32c3.upload.wait_for_upload_port=false
|
||||
|
||||
esp32c3.serial.disableDTR=false
|
||||
esp32c3.serial.disableRTS=false
|
||||
@ -48,6 +52,11 @@ esp32c3.build.boot=qio
|
||||
esp32c3.build.partitions=default
|
||||
esp32c3.build.defines=
|
||||
|
||||
esp32c3.menu.CDCOnBoot.default=Disabled
|
||||
esp32c3.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
esp32c3.menu.CDCOnBoot.cdc=Enabled
|
||||
esp32c3.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
|
||||
esp32c3.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
|
||||
esp32c3.menu.PartitionScheme.default.build.partitions=default
|
||||
esp32c3.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
|
||||
@ -977,7 +986,7 @@ feathers2.build.variant=um_feathers2
|
||||
feathers2.build.board=FEATHERS2
|
||||
|
||||
feathers2.build.cdc_on_boot=1
|
||||
feathers2.build.msc_on_boot=1
|
||||
feathers2.build.msc_on_boot=0
|
||||
feathers2.build.dfu_on_boot=0
|
||||
feathers2.build.f_cpu=240000000L
|
||||
feathers2.build.flash_size=16MB
|
||||
@ -992,10 +1001,10 @@ feathers2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
feathers2.menu.CDCOnBoot.default=Disabled
|
||||
feathers2.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
|
||||
feathers2.menu.MSCOnBoot.msc=Enabled
|
||||
feathers2.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
feathers2.menu.MSCOnBoot.default=Disabled
|
||||
feathers2.menu.MSCOnBoot.default.build.msc_on_boot=0
|
||||
feathers2.menu.MSCOnBoot.msc=Enabled
|
||||
feathers2.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
|
||||
feathers2.menu.DFUOnBoot.default=Disabled
|
||||
feathers2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
@ -1092,7 +1101,131 @@ feathers2.menu.DebugLevel.verbose=Verbose
|
||||
feathers2.menu.DebugLevel.verbose.build.code_debug=5
|
||||
|
||||
##############################################################
|
||||
feathers2neo.name=UM FeatherS2 Neo
|
||||
feathers2neo.vid.0=0x303a
|
||||
feathers2neo.pid.0=0x80B4
|
||||
|
||||
feathers2neo.upload.tool=esptool_py
|
||||
feathers2neo.upload.maximum_size=1310720
|
||||
feathers2neo.upload.maximum_data_size=327680
|
||||
feathers2neo.upload.flags=
|
||||
feathers2neo.upload.extra_flags=
|
||||
feathers2neo.upload.use_1200bps_touch=true
|
||||
feathers2neo.upload.wait_for_upload_port=true
|
||||
|
||||
feathers2neo.serial.disableDTR=false
|
||||
feathers2neo.serial.disableRTS=false
|
||||
|
||||
feathers2neo.build.tarch=xtensa
|
||||
feathers2neo.build.bootloader_addr=0x1000
|
||||
feathers2neo.build.target=esp32s2
|
||||
feathers2neo.build.mcu=esp32s2
|
||||
feathers2neo.build.core=esp32
|
||||
feathers2neo.build.variant=um_feathers2neo
|
||||
feathers2neo.build.board=FEATHERS2NEO
|
||||
|
||||
feathers2neo.build.cdc_on_boot=1
|
||||
feathers2neo.build.msc_on_boot=0
|
||||
feathers2neo.build.dfu_on_boot=0
|
||||
feathers2neo.build.f_cpu=240000000L
|
||||
feathers2neo.build.flash_size=4MB
|
||||
feathers2neo.build.flash_freq=80m
|
||||
feathers2neo.build.flash_mode=dio
|
||||
feathers2neo.build.boot=qio
|
||||
feathers2neo.build.partitions=default
|
||||
feathers2neo.build.defines=
|
||||
|
||||
feathers2neo.menu.CDCOnBoot.cdc=Enabled
|
||||
feathers2neo.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
feathers2neo.menu.CDCOnBoot.default=Disabled
|
||||
feathers2neo.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
|
||||
feathers2neo.menu.MSCOnBoot.default=Disabled
|
||||
feathers2neo.menu.MSCOnBoot.default.build.msc_on_boot=0
|
||||
feathers2neo.menu.MSCOnBoot.msc=Enabled
|
||||
feathers2neo.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
|
||||
feathers2neo.menu.DFUOnBoot.default=Disabled
|
||||
feathers2neo.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
feathers2neo.menu.DFUOnBoot.dfu=Enabled
|
||||
feathers2neo.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
|
||||
|
||||
feathers2neo.menu.PSRAM.enabled=Enabled
|
||||
feathers2neo.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
|
||||
feathers2neo.menu.PSRAM.disabled=Disabled
|
||||
feathers2neo.menu.PSRAM.disabled.build.defines=
|
||||
|
||||
feathers2neo.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.default.build.partitions=default
|
||||
feathers2neo.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
|
||||
feathers2neo.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
|
||||
feathers2neo.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.minimal.build.partitions=minimal
|
||||
feathers2neo.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.no_ota.build.partitions=no_ota
|
||||
feathers2neo.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
|
||||
feathers2neo.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
|
||||
feathers2neo.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
|
||||
feathers2neo.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
|
||||
feathers2neo.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
|
||||
feathers2neo.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
|
||||
feathers2neo.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
|
||||
feathers2neo.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
|
||||
feathers2neo.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
|
||||
feathers2neo.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.huge_app.build.partitions=huge_app
|
||||
feathers2neo.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
|
||||
feathers2neo.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
|
||||
feathers2neo.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
|
||||
feathers2neo.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
|
||||
|
||||
feathers2neo.menu.CPUFreq.240=240MHz (WiFi)
|
||||
feathers2neo.menu.CPUFreq.240.build.f_cpu=240000000L
|
||||
feathers2neo.menu.CPUFreq.160=160MHz (WiFi)
|
||||
feathers2neo.menu.CPUFreq.160.build.f_cpu=160000000L
|
||||
feathers2neo.menu.CPUFreq.80=80MHz (WiFi)
|
||||
feathers2neo.menu.CPUFreq.80.build.f_cpu=80000000L
|
||||
feathers2neo.menu.CPUFreq.40=40MHz
|
||||
feathers2neo.menu.CPUFreq.40.build.f_cpu=40000000L
|
||||
feathers2neo.menu.CPUFreq.20=20MHz
|
||||
feathers2neo.menu.CPUFreq.20.build.f_cpu=20000000L
|
||||
feathers2neo.menu.CPUFreq.10=10MHz
|
||||
feathers2neo.menu.CPUFreq.10.build.f_cpu=10000000L
|
||||
|
||||
feathers2neo.menu.FlashSize.4M=4MB (32Mb)
|
||||
feathers2neo.menu.FlashSize.4M.build.flash_size=4MB
|
||||
feathers2neo.menu.FlashSize.2M=2MB (16Mb)
|
||||
feathers2neo.menu.FlashSize.2M.build.flash_size=2MB
|
||||
feathers2neo.menu.FlashSize.2M.build.partitions=minimal
|
||||
|
||||
feathers2neo.menu.UploadSpeed.921600=921600
|
||||
feathers2neo.menu.UploadSpeed.921600.upload.speed=921600
|
||||
feathers2neo.menu.UploadSpeed.115200=115200
|
||||
feathers2neo.menu.UploadSpeed.115200.upload.speed=115200
|
||||
feathers2neo.menu.UploadSpeed.256000.windows=256000
|
||||
feathers2neo.menu.UploadSpeed.256000.upload.speed=256000
|
||||
feathers2neo.menu.UploadSpeed.230400.windows.upload.speed=256000
|
||||
feathers2neo.menu.UploadSpeed.230400=230400
|
||||
feathers2neo.menu.UploadSpeed.230400.upload.speed=230400
|
||||
feathers2neo.menu.UploadSpeed.460800.linux=460800
|
||||
feathers2neo.menu.UploadSpeed.460800.macosx=460800
|
||||
feathers2neo.menu.UploadSpeed.460800.upload.speed=460800
|
||||
|
||||
feathers2neo.menu.DebugLevel.none=None
|
||||
feathers2neo.menu.DebugLevel.none.build.code_debug=0
|
||||
feathers2neo.menu.DebugLevel.error=Error
|
||||
feathers2neo.menu.DebugLevel.error.build.code_debug=1
|
||||
feathers2neo.menu.DebugLevel.warn=Warn
|
||||
feathers2neo.menu.DebugLevel.warn.build.code_debug=2
|
||||
feathers2neo.menu.DebugLevel.info=Info
|
||||
feathers2neo.menu.DebugLevel.info.build.code_debug=3
|
||||
feathers2neo.menu.DebugLevel.debug=Debug
|
||||
feathers2neo.menu.DebugLevel.debug.build.code_debug=4
|
||||
feathers2neo.menu.DebugLevel.verbose=Verbose
|
||||
feathers2neo.menu.DebugLevel.verbose.build.code_debug=5
|
||||
|
||||
##############################################################
|
||||
tinys2.name=UM TinyS2
|
||||
tinys2.vid.0=0x303a
|
||||
tinys2.pid.0=0x8001
|
||||
@ -1117,7 +1250,7 @@ tinys2.build.variant=um_tinys2
|
||||
tinys2.build.board=TINYS2
|
||||
|
||||
tinys2.build.cdc_on_boot=1
|
||||
tinys2.build.msc_on_boot=1
|
||||
tinys2.build.msc_on_boot=0
|
||||
tinys2.build.dfu_on_boot=0
|
||||
tinys2.build.f_cpu=240000000L
|
||||
tinys2.build.flash_size=4MB
|
||||
@ -1132,10 +1265,10 @@ tinys2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
tinys2.menu.CDCOnBoot.default=Disabled
|
||||
tinys2.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
|
||||
tinys2.menu.MSCOnBoot.msc=Enabled
|
||||
tinys2.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
tinys2.menu.MSCOnBoot.default=Disabled
|
||||
tinys2.menu.MSCOnBoot.default.build.msc_on_boot=0
|
||||
tinys2.menu.MSCOnBoot.msc=Enabled
|
||||
tinys2.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
|
||||
tinys2.menu.DFUOnBoot.default=Disabled
|
||||
tinys2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
@ -1204,7 +1337,6 @@ tinys2.menu.UploadSpeed.460800.linux=460800
|
||||
tinys2.menu.UploadSpeed.460800.macosx=460800
|
||||
tinys2.menu.UploadSpeed.460800.upload.speed=460800
|
||||
|
||||
|
||||
tinys2.menu.DebugLevel.none=None
|
||||
tinys2.menu.DebugLevel.none.build.code_debug=0
|
||||
tinys2.menu.DebugLevel.error=Error
|
||||
@ -1225,6 +1357,7 @@ S_ODI_Ultra.upload.tool=esptool_py
|
||||
S_ODI_Ultra.upload.maximum_size=1310720
|
||||
S_ODI_Ultra.upload.maximum_data_size=327680
|
||||
S_ODI_Ultra.upload.wait_for_upload_port=true
|
||||
S_ODI_Ultra.upload.flags=
|
||||
S_ODI_Ultra.upload.extra_flags=
|
||||
|
||||
S_ODI_Ultra.serial.disableDTR=true
|
||||
@ -1931,6 +2064,122 @@ ttgo-t7-v14-mini32.menu.DebugLevel.verbose.build.code_debug=5
|
||||
|
||||
##############################################################
|
||||
|
||||
ttgo-t-oi-plus.name=TTGO T-OI PLUS RISC-V ESP32-C3
|
||||
|
||||
ttgo-t-oi-plus.upload.tool=esptool_py
|
||||
ttgo-t-oi-plus.upload.maximum_size=1310720
|
||||
ttgo-t-oi-plus.upload.maximum_data_size=327680
|
||||
ttgo-t-oi-plus.upload.flags=
|
||||
ttgo-t-oi-plus.upload.extra_flags=
|
||||
|
||||
ttgo-t-oi-plus.serial.disableDTR=false
|
||||
ttgo-t-oi-plus.serial.disableRTS=false
|
||||
|
||||
ttgo-t-oi-plus.build.tarch=riscv32
|
||||
ttgo-t-oi-plus.build.target=esp
|
||||
ttgo-t-oi-plus.build.mcu=esp32c3
|
||||
ttgo-t-oi-plus.build.core=esp32
|
||||
ttgo-t-oi-plus.build.variant=ttgo-t-oi-plus
|
||||
ttgo-t-oi-plus.build.board=TTGO-T-OI-PLUS_DEV
|
||||
ttgo-t-oi-plus.build.bootloader_addr=0x0
|
||||
|
||||
ttgo-t-oi-plus.build.cdc_on_boot=0
|
||||
ttgo-t-oi-plus.build.f_cpu=160000000L
|
||||
ttgo-t-oi-plus.build.flash_size=4MB
|
||||
ttgo-t-oi-plus.build.flash_freq=80m
|
||||
ttgo-t-oi-plus.build.flash_mode=qio
|
||||
ttgo-t-oi-plus.build.boot=qio
|
||||
ttgo-t-oi-plus.build.partitions=default
|
||||
ttgo-t-oi-plus.build.defines=
|
||||
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.default.build.partitions=default
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.minimal.build.partitions=minimal
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.no_ota.build.partitions=no_ota
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.huge_app.build.partitions=huge_app
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
|
||||
ttgo-t-oi-plus.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080
|
||||
|
||||
|
||||
ttgo-t-oi-plus.menu.CPUFreq.160=160MHz (WiFi)
|
||||
ttgo-t-oi-plus.menu.CPUFreq.160.build.f_cpu=160000000L
|
||||
ttgo-t-oi-plus.menu.CPUFreq.80=80MHz (WiFi)
|
||||
ttgo-t-oi-plus.menu.CPUFreq.80.build.f_cpu=80000000L
|
||||
ttgo-t-oi-plus.menu.CPUFreq.40=40MHz
|
||||
ttgo-t-oi-plus.menu.CPUFreq.40.build.f_cpu=40000000L
|
||||
ttgo-t-oi-plus.menu.CPUFreq.20=20MHz
|
||||
ttgo-t-oi-plus.menu.CPUFreq.20.build.f_cpu=20000000L
|
||||
ttgo-t-oi-plus.menu.CPUFreq.10=10MHz
|
||||
ttgo-t-oi-plus.menu.CPUFreq.10.build.f_cpu=10000000L
|
||||
|
||||
ttgo-t-oi-plus.menu.FlashMode.qio=QIO
|
||||
ttgo-t-oi-plus.menu.FlashMode.qio.build.flash_mode=dio
|
||||
ttgo-t-oi-plus.menu.FlashMode.qio.build.boot=qio
|
||||
ttgo-t-oi-plus.menu.FlashMode.dio=DIO
|
||||
ttgo-t-oi-plus.menu.FlashMode.dio.build.flash_mode=dio
|
||||
ttgo-t-oi-plus.menu.FlashMode.dio.build.boot=dio
|
||||
ttgo-t-oi-plus.menu.FlashMode.qout=QOUT
|
||||
ttgo-t-oi-plus.menu.FlashMode.qout.build.flash_mode=dout
|
||||
ttgo-t-oi-plus.menu.FlashMode.qout.build.boot=qout
|
||||
ttgo-t-oi-plus.menu.FlashMode.dout=DOUT
|
||||
ttgo-t-oi-plus.menu.FlashMode.dout.build.flash_mode=dout
|
||||
ttgo-t-oi-plus.menu.FlashMode.dout.build.boot=dout
|
||||
|
||||
ttgo-t-oi-plus.menu.FlashFreq.80=80MHz
|
||||
ttgo-t-oi-plus.menu.FlashFreq.80.build.flash_freq=80m
|
||||
ttgo-t-oi-plus.menu.FlashFreq.40=40MHz
|
||||
ttgo-t-oi-plus.menu.FlashFreq.40.build.flash_freq=40m
|
||||
|
||||
ttgo-t-oi-plus.menu.FlashSize.4M=4MB (32Mb)
|
||||
ttgo-t-oi-plus.menu.FlashSize.4M.build.flash_size=4MB
|
||||
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.921600=921600
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.921600.upload.speed=921600
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.115200=115200
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.115200.upload.speed=115200
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.256000.windows=256000
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.256000.upload.speed=256000
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.230400.windows.upload.speed=256000
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.230400=230400
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.230400.upload.speed=230400
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.460800.linux=460800
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.460800.macosx=460800
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.460800.upload.speed=460800
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.512000.windows=512000
|
||||
ttgo-t-oi-plus.menu.UploadSpeed.512000.upload.speed=512000
|
||||
|
||||
ttgo-t-oi-plus.menu.DebugLevel.none=None
|
||||
ttgo-t-oi-plus.menu.DebugLevel.none.build.code_debug=0
|
||||
ttgo-t-oi-plus.menu.DebugLevel.error=Error
|
||||
ttgo-t-oi-plus.menu.DebugLevel.error.build.code_debug=1
|
||||
ttgo-t-oi-plus.menu.DebugLevel.warn=Warn
|
||||
ttgo-t-oi-plus.menu.DebugLevel.warn.build.code_debug=2
|
||||
ttgo-t-oi-plus.menu.DebugLevel.info=Info
|
||||
ttgo-t-oi-plus.menu.DebugLevel.info.build.code_debug=3
|
||||
ttgo-t-oi-plus.menu.DebugLevel.debug=Debug
|
||||
ttgo-t-oi-plus.menu.DebugLevel.debug.build.code_debug=4
|
||||
ttgo-t-oi-plus.menu.DebugLevel.verbose=Verbose
|
||||
ttgo-t-oi-plus.menu.DebugLevel.verbose.build.code_debug=5
|
||||
|
||||
##############################################################
|
||||
|
||||
cw02.name=XinaBox CW02
|
||||
|
||||
cw02.upload.tool=esptool_py
|
||||
@ -2087,6 +2336,7 @@ esp32thing_plus.upload.tool=esptool_py
|
||||
esp32thing_plus.upload.maximum_size=1310720
|
||||
esp32thing_plus.upload.maximum_data_size=327680
|
||||
esp32thing_plus.upload.wait_for_upload_port=true
|
||||
esp32thing_plus.upload.flags=
|
||||
esp32thing_plus.upload.extra_flags=
|
||||
|
||||
esp32thing_plus.serial.disableDTR=true
|
||||
@ -2315,6 +2565,8 @@ esp32micromod.upload.tool=esptool_py
|
||||
esp32micromod.upload.maximum_size=1310720
|
||||
esp32micromod.upload.maximum_data_size=327680
|
||||
esp32micromod.upload.wait_for_upload_port=true
|
||||
esp32micromod.upload.flags=
|
||||
esp32micromod.upload.extra_flags=
|
||||
|
||||
esp32micromod.serial.disableDTR=true
|
||||
esp32micromod.serial.disableRTS=true
|
||||
@ -2952,6 +3204,7 @@ lolin32-lite.upload.tool=esptool_py
|
||||
lolin32-lite.upload.maximum_size=1310720
|
||||
lolin32-lite.upload.maximum_data_size=327680
|
||||
lolin32-lite.upload.wait_for_upload_port=true
|
||||
lolin32-lite.upload.flags=
|
||||
lolin32-lite.upload.extra_flags=
|
||||
|
||||
lolin32-lite.serial.disableDTR=true
|
||||
@ -3657,6 +3910,13 @@ adafruit_metro_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
adafruit_metro_esp32s2.menu.DFUOnBoot.dfu=Enabled
|
||||
adafruit_metro_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
|
||||
|
||||
adafruit_metro_esp32s2.menu.UploadMode.cdc=Internal USB
|
||||
adafruit_metro_esp32s2.menu.UploadMode.cdc.upload.use_1200bps_touch=true
|
||||
adafruit_metro_esp32s2.menu.UploadMode.cdc.upload.wait_for_upload_port=true
|
||||
adafruit_metro_esp32s2.menu.UploadMode.default=UART0
|
||||
adafruit_metro_esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false
|
||||
adafruit_metro_esp32s2.menu.UploadMode.default.upload.wait_for_upload_port=false
|
||||
|
||||
adafruit_metro_esp32s2.menu.PSRAM.enabled=Enabled
|
||||
adafruit_metro_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
|
||||
adafruit_metro_esp32s2.menu.PSRAM.disabled=Disabled
|
||||
@ -3771,11 +4031,11 @@ adafruit_metro_esp32s2.menu.DebugLevel.verbose.build.code_debug=5
|
||||
|
||||
adafruit_magtag29_esp32s2.name=Adafruit MagTag 2.9"
|
||||
adafruit_magtag29_esp32s2.vid.0=0x239A
|
||||
adafruit_magtag29_esp32s2.pid.0=0x80DF
|
||||
adafruit_magtag29_esp32s2.pid.0=0x80E5
|
||||
adafruit_magtag29_esp32s2.vid.1=0x239A
|
||||
adafruit_magtag29_esp32s2.pid.1=0x00DF
|
||||
adafruit_magtag29_esp32s2.pid.1=0x00E5
|
||||
adafruit_magtag29_esp32s2.vid.1=0x239A
|
||||
adafruit_magtag29_esp32s2.pid.1=0x80E0
|
||||
adafruit_magtag29_esp32s2.pid.1=0x80E6
|
||||
|
||||
adafruit_magtag29_esp32s2.upload.tool=esptool_py
|
||||
adafruit_magtag29_esp32s2.upload.maximum_size=1310720
|
||||
@ -3822,6 +4082,13 @@ adafruit_magtag29_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
adafruit_magtag29_esp32s2.menu.DFUOnBoot.dfu=Enabled
|
||||
adafruit_magtag29_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
|
||||
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.cdc=Internal USB
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.cdc.upload.use_1200bps_touch=true
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.cdc.upload.wait_for_upload_port=true
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.default=UART0
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false
|
||||
adafruit_magtag29_esp32s2.menu.UploadMode.default.upload.wait_for_upload_port=false
|
||||
|
||||
adafruit_magtag29_esp32s2.menu.PSRAM.enabled=Enabled
|
||||
adafruit_magtag29_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
|
||||
adafruit_magtag29_esp32s2.menu.PSRAM.disabled=Disabled
|
||||
@ -3987,6 +4254,13 @@ adafruit_funhouse_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
adafruit_funhouse_esp32s2.menu.DFUOnBoot.dfu=Enabled
|
||||
adafruit_funhouse_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
|
||||
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.cdc=Internal USB
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.cdc.upload.use_1200bps_touch=true
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.cdc.upload.wait_for_upload_port=true
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.default=UART0
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.default.upload.use_1200bps_touch=false
|
||||
adafruit_funhouse_esp32s2.menu.UploadMode.default.upload.wait_for_upload_port=false
|
||||
|
||||
adafruit_funhouse_esp32s2.menu.PSRAM.enabled=Enabled
|
||||
adafruit_funhouse_esp32s2.menu.PSRAM.enabled.build.defines=-DBOARD_HAS_PSRAM
|
||||
adafruit_funhouse_esp32s2.menu.PSRAM.disabled=Disabled
|
||||
@ -4567,6 +4841,7 @@ esp32doit-espduino.upload.tool=esptool
|
||||
esp32doit-espduino.upload.maximum_size=1310720
|
||||
esp32doit-espduino.upload.maximum_data_size=327680
|
||||
esp32doit-espduino.upload.wait_for_upload_port=true
|
||||
esp32doit-espduino.upload.flags=
|
||||
esp32doit-espduino.upload.extra_flags=
|
||||
|
||||
esp32doit-espduino.serial.disableDTR=true
|
||||
@ -5332,6 +5607,7 @@ m5stack-timer-cam.upload.tool=esptool_py
|
||||
m5stack-timer-cam.upload.maximum_size=1310720
|
||||
m5stack-timer-cam.upload.maximum_data_size=327680
|
||||
m5stack-timer-cam.upload.wait_for_upload_port=true
|
||||
m5stack-timer-cam.upload.flags=
|
||||
m5stack-timer-cam.upload.extra_flags=
|
||||
|
||||
m5stack-timer-cam.serial.disableDTR=true
|
||||
@ -5958,6 +6234,7 @@ heltec_wireless_stick_lite.upload.tool=esptool_py
|
||||
heltec_wireless_stick_lite.upload.maximum_size=1310720
|
||||
heltec_wireless_stick_lite.upload.maximum_data_size=327680
|
||||
heltec_wireless_stick_lite.upload.wait_for_upload_port=true
|
||||
heltec_wireless_stick_lite.upload.flags=
|
||||
heltec_wireless_stick_lite.upload.extra_flags=
|
||||
|
||||
heltec_wireless_stick_lite.serial.disableDTR=true
|
||||
@ -7926,6 +8203,7 @@ kits-edu.upload.tool=esptool_py
|
||||
kits-edu.upload.maximum_size=1310720
|
||||
kits-edu.upload.maximum_data_size=327680
|
||||
kits-edu.upload.wait_for_upload_port=true
|
||||
kits-edu.upload.flags=
|
||||
kits-edu.upload.extra_flags=
|
||||
|
||||
kits-edu.serial.disableDTR=true
|
||||
@ -8108,6 +8386,7 @@ OpenKB.upload.tool=esptool_py
|
||||
OpenKB.upload.maximum_size=1310720
|
||||
OpenKB.upload.maximum_data_size=327680
|
||||
OpenKB.upload.wait_for_upload_port=true
|
||||
OpenKB.upload.flags=
|
||||
OpenKB.upload.extra_flags=
|
||||
|
||||
OpenKB.serial.disableDTR=true
|
||||
@ -8156,6 +8435,7 @@ wifiduino32.upload.tool=esptool_py
|
||||
wifiduino32.upload.maximum_size=1310720
|
||||
wifiduino32.upload.maximum_data_size=327680
|
||||
wifiduino32.upload.wait_for_upload_port=true
|
||||
wifiduino32.upload.flags=
|
||||
wifiduino32.upload.extra_flags=
|
||||
|
||||
wifiduino32.serial.disableDTR=true
|
||||
@ -8342,6 +8622,7 @@ imbrios-logsens-v1p1.upload.tool=esptool_py
|
||||
imbrios-logsens-v1p1.upload.maximum_size=1310720
|
||||
imbrios-logsens-v1p1.upload.maximum_data_size=327680
|
||||
imbrios-logsens-v1p1.upload.wait_for_upload_port=true
|
||||
imbrios-logsens-v1p1.upload.flags=
|
||||
imbrios-logsens-v1p1.upload.extra_flags=
|
||||
|
||||
imbrios-logsens-v1p1.serial.disableDTR=true
|
||||
@ -8416,6 +8697,7 @@ healthypi4.upload.tool=esptool_py
|
||||
healthypi4.upload.maximum_size=1310720
|
||||
healthypi4.upload.maximum_data_size=327680
|
||||
healthypi4.upload.wait_for_upload_port=true
|
||||
healthypi4.upload.flags=
|
||||
healthypi4.upload.extra_flags=
|
||||
|
||||
healthypi4.serial.disableDTR=true
|
||||
@ -8487,6 +8769,7 @@ ET-Board.upload.tool=esptool_py
|
||||
ET-Board.upload.maximum_size=1310720
|
||||
ET-Board.upload.maximum_data_size=327680
|
||||
ET-Board.upload.wait_for_upload_port=true
|
||||
ET-Board.upload.flags=
|
||||
ET-Board.upload.extra_flags=
|
||||
|
||||
ET-Board.serial.disableDTR=true
|
||||
@ -8841,6 +9124,8 @@ kb32.upload.tool=esptool_py
|
||||
kb32.upload.maximum_size=1310720
|
||||
kb32.upload.maximum_data_size=327680
|
||||
kb32.upload.wait_for_upload_port=true
|
||||
kb32.upload.flags=
|
||||
kb32.upload.extra_flags=
|
||||
|
||||
kb32.serial.disableDTR=true
|
||||
kb32.serial.disableRTS=true
|
||||
@ -8981,6 +9266,8 @@ deneyapkart.upload.tool=esptool_py
|
||||
deneyapkart.upload.maximum_size=1310720
|
||||
deneyapkart.upload.maximum_data_size=327680
|
||||
deneyapkart.upload.wait_for_upload_port=true
|
||||
deneyapkart.upload.flags=
|
||||
deneyapkart.upload.extra_flags=
|
||||
|
||||
deneyapkart.serial.disableDTR=true
|
||||
deneyapkart.serial.disableRTS=true
|
||||
@ -9229,19 +9516,32 @@ atmegazero_esp32s2.build.core=esp32
|
||||
atmegazero_esp32s2.build.variant=atmegazero_esp32s2
|
||||
atmegazero_esp32s2.build.board=atmegazero_esp32s2
|
||||
|
||||
atmegazero_esp32s2.build.cdc_on_boot=1
|
||||
atmegazero_esp32s2.build.msc_on_boot=0
|
||||
atmegazero_esp32s2.build.dfu_on_boot=0
|
||||
atmegazero_esp32s2.build.serial=0
|
||||
atmegazero_esp32s2.build.f_cpu=240000000L
|
||||
atmegazero_esp32s2.build.flash_size=4MB
|
||||
atmegazero_esp32s2.build.flash_freq=80m
|
||||
atmegazero_esp32s2.build.flash_size=16MB
|
||||
atmegazero_esp32s2.build.flash_freq=40m
|
||||
atmegazero_esp32s2.build.flash_mode=qio
|
||||
atmegazero_esp32s2.build.boot=qio
|
||||
atmegazero_esp32s2.build.partitions=default
|
||||
atmegazero_esp32s2.build.defines=
|
||||
|
||||
atmegazero_esp32s2.menu.SerialMode.cdc=USB CDC
|
||||
atmegazero_esp32s2.menu.SerialMode.cdc.build.serial=1
|
||||
atmegazero_esp32s2.menu.SerialMode.default=UART0
|
||||
atmegazero_esp32s2.menu.SerialMode.default.build.serial=0
|
||||
atmegazero_esp32s2.menu.CDCOnBoot.cdc=Enabled
|
||||
atmegazero_esp32s2.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
atmegazero_esp32s2.menu.CDCOnBoot.default=Disabled
|
||||
atmegazero_esp32s2.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
|
||||
atmegazero_esp32s2.menu.MSCOnBoot.default=Disabled
|
||||
atmegazero_esp32s2.menu.MSCOnBoot.default.build.msc_on_boot=0
|
||||
atmegazero_esp32s2.menu.MSCOnBoot.msc=Enabled
|
||||
atmegazero_esp32s2.menu.MSCOnBoot.msc.build.msc_on_boot=1
|
||||
|
||||
atmegazero_esp32s2.menu.DFUOnBoot.default=Disabled
|
||||
atmegazero_esp32s2.menu.DFUOnBoot.default.build.dfu_on_boot=0
|
||||
atmegazero_esp32s2.menu.DFUOnBoot.dfu=Enabled
|
||||
atmegazero_esp32s2.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
|
||||
|
||||
atmegazero_esp32s2.menu.PSRAM.disabled=Disabled
|
||||
atmegazero_esp32s2.menu.PSRAM.disabled.build.defines=
|
||||
@ -9387,10 +9687,10 @@ deneyapmini.build.boot=qio
|
||||
deneyapmini.build.partitions=default
|
||||
deneyapmini.build.defines=
|
||||
|
||||
deneyapmini.menu.SerialMode.default=USB_CDC
|
||||
deneyapmini.menu.SerialMode.default.build.serial=1
|
||||
deneyapmini.menu.SerialMode.uart=UART0
|
||||
deneyapmini.menu.SerialMode.uart.build.serial=0
|
||||
deneyapmini.menu.CDCOnBoot.default=Disabled
|
||||
deneyapmini.menu.CDCOnBoot.default.build.cdc_on_boot=0
|
||||
deneyapmini.menu.CDCOnBoot.cdc=Enabled
|
||||
deneyapmini.menu.CDCOnBoot.cdc.build.cdc_on_boot=1
|
||||
|
||||
deneyapmini.menu.PSRAM.disabled=Disabled
|
||||
deneyapmini.menu.PSRAM.disabled.build.defines=
|
||||
|
@ -38,6 +38,7 @@ extern "C" {
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing flash size and spi mode
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/spi_flash.h"
|
||||
@ -270,7 +271,17 @@ const char * EspClass::getChipModel(void)
|
||||
return "Unknown";
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
return "ESP32-S2";
|
||||
uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
|
||||
switch (pkg_ver) {
|
||||
case 0:
|
||||
return "ESP32-S2";
|
||||
case 1:
|
||||
return "ESP32-S2FH16";
|
||||
case 2:
|
||||
return "ESP32-S2FH32";
|
||||
default:
|
||||
return "ESP32-S2 (Unknown)";
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
return "ESP32-S3";
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
|
@ -113,6 +113,7 @@ static size_t msc_update_get_required_disk_sectors(){
|
||||
log_d("USING FAT12");
|
||||
mcs_is_fat16 = false;
|
||||
}
|
||||
log_d("FAT sector size: %u", DISK_SECTOR_SIZE);
|
||||
log_d("FAT data sectors: %u", data_sectors);
|
||||
log_d("FAT table sectors: %u", msc_table_sectors);
|
||||
log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024);
|
||||
@ -227,7 +228,7 @@ static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t off
|
||||
//called when error was encountered while updating
|
||||
static void msc_update_error(){
|
||||
log_e("UPDATE_ERROR: %u", msc_update_bytes_written);
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.error.size = msc_update_bytes_written;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
msc_update_state = MSC_UPDATE_IDLE;
|
||||
@ -251,7 +252,7 @@ static void msc_update_end(){
|
||||
msc_update_error();
|
||||
return;
|
||||
}
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.end.size = msc_update_entry->file_size;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
@ -289,7 +290,7 @@ static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_
|
||||
}
|
||||
} else if(msc_ota_partition && lba >= msc_update_start_sector){
|
||||
//handle writes to the region where the new firmware will be uploaded
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){
|
||||
msc_update_state = MSC_UPDATE_RUNNING;
|
||||
msc_update_start_sector = lba;
|
||||
@ -345,7 +346,7 @@ static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bu
|
||||
|
||||
static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){
|
||||
//log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject);
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
arduino_firmware_msc_event_data_t p;
|
||||
p.power.power_condition = power_condition;
|
||||
p.power.start = start;
|
||||
p.power.load_eject = load_eject;
|
||||
|
388
cores/esp32/HWCDC.cpp
Normal file
388
cores/esp32/HWCDC.cpp
Normal file
@ -0,0 +1,388 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USB.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "HWCDC.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "hal/usb_serial_jtag_ll.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS);
|
||||
|
||||
static RingbufHandle_t tx_ring_buf = NULL;
|
||||
static xQueueHandle rx_queue = NULL;
|
||||
static uint8_t rx_data_buf[64];
|
||||
static intr_handle_t intr_handle = NULL;
|
||||
static volatile bool initial_empty = false;
|
||||
static xSemaphoreHandle tx_lock = NULL;
|
||||
static uint32_t tx_timeout_ms = 200;
|
||||
static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL;
|
||||
|
||||
static esp_err_t arduino_hw_cdc_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, BaseType_t *task_unblocked){
|
||||
if(arduino_hw_cdc_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_isr_post_to(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_data, event_data_size, task_unblocked);
|
||||
}
|
||||
|
||||
static esp_err_t arduino_hw_cdc_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){
|
||||
if (!arduino_hw_cdc_event_loop_handle) {
|
||||
esp_event_loop_args_t event_task_args = {
|
||||
.queue_size = 5,
|
||||
.task_name = "arduino_hw_cdc_events",
|
||||
.task_priority = 5,
|
||||
.task_stack_size = 2048,
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
if (esp_event_loop_create(&event_task_args, &arduino_hw_cdc_event_loop_handle) != ESP_OK) {
|
||||
log_e("esp_event_loop_create failed");
|
||||
}
|
||||
}
|
||||
if(arduino_hw_cdc_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_handler_register_with(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
static void hw_cdc_isr_handler(void *arg) {
|
||||
portBASE_TYPE xTaskWoken = 0;
|
||||
uint32_t usbjtag_intr_status = 0;
|
||||
arduino_hw_cdc_event_data_t event = {0};
|
||||
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) {
|
||||
// Interrupt tells us the host picked up the data we sent.
|
||||
if (usb_serial_jtag_ll_txfifo_writable() == 1) {
|
||||
// We disable the interrupt here so that the interrupt won't be triggered if there is no data to send.
|
||||
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
|
||||
if(!initial_empty){
|
||||
initial_empty = true;
|
||||
//send event?
|
||||
//ets_printf("CONNECTED\n");
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
size_t queued_size;
|
||||
uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64);
|
||||
// If the hardware fifo is avaliable, write in it. Otherwise, do nothing.
|
||||
if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called.
|
||||
//Copy the queued buffer into the TX FIFO
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size);
|
||||
usb_serial_jtag_ll_txfifo_flush();
|
||||
vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken);
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
//send event?
|
||||
//ets_printf("TX:%u\n", queued_size);
|
||||
event.tx.len = queued_size;
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_TX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
} else {
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
|
||||
// read rx buffer(max length is 64), and send avaliable data to ringbuffer.
|
||||
// Ensure the rx buffer size is larger than RX_MAX_SIZE.
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
|
||||
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rx_data_buf, 64);
|
||||
uint32_t i=0;
|
||||
for(i=0; i<rx_fifo_len; i++){
|
||||
if(rx_queue == NULL || !xQueueSendFromISR(rx_queue, rx_data_buf+i, &xTaskWoken)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
//send event?
|
||||
//ets_printf("RX:%u/%u\n", i, rx_fifo_len);
|
||||
event.rx.len = i;
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
|
||||
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
initial_empty = false;
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
//ets_printf("BUS_RESET\n");
|
||||
arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken);
|
||||
}
|
||||
|
||||
if (xTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c) {
|
||||
if(xPortInIsrContext()){
|
||||
xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL);
|
||||
} else {
|
||||
xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
|
||||
HWCDC::HWCDC() {
|
||||
|
||||
}
|
||||
|
||||
HWCDC::~HWCDC(){
|
||||
end();
|
||||
}
|
||||
|
||||
HWCDC::operator bool() const
|
||||
{
|
||||
return initial_empty;
|
||||
}
|
||||
|
||||
void HWCDC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_HW_CDC_ANY_EVENT, callback);
|
||||
}
|
||||
|
||||
void HWCDC::onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback){
|
||||
arduino_hw_cdc_event_handler_register_with(ARDUINO_HW_CDC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
void HWCDC::begin(unsigned long baud)
|
||||
{
|
||||
if(tx_lock == NULL) {
|
||||
tx_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
setRxBufferSize(256);//default if not preset
|
||||
setTxBufferSize(256);//default if not preset
|
||||
|
||||
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){
|
||||
isr_log_e("HW USB CDC failed to init interrupts");
|
||||
end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDC::end()
|
||||
{
|
||||
//Disable tx/rx interrupt.
|
||||
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET);
|
||||
esp_intr_free(intr_handle);
|
||||
intr_handle = NULL;
|
||||
if(tx_lock != NULL) {
|
||||
vSemaphoreDelete(tx_lock);
|
||||
}
|
||||
setRxBufferSize(0);
|
||||
setTxBufferSize(0);
|
||||
if (arduino_hw_cdc_event_loop_handle) {
|
||||
esp_event_loop_delete(arduino_hw_cdc_event_loop_handle);
|
||||
arduino_hw_cdc_event_loop_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void HWCDC::setTxTimeoutMs(uint32_t timeout){
|
||||
tx_timeout_ms = timeout;
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
size_t HWCDC::setTxBufferSize(size_t tx_queue_len){
|
||||
if(tx_ring_buf){
|
||||
if(!tx_queue_len){
|
||||
vRingbufferDelete(tx_ring_buf);
|
||||
tx_ring_buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF);
|
||||
if(!tx_ring_buf){
|
||||
return 0;
|
||||
}
|
||||
return tx_queue_len;
|
||||
}
|
||||
|
||||
int HWCDC::availableForWrite(void)
|
||||
{
|
||||
if(tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t a = xRingbufferGetCurFreeSize(tx_ring_buf);
|
||||
xSemaphoreGive(tx_lock);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t HWCDC::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t max_size = xRingbufferGetMaxItemSize(tx_ring_buf);
|
||||
size_t space = xRingbufferGetCurFreeSize(tx_ring_buf);
|
||||
size_t to_send = size, so_far = 0;
|
||||
|
||||
if(space > size){
|
||||
space = size;
|
||||
}
|
||||
// Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR.
|
||||
if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){
|
||||
size = 0;
|
||||
} else {
|
||||
to_send -= space;
|
||||
so_far += space;
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
|
||||
while(to_send){
|
||||
if(max_size > to_send){
|
||||
max_size = to_send;
|
||||
}
|
||||
// Blocking method, Sending data to ringbuffer, and handle the data in ISR.
|
||||
if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
|
||||
size = so_far;
|
||||
break;
|
||||
}
|
||||
so_far += max_size;
|
||||
to_send -= max_size;
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(tx_lock);
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t HWCDC::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
}
|
||||
|
||||
void HWCDC::flush(void)
|
||||
{
|
||||
if(tx_ring_buf == NULL || tx_lock == NULL){
|
||||
return;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return;
|
||||
}
|
||||
UBaseType_t uxItemsWaiting = 0;
|
||||
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
if(uxItemsWaiting){
|
||||
// Now trigger the ISR to read data from the ring buffer.
|
||||
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY);
|
||||
}
|
||||
while(uxItemsWaiting){
|
||||
delay(5);
|
||||
vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting);
|
||||
}
|
||||
xSemaphoreGive(tx_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* READING
|
||||
*/
|
||||
|
||||
size_t HWCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
if(rx_queue){
|
||||
if(!rx_queue_len){
|
||||
vQueueDelete(rx_queue);
|
||||
rx_queue = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
|
||||
if(!rx_queue){
|
||||
return 0;
|
||||
}
|
||||
if(!tx_ring_buf){
|
||||
tx_ring_buf = xRingbufferCreate(rx_queue_len, RINGBUF_TYPE_BYTEBUF);
|
||||
}
|
||||
return rx_queue_len;
|
||||
}
|
||||
|
||||
int HWCDC::available(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
return uxQueueMessagesWaiting(rx_queue);
|
||||
}
|
||||
|
||||
int HWCDC::peek(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c;
|
||||
if(xQueuePeek(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int HWCDC::read(void)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
if(xQueueReceive(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t HWCDC::read(uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
size_t count = 0;
|
||||
while(count < size && xQueueReceive(rx_queue, &c, 0)){
|
||||
buffer[count++] = c;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* DEBUG
|
||||
*/
|
||||
|
||||
void HWCDC::setDebugOutput(bool en)
|
||||
{
|
||||
if(en) {
|
||||
uartSetDebug(NULL);
|
||||
ets_install_putc1((void (*)(char)) &cdc0_write_char);
|
||||
} else {
|
||||
ets_install_putc1(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#if ARDUINO_HW_CDC_ON_BOOT //Serial used for USB CDC
|
||||
HWCDC Serial;
|
||||
#else
|
||||
HWCDC USBSerial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_TINYUSB_CDC_ENABLED */
|
107
cores/esp32/HWCDC.h
Normal file
107
cores/esp32/HWCDC.h
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_event.h"
|
||||
#include "Stream.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_HW_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_HW_CDC_CONNECTED_EVENT = 0,
|
||||
ARDUINO_HW_CDC_BUS_RESET_EVENT,
|
||||
ARDUINO_HW_CDC_RX_EVENT,
|
||||
ARDUINO_HW_CDC_TX_EVENT,
|
||||
ARDUINO_HW_CDC_MAX_EVENT,
|
||||
} arduino_hw_cdc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t len;
|
||||
} rx;
|
||||
struct {
|
||||
size_t len;
|
||||
} tx;
|
||||
} arduino_hw_cdc_event_data_t;
|
||||
|
||||
class HWCDC: public Stream
|
||||
{
|
||||
public:
|
||||
HWCDC();
|
||||
~HWCDC();
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback);
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
size_t setTxBufferSize(size_t);
|
||||
void setTxTimeoutMs(uint32_t timeout);
|
||||
void begin(unsigned long baud=0);
|
||||
void end();
|
||||
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
size_t read(uint8_t *buffer, size_t size);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush(void);
|
||||
|
||||
inline size_t read(char * buffer, size_t size)
|
||||
{
|
||||
return read((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * buffer, size_t size)
|
||||
{
|
||||
return write((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
operator bool() const;
|
||||
void setDebugOutput(bool);
|
||||
uint32_t baudRate(){return 115200;}
|
||||
|
||||
};
|
||||
|
||||
#if ARDUINO_HW_CDC_ON_BOOT //Serial used for USB CDC
|
||||
extern HWCDC Serial;
|
||||
#else
|
||||
extern HWCDC USBSerial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32C3 */
|
@ -76,6 +76,8 @@ void serialEvent2(void) {}
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
HardwareSerial Serial0(0);
|
||||
#elif ARDUINO_HW_CDC_ON_BOOT
|
||||
HardwareSerial Serial0(0);
|
||||
#else
|
||||
HardwareSerial Serial(0);
|
||||
#endif
|
||||
@ -85,12 +87,13 @@ HardwareSerial Serial1(1);
|
||||
#if SOC_UART_NUM > 2
|
||||
HardwareSerial Serial2(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEventRun(void)
|
||||
{
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
if(Serial0.available()) serialEvent();
|
||||
#elif ARDUINO_HW_CDC_ON_BOOT
|
||||
if(Serial0.available()) serialEvent();
|
||||
#else
|
||||
if(Serial.available()) serialEvent();
|
||||
#endif
|
||||
@ -101,9 +104,10 @@ void serialEventRun(void)
|
||||
if(Serial2.available()) serialEvent2();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
|
||||
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256) {}
|
||||
|
||||
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
|
||||
{
|
||||
@ -133,7 +137,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
}
|
||||
#endif
|
||||
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
|
||||
if (!baud) {
|
||||
// using baud rate as zero, forces it to try to detect the current baud rate in place
|
||||
uartStartDetectBaudrate(_uart);
|
||||
@ -147,7 +151,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
|
||||
if(detectedBaudRate) {
|
||||
delay(100); // Give some time...
|
||||
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
||||
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
|
||||
} else {
|
||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||
_uart = NULL;
|
||||
@ -268,3 +272,18 @@ void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
|
||||
uartSetPins(_uart, rxPin, txPin);
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
||||
|
||||
if (_uart) {
|
||||
log_e("RX Buffer can't be resized when Serial is already running.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (new_size <= SOC_UART_FIFO_LEN) {
|
||||
log_e("RX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_rxBufferSize = new_size;
|
||||
return _rxBufferSize;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "Stream.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "HWCDC.h"
|
||||
|
||||
class HardwareSerial: public Stream
|
||||
{
|
||||
@ -103,10 +104,12 @@ public:
|
||||
|
||||
void setRxInvert(bool);
|
||||
void setPins(uint8_t rxPin, uint8_t txPin);
|
||||
size_t setRxBufferSize(size_t new_size);
|
||||
|
||||
protected:
|
||||
int _uart_nr;
|
||||
uart_t* _uart;
|
||||
size_t _rxBufferSize;
|
||||
};
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
@ -119,6 +122,8 @@ extern void serialEventRun(void) __attribute__((weak));
|
||||
#include "USB.h"
|
||||
#include "USBCDC.h"
|
||||
extern HardwareSerial Serial0;
|
||||
#elif ARDUINO_HW_CDC_ON_BOOT
|
||||
extern HardwareSerial Serial0;
|
||||
#else
|
||||
extern HardwareSerial Serial;
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#if CONFIG_TINYUSB_ENABLED
|
||||
|
||||
#include "pins_arduino.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "common/tusb_common.h"
|
||||
@ -85,14 +86,14 @@ static bool tinyusb_device_suspended = false;
|
||||
// Invoked when device is mounted (configured)
|
||||
void tud_mount_cb(void){
|
||||
tinyusb_device_mounted = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void){
|
||||
tinyusb_device_mounted = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
@ -100,7 +101,7 @@ void tud_umount_cb(void){
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
void tud_suspend_cb(bool remote_wakeup_en){
|
||||
tinyusb_device_suspended = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_data_t p;
|
||||
p.suspend.remote_wakeup_en = remote_wakeup_en;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
@ -108,7 +109,7 @@ void tud_suspend_cb(bool remote_wakeup_en){
|
||||
// Invoked when usb bus is resumed
|
||||
void tud_resume_cb(void){
|
||||
tinyusb_device_suspended = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
@ -62,63 +62,40 @@ void tud_cdc_rx_cb(uint8_t itf)
|
||||
|
||||
// Invoked when received send break
|
||||
void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){
|
||||
//isr_log_v("itf: %u, duration_ms: %u", itf, duration_ms);
|
||||
//log_v("itf: %u, duration_ms: %u", itf, duration_ms);
|
||||
}
|
||||
|
||||
// Invoked when space becomes available in TX buffer
|
||||
void tud_cdc_tx_complete_cb(uint8_t itf){
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL && devices[itf]->tx_sem != NULL){
|
||||
xSemaphoreGive(devices[itf]->tx_sem);
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onTX();
|
||||
}
|
||||
}
|
||||
|
||||
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
|
||||
if(itf >= MAX_USB_CDC_DEVICES || devices[itf] == NULL || devices[itf]->tx_sem == NULL){
|
||||
return 0;
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c){
|
||||
if(devices[0] != NULL){
|
||||
devices[0]->write(c);
|
||||
}
|
||||
if(!tud_cdc_n_connected(itf)){
|
||||
return 0;
|
||||
}
|
||||
size_t tosend = size, sofar = 0;
|
||||
while(tosend){
|
||||
uint32_t space = tud_cdc_n_write_available(itf);
|
||||
if(!space){
|
||||
//make sure that we do not get previous semaphore
|
||||
xSemaphoreTake(devices[itf]->tx_sem, 0);
|
||||
//wait for tx_complete
|
||||
if(xSemaphoreTake(devices[itf]->tx_sem, 200 / portTICK_PERIOD_MS) == pdTRUE){
|
||||
space = tud_cdc_n_write_available(itf);
|
||||
}
|
||||
if(!space){
|
||||
return sofar;
|
||||
}
|
||||
}
|
||||
if(tosend < space){
|
||||
space = tosend;
|
||||
}
|
||||
uint32_t sent = tud_cdc_n_write(itf, buffer + sofar, space);
|
||||
if(!sent){
|
||||
return sofar;
|
||||
}
|
||||
sofar += sent;
|
||||
tosend -= sent;
|
||||
tud_cdc_n_write_flush(itf);
|
||||
//xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY);
|
||||
}
|
||||
return sofar;
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
|
||||
{
|
||||
tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
|
||||
}
|
||||
|
||||
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
((USBCDC*)arg)->_onUnplugged();
|
||||
}
|
||||
|
||||
USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_sem(NULL) {
|
||||
USBCDC::USBCDC(uint8_t itfn)
|
||||
: itf(itfn)
|
||||
, bit_rate(0)
|
||||
, stop_bits(0)
|
||||
, parity(0)
|
||||
, data_bits(0)
|
||||
, dtr(false)
|
||||
, rts(false)
|
||||
, connected(false)
|
||||
, reboot_enable(true)
|
||||
, rx_queue(NULL)
|
||||
, tx_lock(NULL)
|
||||
, tx_timeout_ms(250)
|
||||
{
|
||||
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
|
||||
if(itf < MAX_USB_CDC_DEVICES){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
|
||||
@ -153,9 +130,8 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
|
||||
void USBCDC::begin(unsigned long baud)
|
||||
{
|
||||
if(tx_sem == NULL){
|
||||
tx_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreTake(tx_sem, 0);
|
||||
if(tx_lock == NULL) {
|
||||
tx_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
setRxBufferSize(256);//default if not preset
|
||||
devices[itf] = this;
|
||||
@ -166,18 +142,21 @@ void USBCDC::end()
|
||||
connected = false;
|
||||
devices[itf] = NULL;
|
||||
setRxBufferSize(0);
|
||||
if (tx_sem != NULL) {
|
||||
vSemaphoreDelete(tx_sem);
|
||||
tx_sem = NULL;
|
||||
if(tx_lock != NULL) {
|
||||
vSemaphoreDelete(tx_lock);
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::setTxTimeoutMs(uint32_t timeout){
|
||||
tx_timeout_ms = timeout;
|
||||
}
|
||||
|
||||
void USBCDC::_onUnplugged(void){
|
||||
if(connected){
|
||||
connected = false;
|
||||
dtr = false;
|
||||
rts = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
@ -199,7 +178,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
lineState++;
|
||||
if(connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
} else {
|
||||
@ -229,14 +208,14 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
if(dtr && rts && !connected){
|
||||
connected = true;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
} else if(!dtr && connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
arduino_usb_cdc_event_data_t l = {0};
|
||||
arduino_usb_cdc_event_data_t l;
|
||||
l.line_state.dtr = dtr;
|
||||
l.line_state.rts = rts;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
@ -254,7 +233,7 @@ void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _pari
|
||||
data_bits = _data_bits;
|
||||
stop_bits = _stop_bits;
|
||||
parity = _parity;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
p.line_coding.bit_rate = bit_rate;
|
||||
p.line_coding.data_bits = data_bits;
|
||||
p.line_coding.stop_bits = stop_bits;
|
||||
@ -272,13 +251,13 @@ void USBCDC::_onRX(){
|
||||
return;
|
||||
}
|
||||
}
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
p.rx.len = count;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
void USBCDC::_onTX(){
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_cdc_event_data_t p;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_TX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
@ -336,23 +315,73 @@ size_t USBCDC::read(uint8_t *buffer, size_t size)
|
||||
|
||||
void USBCDC::flush(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){
|
||||
return;
|
||||
}
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return;
|
||||
}
|
||||
tud_cdc_n_write_flush(itf);
|
||||
xSemaphoreGive(tx_lock);
|
||||
}
|
||||
|
||||
int USBCDC::availableForWrite(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
|
||||
return -1;
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){
|
||||
return 0;
|
||||
}
|
||||
return tud_cdc_n_write_available(itf);
|
||||
if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t a = tud_cdc_n_write_available(itf);
|
||||
xSemaphoreGive(tx_lock);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t USBCDC::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
return tinyusb_cdc_write(itf, buffer, size);
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)){
|
||||
return 0;
|
||||
}
|
||||
if(xPortInIsrContext()){
|
||||
BaseType_t taskWoken = false;
|
||||
if(xSemaphoreTakeFromISR(tx_lock, &taskWoken) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
} else if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){
|
||||
return 0;
|
||||
}
|
||||
size_t to_send = size, so_far = 0;
|
||||
while(to_send){
|
||||
if(!tud_cdc_n_connected(itf)){
|
||||
size = so_far;
|
||||
break;
|
||||
}
|
||||
size_t space = tud_cdc_n_write_available(itf);
|
||||
if(!space){
|
||||
tud_cdc_n_write_flush(itf);
|
||||
continue;
|
||||
}
|
||||
if(space > to_send){
|
||||
space = to_send;
|
||||
}
|
||||
size_t sent = tud_cdc_n_write(itf, buffer+so_far, space);
|
||||
if(sent){
|
||||
so_far += sent;
|
||||
to_send -= sent;
|
||||
tud_cdc_n_write_flush(itf);
|
||||
} else {
|
||||
size = so_far;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(xPortInIsrContext()){
|
||||
BaseType_t taskWoken = false;
|
||||
xSemaphoreGiveFromISR(tx_lock, &taskWoken);
|
||||
} else {
|
||||
xSemaphoreGive(tx_lock);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t USBCDC::write(uint8_t c)
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_event.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "Stream.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
@ -58,7 +61,8 @@ public:
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
size_t setRxBufferSize(size_t size);
|
||||
void setTxTimeoutMs(uint32_t timeout);
|
||||
void begin(unsigned long baud=0);
|
||||
void end();
|
||||
|
||||
@ -113,7 +117,6 @@ public:
|
||||
void _onRX(void);
|
||||
void _onTX(void);
|
||||
void _onUnplugged(void);
|
||||
xSemaphoreHandle tx_sem;
|
||||
|
||||
protected:
|
||||
uint8_t itf;
|
||||
@ -126,6 +129,8 @@ protected:
|
||||
bool connected;
|
||||
bool reboot_enable;
|
||||
xQueueHandle rx_queue;
|
||||
xSemaphoreHandle tx_lock;
|
||||
uint32_t tx_timeout_ms;
|
||||
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,12 @@ String::String(const char *cstr) {
|
||||
copy(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
String::String(const char *cstr, unsigned int length) {
|
||||
init();
|
||||
if (cstr)
|
||||
copy(cstr, length);
|
||||
}
|
||||
|
||||
String::String(const String &value) {
|
||||
init();
|
||||
*this = value;
|
||||
@ -705,10 +711,7 @@ String String::substring(unsigned int left, unsigned int right) const {
|
||||
return out;
|
||||
if(right > len())
|
||||
right = len();
|
||||
char temp = buffer()[right]; // save the replaced character
|
||||
wbuffer()[right] = '\0';
|
||||
out = wbuffer() + left; // pointer arithmetic
|
||||
wbuffer()[right] = temp; //restore character
|
||||
out.copy(buffer() + left, right - left);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,10 @@ class String {
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const char *cstr, unsigned int length);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {}
|
||||
#endif
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
@ -108,6 +112,8 @@ class String {
|
||||
// concatenation is considered unsuccessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);}
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char c);
|
||||
unsigned char concat(int num);
|
||||
@ -326,7 +332,6 @@ class String {
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
|
@ -37,7 +37,7 @@ static uint8_t __analogVRefPin = 0;
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#else
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
@ -46,10 +46,23 @@ static uint8_t __analogVRefPin = 0;
|
||||
#endif
|
||||
|
||||
static uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = 3;//12 bits
|
||||
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2
|
||||
static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP32C3; 13 for ESP32S2
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
|
||||
|
||||
static inline uint16_t mapResolution(uint16_t value)
|
||||
{
|
||||
uint8_t from = __analogWidth + 9;
|
||||
if (from == __analogReturnedWidth) {
|
||||
return value;
|
||||
}
|
||||
if (from > __analogReturnedWidth) {
|
||||
return value >> (from - __analogReturnedWidth);
|
||||
}
|
||||
return value << (__analogReturnedWidth - from);
|
||||
}
|
||||
|
||||
void __analogSetClockDiv(uint8_t clockDiv){
|
||||
if(!clockDiv){
|
||||
clockDiv = 1;
|
||||
@ -146,6 +159,7 @@ void __analogReadResolution(uint8_t bits)
|
||||
if(!bits || bits > 16){
|
||||
return;
|
||||
}
|
||||
__analogReturnedWidth = bits;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
__analogSetWidth(bits); // hadware from 9 to 12
|
||||
#endif
|
||||
@ -165,7 +179,7 @@ uint16_t __analogRead(uint8_t pin)
|
||||
channel -= 10;
|
||||
r = adc2_get_raw( channel, __analogWidth, &value);
|
||||
if ( r == ESP_OK ) {
|
||||
return value;
|
||||
return mapResolution(value);
|
||||
} else if ( r == ESP_ERR_INVALID_STATE ) {
|
||||
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
|
||||
} else if ( r == ESP_ERR_TIMEOUT ) {
|
||||
@ -174,9 +188,10 @@ uint16_t __analogRead(uint8_t pin)
|
||||
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
|
||||
}
|
||||
} else {
|
||||
return adc1_get_raw(channel);
|
||||
value = adc1_get_raw(channel);
|
||||
return mapResolution(value);
|
||||
}
|
||||
return value;
|
||||
return mapResolution(value);
|
||||
}
|
||||
|
||||
uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
|
848
cores/esp32/esp32-hal-i2c-slave.c
Executable file
848
cores/esp32/esp32-hal-i2c-slave.c
Executable file
@ -0,0 +1,848 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "hal/i2c_ll.h"
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-i2c-slave.h"
|
||||
|
||||
#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
|
||||
#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0))
|
||||
#else
|
||||
#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX
|
||||
#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA
|
||||
#define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA
|
||||
#endif
|
||||
|
||||
enum {
|
||||
I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX
|
||||
};
|
||||
|
||||
typedef struct i2c_slave_struct_t {
|
||||
i2c_dev_t * dev;
|
||||
uint8_t num;
|
||||
int8_t sda;
|
||||
int8_t scl;
|
||||
i2c_slave_request_cb_t request_callback;
|
||||
i2c_slave_receive_cb_t receive_callback;
|
||||
void * arg;
|
||||
intr_handle_t intr_handle;
|
||||
TaskHandle_t task_handle;
|
||||
xQueueHandle event_queue;
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
xQueueHandle rx_queue;
|
||||
#else
|
||||
RingbufHandle_t rx_ring_buf;
|
||||
#endif
|
||||
xQueueHandle tx_queue;
|
||||
uint32_t rx_data_count;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
} i2c_slave_struct_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t event : 2;
|
||||
uint32_t stop : 1;
|
||||
uint32_t param : 29;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2c_slave_queue_event_t;
|
||||
|
||||
static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = {
|
||||
{ &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
, NULL
|
||||
#endif
|
||||
},
|
||||
#if SOC_I2C_NUM > 1
|
||||
{ &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
, NULL
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define I2C_SLAVE_MUTEX_LOCK()
|
||||
#define I2C_SLAVE_MUTEX_UNLOCK()
|
||||
#else
|
||||
#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);}
|
||||
#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);}
|
||||
#endif
|
||||
|
||||
//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------
|
||||
typedef enum {
|
||||
I2C_STRETCH_CAUSE_MASTER_READ,
|
||||
I2C_STRETCH_CAUSE_TX_FIFO_EMPTY,
|
||||
I2C_STRETCH_CAUSE_RX_FIFO_FULL,
|
||||
I2C_STRETCH_CAUSE_MAX
|
||||
} i2c_stretch_cause_t;
|
||||
|
||||
static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.stretch_cause;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
return hw->status_reg.stretch_cause;
|
||||
#else
|
||||
return I2C_STRETCH_CAUSE_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2c_ll_set_stretch(i2c_dev_t *hw, uint16_t time)
|
||||
{
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
typeof(hw->scl_stretch_conf) scl_stretch_conf;
|
||||
scl_stretch_conf.val = 0;
|
||||
scl_stretch_conf.slave_scl_stretch_en = (time > 0);
|
||||
scl_stretch_conf.stretch_protect_num = time;
|
||||
scl_stretch_conf.slave_scl_stretch_clr = 1;
|
||||
hw->scl_stretch_conf.val = scl_stretch_conf.val;
|
||||
if(time > 0){
|
||||
//enable interrupt
|
||||
hw->int_ena.val |= I2C_SLAVE_STRETCH_INT_ENA;
|
||||
} else {
|
||||
//disable interrupt
|
||||
hw->int_ena.val &= (~I2C_SLAVE_STRETCH_INT_ENA);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void i2c_ll_stretch_clr(i2c_dev_t *hw)
|
||||
{
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
hw->scl_stretch_conf.slave_scl_stretch_clr = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.slave_addressed;
|
||||
#else
|
||||
return hw->status_reg.slave_addressed;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
return hw->sr.slave_rw;
|
||||
#else
|
||||
return hw->status_reg.slave_rw;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------
|
||||
static void i2c_slave_free_resources(i2c_slave_struct_t * i2c);
|
||||
static void i2c_slave_delay_us(uint64_t us);
|
||||
static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode);
|
||||
static bool i2c_slave_check_line_state(int8_t sda, int8_t scl);
|
||||
static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl);
|
||||
static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c);
|
||||
static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed);
|
||||
static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event);
|
||||
static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c);
|
||||
static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len);
|
||||
static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len);
|
||||
static void i2c_slave_isr_handler(void* arg);
|
||||
static void i2c_slave_task(void *pv_args);
|
||||
|
||||
|
||||
//=====================================================================================================================
|
||||
//-------------------------------------- Public Functions -------------------------------------------------------------
|
||||
//=====================================================================================================================
|
||||
|
||||
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg){
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
i2c->request_callback = request_callback;
|
||||
i2c->receive_callback = receive_callback;
|
||||
i2c->arg = arg;
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) {
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (sda < 0 || scl < 0) {
|
||||
log_e("invalid pins sda=%d, scl=%d", sda, scl);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if(!frequency){
|
||||
frequency = 100000;
|
||||
} else if(frequency > 1000000){
|
||||
frequency = 1000000;
|
||||
}
|
||||
|
||||
log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID);
|
||||
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(!i2c->lock){
|
||||
i2c->lock = xSemaphoreCreateMutex();
|
||||
if (i2c->lock == NULL) {
|
||||
log_e("RX queue create failed");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
i2c_slave_free_resources(i2c);
|
||||
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t));
|
||||
if (i2c->rx_queue == NULL) {
|
||||
log_e("RX queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
i2c->rx_ring_buf = xRingbufferCreate(rx_len, RINGBUF_TYPE_BYTEBUF);
|
||||
if (i2c->rx_ring_buf == NULL) {
|
||||
log_e("RX RingBuf create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2c->tx_queue = xQueueCreate(tx_len, sizeof(uint8_t));
|
||||
if (i2c->tx_queue == NULL) {
|
||||
log_e("TX queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i2c->event_queue = xQueueCreate(16, sizeof(i2c_slave_queue_event_t));
|
||||
if (i2c->event_queue == NULL) {
|
||||
log_e("Event queue create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
xTaskCreate(i2c_slave_task, "i2c_slave_task", 4096, i2c, 20, &i2c->task_handle);
|
||||
if(i2c->task_handle == NULL){
|
||||
log_e("Event thread create failed");
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (frequency == 0) {
|
||||
frequency = 100000L;
|
||||
}
|
||||
frequency = (frequency * 5) / 4;
|
||||
|
||||
if (i2c->num == 0) {
|
||||
periph_module_enable(PERIPH_I2C0_MODULE);
|
||||
#if SOC_I2C_NUM > 1
|
||||
} else {
|
||||
periph_module_enable(PERIPH_I2C1_MODULE);
|
||||
#endif
|
||||
}
|
||||
|
||||
i2c_ll_slave_init(i2c->dev);
|
||||
i2c_ll_set_fifo_mode(i2c->dev, true);
|
||||
i2c_ll_set_slave_addr(i2c->dev, slaveID, false);
|
||||
i2c_ll_set_tout(i2c->dev, 32000);
|
||||
i2c_slave_set_frequency(i2c, frequency);
|
||||
|
||||
if (!i2c_slave_check_line_state(sda, scl)) {
|
||||
log_e("bad pin state");
|
||||
ret = ESP_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i2c_slave_attach_gpio(i2c, sda, scl);
|
||||
|
||||
if (i2c_ll_is_bus_busy(i2c->dev)) {
|
||||
log_w("Bus busy, reinit");
|
||||
ret = ESP_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
|
||||
i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK);
|
||||
i2c_ll_set_fifo_mode(i2c->dev, true);
|
||||
|
||||
if (!i2c->intr_handle) {
|
||||
uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED;
|
||||
if(i2c->num == 0) {
|
||||
ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
|
||||
#if SOC_I2C_NUM > 1
|
||||
} else {
|
||||
ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
log_e("install interrupt handler Failed=%d", ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_ll_txfifo_rst(i2c->dev);
|
||||
i2c_ll_rxfifo_rst(i2c->dev);
|
||||
i2c_ll_slave_enable_rx_it(i2c->dev);
|
||||
i2c_ll_set_stretch(i2c->dev, 0x3FF);
|
||||
i2c_ll_update(i2c->dev);
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
i2c_slave_free_resources(i2c);
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2cSlaveDeinit(uint8_t num){
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
if(!i2c->lock){
|
||||
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
i2c_slave_free_resources(i2c);
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) {
|
||||
if(num >= SOC_I2C_NUM){
|
||||
log_e("Invalid port num: %u", num);
|
||||
return 0;
|
||||
}
|
||||
size_t to_queue = 0, to_fifo = 0;
|
||||
i2c_slave_struct_t * i2c = &_i2c_bus_array[num];
|
||||
if(!i2c->lock){
|
||||
log_e("Lock is not initialized! Did you call i2c_slave_init()?");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
if(!i2c->tx_queue){
|
||||
return 0;
|
||||
}
|
||||
I2C_SLAVE_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//make sure that tx is idle
|
||||
uint64_t tout_at = esp_timer_get_time() + (timeout_ms * 1000);
|
||||
while(i2c_ll_slave_addressed(i2c->dev) && i2c_ll_slave_rw(i2c->dev)) {
|
||||
// ongoing MASTER READ
|
||||
//wait up to timeout_ms for current transaction to finish
|
||||
vTaskDelay(2);
|
||||
if((uint64_t)esp_timer_get_time() >= tout_at){
|
||||
log_e("TX IDLE WAIT TIMEOUT!");
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
i2c_ll_slave_disable_tx_it(i2c->dev);
|
||||
if (i2c_ll_get_txfifo_len(i2c->dev) < SOC_I2C_FIFO_LEN) {
|
||||
i2c_ll_txfifo_rst(i2c->dev);
|
||||
}
|
||||
#endif
|
||||
to_fifo = i2c_ll_get_txfifo_len(i2c->dev);
|
||||
if(len < to_fifo){
|
||||
to_fifo = len;
|
||||
}
|
||||
i2c_ll_write_txfifo(i2c->dev, (uint8_t*)buf, to_fifo);
|
||||
buf += to_fifo;
|
||||
len -= to_fifo;
|
||||
//reset tx_queue
|
||||
xQueueReset(i2c->tx_queue);
|
||||
//write the rest of the bytes to the queue
|
||||
if(len){
|
||||
to_queue = uxQueueSpacesAvailable(i2c->tx_queue);
|
||||
if(len < to_queue){
|
||||
to_queue = len;
|
||||
}
|
||||
for (size_t i = 0; i < to_queue; i++) {
|
||||
if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_RATE_MS) != pdTRUE) {
|
||||
xQueueReset(i2c->tx_queue);
|
||||
to_queue = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//no need to enable TX_EMPTY if tx_queue is empty
|
||||
if(to_queue){
|
||||
i2c_ll_slave_enable_tx_it(i2c->dev);
|
||||
}
|
||||
}
|
||||
I2C_SLAVE_MUTEX_UNLOCK();
|
||||
return to_queue + to_fifo;
|
||||
}
|
||||
|
||||
//=====================================================================================================================
|
||||
//-------------------------------------- Private Functions ------------------------------------------------------------
|
||||
//=====================================================================================================================
|
||||
|
||||
static void i2c_slave_free_resources(i2c_slave_struct_t * i2c){
|
||||
i2c_slave_detach_gpio(i2c);
|
||||
i2c_ll_set_slave_addr(i2c->dev, 0, false);
|
||||
i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK);
|
||||
i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK);
|
||||
|
||||
if (i2c->intr_handle) {
|
||||
esp_intr_free(i2c->intr_handle);
|
||||
i2c->intr_handle = NULL;
|
||||
}
|
||||
|
||||
if(i2c->task_handle){
|
||||
vTaskDelete(i2c->task_handle);
|
||||
i2c->task_handle = NULL;
|
||||
}
|
||||
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
if (i2c->rx_queue) {
|
||||
vQueueDelete(i2c->rx_queue);
|
||||
i2c->rx_queue = NULL;
|
||||
}
|
||||
#else
|
||||
if (i2c->rx_ring_buf) {
|
||||
vRingbufferDelete(i2c->rx_ring_buf);
|
||||
i2c->rx_ring_buf = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i2c->tx_queue) {
|
||||
vQueueDelete(i2c->tx_queue);
|
||||
i2c->tx_queue = NULL;
|
||||
}
|
||||
|
||||
if (i2c->event_queue) {
|
||||
vQueueDelete(i2c->event_queue);
|
||||
i2c->event_queue = NULL;
|
||||
}
|
||||
|
||||
i2c->rx_data_count = 0;
|
||||
}
|
||||
|
||||
static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed)
|
||||
{
|
||||
if (i2c == NULL) {
|
||||
log_e("no control buffer");
|
||||
return false;
|
||||
}
|
||||
if(clk_speed > 1100000UL){
|
||||
clk_speed = 1100000UL;
|
||||
}
|
||||
|
||||
// Adjust Fifo thresholds based on frequency
|
||||
uint32_t a = (clk_speed / 50000L) + 2;
|
||||
log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a);
|
||||
|
||||
i2c_clk_cal_t clk_cal;
|
||||
#if SOC_I2C_SUPPORT_APB
|
||||
i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal);
|
||||
i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_APB); /*!< I2C source clock from APB, 80M*/
|
||||
#elif SOC_I2C_SUPPORT_XTAL
|
||||
i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal);
|
||||
i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_XTAL); /*!< I2C source clock from XTAL, 40M */
|
||||
#endif
|
||||
i2c_ll_set_txfifo_empty_thr(i2c->dev, a);
|
||||
i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a);
|
||||
i2c_ll_set_bus_timing(i2c->dev, &clk_cal);
|
||||
i2c_ll_set_filter(i2c->dev, 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void i2c_slave_delay_us(uint64_t us)
|
||||
{
|
||||
uint64_t m = esp_timer_get_time();
|
||||
if (us) {
|
||||
uint64_t e = (m + us);
|
||||
if (m > e) { //overflow
|
||||
while ((uint64_t)esp_timer_get_time() > e);
|
||||
}
|
||||
while ((uint64_t)esp_timer_get_time() < e);
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode)
|
||||
{
|
||||
gpio_config_t conf = {
|
||||
.pin_bit_mask = 1LL << pin,
|
||||
.mode = mode,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&conf);
|
||||
}
|
||||
|
||||
static bool i2c_slave_check_line_state(int8_t sda, int8_t scl)
|
||||
{
|
||||
if (sda < 0 || scl < 0) {
|
||||
return false;//return false since there is nothing to do
|
||||
}
|
||||
// if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles
|
||||
gpio_set_level(sda, 1);
|
||||
gpio_set_level(scl, 1);
|
||||
i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD);
|
||||
i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD);
|
||||
gpio_set_level(scl, 1);
|
||||
|
||||
if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
|
||||
log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl));
|
||||
for (uint8_t a=0; a<9; a++) {
|
||||
i2c_slave_delay_us(5);
|
||||
if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered
|
||||
log_w("Recovered after %d Cycles",a);
|
||||
gpio_set_level(sda,0); // start
|
||||
i2c_slave_delay_us(5);
|
||||
for (uint8_t a=0;a<9; a++) {
|
||||
gpio_set_level(scl,1);
|
||||
i2c_slave_delay_us(5);
|
||||
gpio_set_level(scl,0);
|
||||
i2c_slave_delay_us(5);
|
||||
}
|
||||
gpio_set_level(scl,1);
|
||||
i2c_slave_delay_us(5);
|
||||
gpio_set_level(sda,1); // stop
|
||||
break;
|
||||
}
|
||||
gpio_set_level(scl, 0);
|
||||
i2c_slave_delay_us(5);
|
||||
gpio_set_level(scl, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state
|
||||
log_e("Bus Invalid State, Can't init sda=%d, scl=%d",gpio_get_level(sda),gpio_get_level(scl));
|
||||
return false; // bus is busy
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl)
|
||||
{
|
||||
if (i2c == NULL) {
|
||||
log_e("no control block");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sda < 0)||( scl < 0)) {
|
||||
log_e("bad pins sda=%d, scl=%d",sda,scl);
|
||||
return false;
|
||||
}
|
||||
|
||||
i2c->scl = scl;
|
||||
gpio_set_level(scl, 1);
|
||||
i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false);
|
||||
gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false);
|
||||
|
||||
i2c->sda = sda;
|
||||
gpio_set_level(sda, 1);
|
||||
i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false);
|
||||
gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c)
|
||||
{
|
||||
if (i2c == NULL) {
|
||||
log_e("no control Block");
|
||||
return false;
|
||||
}
|
||||
if (i2c->scl >= 0) {
|
||||
gpio_matrix_out(i2c->scl, 0x100, false, false);
|
||||
gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false);
|
||||
i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT);
|
||||
i2c->scl = -1; // un attached
|
||||
}
|
||||
if (i2c->sda >= 0) {
|
||||
gpio_matrix_out(i2c->sda, 0x100, false, false);
|
||||
gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false);
|
||||
i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT);
|
||||
i2c->sda = -1; // un attached
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event)
|
||||
{
|
||||
bool pxHigherPriorityTaskWoken = false;
|
||||
if(i2c->event_queue) {
|
||||
if(xQueueSendFromISR(i2c->event_queue, event, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
|
||||
//log_e("event_queue_full");
|
||||
}
|
||||
}
|
||||
return pxHigherPriorityTaskWoken;
|
||||
}
|
||||
|
||||
static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c)
|
||||
{
|
||||
bool pxHigherPriorityTaskWoken = false;
|
||||
uint32_t d = 0, moveCnt = i2c_ll_get_txfifo_len(i2c->dev);
|
||||
while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty
|
||||
if(xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE){
|
||||
i2c_ll_write_txfifo(i2c->dev, (uint8_t*)&d, 1);
|
||||
moveCnt--;
|
||||
} else {
|
||||
i2c_ll_slave_disable_tx_it(i2c->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pxHigherPriorityTaskWoken;
|
||||
}
|
||||
|
||||
static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len)
|
||||
{
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
uint32_t d = 0;
|
||||
#else
|
||||
uint8_t data[SOC_I2C_FIFO_LEN];
|
||||
#endif
|
||||
bool pxHigherPriorityTaskWoken = false;
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
while (len > 0) {
|
||||
i2c_ll_read_rxfifo(i2c->dev, (uint8_t*)&d, 1);
|
||||
if(xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
|
||||
log_e("rx_queue_full");
|
||||
} else {
|
||||
i2c->rx_data_count++;
|
||||
}
|
||||
if (--len == 0) {
|
||||
len = i2c_ll_get_rxfifo_cnt(i2c->dev);
|
||||
}
|
||||
#else
|
||||
if(len){
|
||||
i2c_ll_read_rxfifo(i2c->dev, data, len);
|
||||
if(xRingbufferSendFromISR(i2c->rx_ring_buf, (void*) data, len, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){
|
||||
log_e("rx_ring_buf_full");
|
||||
} else {
|
||||
i2c->rx_data_count += len;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return pxHigherPriorityTaskWoken;
|
||||
}
|
||||
|
||||
static void i2c_slave_isr_handler(void* arg)
|
||||
{
|
||||
bool pxHigherPriorityTaskWoken = false;
|
||||
i2c_slave_struct_t * i2c = (i2c_slave_struct_t *) arg; // recover data
|
||||
|
||||
uint32_t activeInt = i2c_ll_get_intsts_mask(i2c->dev);
|
||||
i2c_ll_clr_intsts_mask(i2c->dev, activeInt);
|
||||
uint8_t rx_fifo_len = i2c_ll_get_rxfifo_cnt(i2c->dev);
|
||||
uint8_t tx_fifo_len = SOC_I2C_FIFO_LEN - i2c_ll_get_txfifo_len(i2c->dev);
|
||||
bool slave_rw = i2c_ll_slave_rw(i2c->dev);
|
||||
|
||||
if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
|
||||
i2c_ll_slave_enable_rx_it(i2c->dev);//is this necessary?
|
||||
}
|
||||
|
||||
if(activeInt & I2C_TRANS_COMPLETE_INT_ENA){ // STOP
|
||||
if(rx_fifo_len){ //READ RX FIFO
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
|
||||
}
|
||||
if(i2c->rx_data_count){ //WRITE or RepeatedStart
|
||||
//SEND RX Event
|
||||
i2c_slave_queue_event_t event;
|
||||
event.event = I2C_SLAVE_EVT_RX;
|
||||
event.stop = !slave_rw;
|
||||
event.param = i2c->rx_data_count;
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
|
||||
//Zero RX count
|
||||
i2c->rx_data_count = 0;
|
||||
}
|
||||
if(slave_rw){ // READ
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//SEND TX Event
|
||||
i2c_slave_queue_event_t event;
|
||||
event.event = I2C_SLAVE_EVT_TX;
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
|
||||
#else
|
||||
//reset TX data
|
||||
i2c_ll_txfifo_rst(i2c->dev);
|
||||
uint8_t d;
|
||||
while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE) ;//flush partial write
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
if(activeInt & I2C_SLAVE_STRETCH_INT_ENA){ // STRETCH
|
||||
i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev);
|
||||
if(cause == I2C_STRETCH_CAUSE_MASTER_READ){
|
||||
//on C3 RX data dissapears with repeated start, so we need to get it here
|
||||
if(rx_fifo_len){
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
|
||||
}
|
||||
//SEND TX Event
|
||||
i2c_slave_queue_event_t event;
|
||||
event.event = I2C_SLAVE_EVT_TX;
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
|
||||
//will clear after execution
|
||||
} else if(cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY){
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c);
|
||||
i2c_ll_stretch_clr(i2c->dev);
|
||||
} else if(cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL){
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len);
|
||||
i2c_ll_stretch_clr(i2c->dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(activeInt & I2C_TXFIFO_WM_INT_ENA){ // TX FiFo Empty
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c);
|
||||
}
|
||||
|
||||
if(pxHigherPriorityTaskWoken){
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len){
|
||||
if(!len){
|
||||
return 0;
|
||||
}
|
||||
#if I2C_SLAVE_USE_RX_QUEUE
|
||||
uint8_t d = 0;
|
||||
BaseType_t res = pdTRUE;
|
||||
for(size_t i=0; i<len; i++) {
|
||||
if(data){
|
||||
res = xQueueReceive(i2c->rx_queue, &data[i], 0);
|
||||
} else {
|
||||
res = xQueueReceive(i2c->rx_queue, &d, 0);
|
||||
}
|
||||
if (res != pdTRUE) {
|
||||
log_e("Read Queue(%u) Failed", i);
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (data)?len:0;
|
||||
#else
|
||||
size_t dlen = 0,
|
||||
to_read = len,
|
||||
so_far = 0,
|
||||
available = 0;
|
||||
uint8_t * rx_data = NULL;
|
||||
|
||||
vRingbufferGetInfo(i2c->rx_ring_buf, NULL, NULL, NULL, NULL, &available);
|
||||
if(available < to_read){
|
||||
log_e("Less available than requested. %u < %u", available, len);
|
||||
to_read = available;
|
||||
}
|
||||
|
||||
while(to_read){
|
||||
dlen = 0;
|
||||
rx_data = (uint8_t *)xRingbufferReceiveUpTo(i2c->rx_ring_buf, &dlen, 0, to_read);
|
||||
if(!rx_data){
|
||||
log_e("Receive %u Failed", to_read);
|
||||
return so_far;
|
||||
}
|
||||
if(data){
|
||||
memcpy(data+so_far, rx_data, dlen);
|
||||
}
|
||||
vRingbufferReturnItem(i2c->rx_ring_buf, rx_data);
|
||||
so_far+=dlen;
|
||||
to_read-=dlen;
|
||||
}
|
||||
return (data)?so_far:0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void i2c_slave_task(void *pv_args)
|
||||
{
|
||||
i2c_slave_struct_t * i2c = (i2c_slave_struct_t *)pv_args;
|
||||
i2c_slave_queue_event_t event;
|
||||
size_t len = 0;
|
||||
bool stop = false;
|
||||
uint8_t * data = NULL;
|
||||
for(;;){
|
||||
if(xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE){
|
||||
// Write
|
||||
if(event.event == I2C_SLAVE_EVT_RX){
|
||||
len = event.param;
|
||||
stop = event.stop;
|
||||
data = (len > 0)?(uint8_t*)malloc(len):NULL;
|
||||
|
||||
if(len && data == NULL){
|
||||
log_e("Malloc (%u) Failed", len);
|
||||
}
|
||||
len = i2c_slave_read_rx(i2c, data, len);
|
||||
if(i2c->receive_callback){
|
||||
i2c->receive_callback(i2c->num, data, len, stop, i2c->arg);
|
||||
}
|
||||
free(data);
|
||||
|
||||
// Read
|
||||
} else if(event.event == I2C_SLAVE_EVT_TX){
|
||||
if(i2c->request_callback){
|
||||
i2c->request_callback(i2c->num, i2c->arg);
|
||||
}
|
||||
i2c_ll_stretch_clr(i2c->dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
35
cores/esp32/esp32-hal-i2c-slave.h
Executable file
35
cores/esp32/esp32-hal-i2c-slave.h
Executable file
@ -0,0 +1,35 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stddef.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg);
|
||||
typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg);
|
||||
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg);
|
||||
|
||||
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len);
|
||||
esp_err_t i2cSlaveDeinit(uint8_t num);
|
||||
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// modified Nov 2017 by Chuck Todd <StickBreaker> to support Interrupt Driven I/O
|
||||
// modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
|
||||
|
||||
#ifndef _ESP32_HAL_I2C_H_
|
||||
#define _ESP32_HAL_I2C_H_
|
||||
@ -22,58 +23,16 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <esp_err.h>
|
||||
|
||||
// External Wire.h equivalent error Codes
|
||||
typedef enum {
|
||||
I2C_ERROR_OK=0,
|
||||
I2C_ERROR_DEV,
|
||||
I2C_ERROR_ACK,
|
||||
I2C_ERROR_TIMEOUT,
|
||||
I2C_ERROR_BUS,
|
||||
I2C_ERROR_BUSY,
|
||||
I2C_ERROR_MEMORY,
|
||||
I2C_ERROR_CONTINUE,
|
||||
I2C_ERROR_NO_BEGIN
|
||||
} i2c_err_t;
|
||||
|
||||
struct i2c_struct_t;
|
||||
typedef struct i2c_struct_t i2c_t;
|
||||
|
||||
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
|
||||
void i2cRelease(i2c_t *i2c); // free ISR, Free DQ, Power off peripheral clock. Must call i2cInit() to recover
|
||||
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis);
|
||||
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount);
|
||||
i2c_err_t i2cFlush(i2c_t *i2c);
|
||||
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
|
||||
uint32_t i2cGetFrequency(i2c_t * i2c);
|
||||
uint32_t i2cGetStatus(i2c_t * i2c); // Status register of peripheral
|
||||
|
||||
//Functions below should be used only if well understood
|
||||
//Might be deprecated and removed in future
|
||||
i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl);
|
||||
i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl);
|
||||
i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda);
|
||||
i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda);
|
||||
|
||||
//Stickbreakers ISR Support
|
||||
i2c_err_t i2cProcQueue(i2c_t *i2c, uint32_t *readCount, uint16_t timeOutMillis);
|
||||
i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
|
||||
i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
|
||||
|
||||
//stickbreaker debug support
|
||||
uint32_t i2cDebug(i2c_t *, uint32_t setBits, uint32_t resetBits);
|
||||
// Debug actions have 3 currently defined locus
|
||||
// 0xXX------ : at entry of ProcQueue
|
||||
// 0x--XX---- : at exit of ProcQueue
|
||||
// 0x------XX : at entry of Flush
|
||||
//
|
||||
// bit 0 causes DumpI2c to execute
|
||||
// bit 1 causes DumpInts to execute
|
||||
// bit 2 causes DumpCmdqueue to execute
|
||||
// bit 3 causes DumpStatus to execute
|
||||
// bit 4 causes DumpFifo to execute
|
||||
esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed);
|
||||
esp_err_t i2cDeinit(uint8_t i2c_num);
|
||||
esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency);
|
||||
esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency);
|
||||
esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis);
|
||||
esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount);
|
||||
esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount);
|
||||
bool i2cIsInit(uint8_t i2c_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -90,17 +90,10 @@ typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
|
||||
|
||||
void ARDUINO_ISR_ATTR __timerISR(void * arg){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t s0 = TIMERG0.int_st_timers.val;
|
||||
uint32_t s1 = TIMERG1.int_st_timers.val;
|
||||
TIMERG0.int_clr_timers.val = s0;
|
||||
TIMERG1.int_clr_timers.val = s1;
|
||||
#else
|
||||
uint32_t s0 = TIMERG0.int_st.val;
|
||||
uint32_t s1 = TIMERG1.int_st.val;
|
||||
TIMERG0.int_clr.val = s0;
|
||||
TIMERG1.int_clr.val = s1;
|
||||
#endif
|
||||
uint8_t status = (s1 & 3) << 2 | (s0 & 3);
|
||||
uint8_t i = 4;
|
||||
//restart the timers that should autoreload
|
||||
@ -239,19 +232,19 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
}
|
||||
timer->dev->config.enable = 0;
|
||||
if(timer->group) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG1.int_clr.val = BIT(timer->timer);
|
||||
TIMERG1.int_ena_timers.val &= ~BIT(timer->timer);
|
||||
#endif
|
||||
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
|
||||
} else {
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#else
|
||||
TIMERG0.int_clr.val = BIT(timer->timer);
|
||||
TIMERG0.int_ena_timers.val &= ~BIT(timer->timer);
|
||||
#endif
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
}
|
||||
#ifdef TIMER_GROUP_SUPPORTS_XTAL_CLOCK
|
||||
timer->dev->config.use_xtal = 0;
|
||||
@ -289,19 +282,19 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
timer->dev->config.edge_int_en = 0;
|
||||
timer->dev->config.alarm_en = 0;
|
||||
if(timer->num & 2){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#else
|
||||
TIMERG1.int_ena_timers.val &= ~BIT(timer->timer);
|
||||
#endif
|
||||
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG1.int_clr.val = BIT(timer->timer);
|
||||
#endif
|
||||
} else {
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#else
|
||||
TIMERG0.int_clr.val = BIT(timer->timer);
|
||||
TIMERG0.int_ena_timers.val &= ~BIT(timer->timer);
|
||||
#endif
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
}
|
||||
__timerInterruptHandlers[timer->num] = NULL;
|
||||
} else {
|
||||
@ -333,9 +326,17 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle));
|
||||
}
|
||||
if(timer->group){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_ena.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG1.int_ena_timers.val |= BIT(timer->timer);
|
||||
#endif
|
||||
} else {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG0.int_ena.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG0.int_ena_timers.val |= BIT(timer->timer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(intr_handle){
|
||||
|
@ -269,7 +269,7 @@ void uartWrite(uart_t* uart, uint8_t c)
|
||||
|
||||
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
if(uart == NULL || data == NULL || !len) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -368,13 +368,9 @@ void uartSetDebug(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->num >= SOC_UART_NUM) {
|
||||
s_uart_debug_nr = -1;
|
||||
//ets_install_putc1(NULL);
|
||||
//return;
|
||||
} else
|
||||
if(s_uart_debug_nr == uart->num) {
|
||||
return;
|
||||
} else
|
||||
s_uart_debug_nr = uart->num;
|
||||
} else {
|
||||
s_uart_debug_nr = uart->num;
|
||||
}
|
||||
uart_install_putc();
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,11 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -39,7 +39,7 @@ static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12";
|
||||
|
||||
static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = (((sector_num * 3)+1)/2);
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0);
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
@ -68,7 +68,7 @@ static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16";
|
||||
|
||||
static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = sector_num * 2;
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0);
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
@ -129,7 +129,7 @@ fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint
|
||||
boot->num_heads = 1;
|
||||
boot->hidden_sectors_count = 0;
|
||||
boot->total_sectors_32 = 0;
|
||||
boot->physical_drive_number = 0x00;
|
||||
boot->physical_drive_number = 0x80;
|
||||
boot->reserved0 = 0x00;
|
||||
boot->extended_boot_signature = 0x29;
|
||||
boot->serial_number = serial_number;
|
||||
|
@ -12,7 +12,7 @@ static int base64_decode_value_signed(int8_t value_in){
|
||||
static const int8_t decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
|
||||
static const int8_t decoding_size = sizeof(decoding);
|
||||
value_in -= 43;
|
||||
if (value_in < 0 || value_in > decoding_size) return -1;
|
||||
if (value_in < 0 || value_in >= decoding_size) return -1;
|
||||
return decoding[(int)value_in];
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ Here are the ESP32 series supported by the Arduino-ESP32 project:
|
||||
SoC Stable Development Datasheet
|
||||
======== ====== =========== ===================================
|
||||
ESP32 Yes Yes `ESP32 Datasheet`_
|
||||
ESP32-S2 No Yes `ESP32-S2 Datasheet`_
|
||||
ESP32-C3 No Yes `ESP32-C3 Datasheet`_
|
||||
ESP32-S2 Yes Yes `ESP32-S2 Datasheet`_
|
||||
ESP32-C3 Yes Yes `ESP32-C3 Datasheet`_
|
||||
ESP32-S3 No No Not Available Yet
|
||||
======== ====== =========== ===================================
|
||||
|
||||
|
@ -166,9 +166,7 @@ Debian/Ubuntu
|
||||
mkdir -p ~/Arduino/hardware/espressif && \
|
||||
cd ~/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
cd esp32/tools && \
|
||||
python3 get.py
|
||||
|
||||
- Restart Arduino IDE.
|
||||
@ -181,9 +179,7 @@ Debian/Ubuntu
|
||||
mkdir -p espressif && \
|
||||
cd espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
cd esp32/tools && \
|
||||
python3 get.py
|
||||
|
||||
Fedora
|
||||
@ -203,9 +199,7 @@ Fedora
|
||||
mkdir -p ~/Arduino/hardware/espressif && \
|
||||
cd ~/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
cd esp32/tools && \
|
||||
python get.py
|
||||
|
||||
- Restart Arduino IDE.
|
||||
@ -228,9 +222,7 @@ openSUSE
|
||||
mkdir -p ~/Arduino/hardware/espressif && \
|
||||
cd ~/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
cd esp32/tools && \
|
||||
python get.py
|
||||
|
||||
- Restart Arduino IDE.
|
||||
@ -246,10 +238,8 @@ macOS
|
||||
|
||||
mkdir -p ~/Documents/Arduino/hardware/espressif && \
|
||||
cd ~/Documents/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 --depth 1 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive --depth 1 && \
|
||||
cd tools && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32/tools && \
|
||||
python get.py
|
||||
|
||||
Where ``~/Documents/Arduino`` represents your sketch book location as per "Arduino" > "Preferences" > "Sketchbook location" (in the IDE once started). Adjust the command above accordingly.
|
||||
|
@ -12,31 +12,57 @@ Here are some of the most common issues around the ESP32 development using Ardui
|
||||
Installing
|
||||
----------
|
||||
|
||||
Here are the common issues during the installation.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Missing Python: "python": executable file not found in $PATH
|
||||
************************************************************
|
||||
|
||||
You are trying to build your sketch using Ubuntu and this message appears:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
"exec: "python": executable file not found in $PATH
|
||||
Error compiling for board ESP32 Dev Module"
|
||||
|
||||
Solution
|
||||
^^^^^^^^
|
||||
|
||||
To avoid this error, you can install the ``python-is-python3`` package to create the symbolic links.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install python-is-python3
|
||||
|
||||
If you are not using Ubuntu, you can check if you have the Python correctly installed or the presence of the symbolic links/environment variables.
|
||||
|
||||
Flashing
|
||||
--------
|
||||
|
||||
Why is my board not flashing/uploading when I try to upload my sketch?
|
||||
**********************************************************************
|
||||
|
||||
If you are trying to upload a new sketch and your board isn't responding, there are some possible reasons.
|
||||
To be able to upload the sketch via serial interface, the ESP32 must be in the download mode. The download mode allows you to upload the sketch over the serial port and to get into it, you need to keep the **GPIO0** in LOW while a resetting (**EN** pin) cycle.
|
||||
If you are trying to upload a new sketch and your board is not responding, there are some possible reasons.
|
||||
|
||||
Possible fatal error message from the Arduino IDE:
|
||||
|
||||
*A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header*
|
||||
|
||||
Solution
|
||||
^^^^^^^^
|
||||
|
||||
Here are some steps that you can try to:
|
||||
|
||||
* Check your USB cable and try a new one.
|
||||
* Change the USB port.
|
||||
* Check your power supply.
|
||||
* In some instances, you must keep **GPIO0** LOW during the uploading process via serial interface.
|
||||
* Hold-down the **“BOOT”** button in your ESP32 board while uploading/flashing.
|
||||
* In some instances, you must keep **GPIO0** LOW during the uploading process via the serial interface.
|
||||
* Hold down the **“BOOT”** button in your ESP32 board while uploading/flashing.
|
||||
|
||||
In some development boards, you can try adding the reset delay circuit, as decribed in the *Power-on Sequence* section on the `ESP32 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32_hardware_design_guidelines_en.pdf>`_ in order to get into the download mode automatically.
|
||||
In some development boards, you can try adding the reset delay circuit, as described in the *Power-on Sequence* section on the `ESP32 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32_hardware_design_guidelines_en.pdf>`_ in order to get into the download mode automatically.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
@ -44,7 +70,10 @@ Hardware
|
||||
Why is my computer not detecting my board?
|
||||
**************************************************
|
||||
|
||||
If your board is not detected after connecting into the USB, you can try to:
|
||||
If your board is not being detected after connecting to the USB, you can try to:
|
||||
|
||||
Solution
|
||||
^^^^^^^^
|
||||
|
||||
* Check if the USB driver is missing. - `USB Driver Download Link <https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers>`_
|
||||
* Check your USB cable and try a new one.
|
||||
|
113
docs/source/tutorials/blink.rst
Normal file
113
docs/source/tutorials/blink.rst
Normal file
@ -0,0 +1,113 @@
|
||||
##########################
|
||||
Blink Interactive Tutorial
|
||||
##########################
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is the interactive blink tutorial using `Wokwi`_. For this tutorial, you don't need the ESP32 board or the Arduino toolchain.
|
||||
|
||||
.. note:: If you don't want to use this tutorial with the simulation, you can copy and paste the :ref:`blink_example_code` from `Wokwi`_ editor and use it on the `Arduino IDE`_ or `PlatformIO`_.
|
||||
|
||||
About this Tutorial
|
||||
-------------------
|
||||
|
||||
This tutorial is the most basic for any get started. In this tutorial, we will show how to set a GPIO pin as an output to drive a LED to blink each 1 second.
|
||||
|
||||
Step by step
|
||||
------------
|
||||
|
||||
In order to make this simple blink tutorial, you'll need to do the following steps.
|
||||
|
||||
1. **Define the GPIO for the LED.**
|
||||
|
||||
.. code-block::
|
||||
|
||||
#define LED 2
|
||||
|
||||
This ``#define LED 2`` will be used to set the GPIO2 as the ``LED`` output pin.
|
||||
|
||||
2. **Setup.**
|
||||
|
||||
Inside the ``setup()`` function, we need to add all things we want to run once during the startup.
|
||||
Here we'll add the ``pinMode`` function to set the pin as output.
|
||||
|
||||
.. code-block::
|
||||
|
||||
void setup() {
|
||||
pinMode(LED, OUTPUT);
|
||||
}
|
||||
|
||||
The first argument is the GPIO number, already defined and the second is the mode, here defined as an output.
|
||||
|
||||
3. **Main Loop.**
|
||||
|
||||
After the ``setup``, the code runs the ``loop`` function infinitely. Here we will handle the GPIO in order to get the LED blinking.
|
||||
|
||||
.. code-block::
|
||||
|
||||
void loop() {
|
||||
digitalWrite(LED, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(LED, LOW);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
The first function is the ``digitalWrite()`` with two arguments:
|
||||
|
||||
* GPIO: Set the GPIO pin. Here defined by our ``LED`` connected to the GPIO2.
|
||||
* State: Set the GPIO state as HIGH (ON) or LOW (OFF).
|
||||
|
||||
This first ``digitalWrite`` we will set the LED ON.
|
||||
|
||||
After the ``digitalWrite``, we will set a ``delay`` function in order to wait for some time, defined in milliseconds.
|
||||
|
||||
Now we can set the GPIO to ``LOW`` to turn the LED off and ``delay`` for more few milliseconds to get the LED blinking.
|
||||
|
||||
4. **Run the code.**
|
||||
|
||||
To run this code, you'll need a development board and the Arduino toolchain installed on your computer. If you don't have both, you can use the simulator to test and edit the code.
|
||||
|
||||
Simulation
|
||||
----------
|
||||
|
||||
This simulator is provided by `Wokwi`_ and you can test the blink code and play with some modifications to learn more about this example.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe src="https://wokwi.com/arduino/projects/305566932847821378?embed=1" width="100%" height="400" border="0"></iframe>
|
||||
|
||||
Change the parameters, like the delay period, to test the code right on your browser. You can add more LEDs, change the GPIO, and more.
|
||||
|
||||
.. _blink_example_code:
|
||||
|
||||
Example Code
|
||||
------------
|
||||
|
||||
Here is the full blink code.
|
||||
|
||||
.. code-block::
|
||||
|
||||
#define LED 2
|
||||
|
||||
void setup() {
|
||||
pinMode(LED, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(LED, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(LED, LOW);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* `ESP32 Datasheet`_ (Datasheet)
|
||||
* `Wokwi`_ (Wokwi Website)
|
||||
|
||||
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
||||
.. _Wokwi: https://wokwi.com/
|
||||
.. _PlatformIO: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#platformio
|
||||
.. _Arduino IDE: https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html#installing-using-boards-manager
|
@ -6,6 +6,7 @@ Tutorials
|
||||
:maxdepth: 2
|
||||
:caption: Tutorials:
|
||||
|
||||
Blink <blink>
|
||||
Basic <basic>
|
||||
DFU <dfu>
|
||||
GPIO Matrix and Pin Mux <io_mux>
|
||||
|
@ -191,7 +191,7 @@ uint8_t* BLECharacteristic::getData() {
|
||||
* @brief Retrieve the current length of the data of the characteristic.
|
||||
* @return Amount of databytes of the characteristic.
|
||||
*/
|
||||
uint8_t BLECharacteristic::getLength() {
|
||||
size_t BLECharacteristic::getLength() {
|
||||
return m_value.getLength();
|
||||
} // getLength
|
||||
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
BLEUUID getUUID();
|
||||
std::string getValue();
|
||||
uint8_t* getData();
|
||||
uint8_t getLength();
|
||||
size_t getLength();
|
||||
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
|
@ -157,7 +157,9 @@ void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t
|
||||
|
||||
case ESP_GATTS_MTU_EVT:
|
||||
updatePeerMTU(param->mtu.conn_id, param->mtu.mtu);
|
||||
m_pServerCallbacks->onMtuChanged(this, param);
|
||||
if (m_pServerCallbacks != nullptr) {
|
||||
m_pServerCallbacks->onMtuChanged(this, param);
|
||||
}
|
||||
break;
|
||||
|
||||
// ESP_GATTS_CONNECT_EVT
|
||||
|
@ -11,27 +11,27 @@
|
||||
#include "EEPROM.h"
|
||||
|
||||
// Instantiate eeprom objects with parameter/argument names and sizes
|
||||
EEPROMClass NAMES("eeprom0", 0x500);
|
||||
EEPROMClass HEIGHT("eeprom1", 0x200);
|
||||
EEPROMClass AGE("eeprom2", 0x100);
|
||||
EEPROMClass NAMES("eeprom0");
|
||||
EEPROMClass HEIGHT("eeprom1");
|
||||
EEPROMClass AGE("eeprom2");
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println("Testing EEPROMClass\n");
|
||||
if (!NAMES.begin(NAMES.length())) {
|
||||
if (!NAMES.begin(0x500)) {
|
||||
Serial.println("Failed to initialise NAMES");
|
||||
Serial.println("Restarting...");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
if (!HEIGHT.begin(HEIGHT.length())) {
|
||||
if (!HEIGHT.begin(0x200)) {
|
||||
Serial.println("Failed to initialise HEIGHT");
|
||||
Serial.println("Restarting...");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
if (!AGE.begin(AGE.length())) {
|
||||
if (!AGE.begin(0x100)) {
|
||||
Serial.println("Failed to initialise AGE");
|
||||
Serial.println("Restarting...");
|
||||
delay(1000);
|
||||
|
@ -34,7 +34,6 @@ EEPROMClass::EEPROMClass(void)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
, _name("eeprom")
|
||||
, _user_defined_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -45,17 +44,15 @@ EEPROMClass::EEPROMClass(uint32_t sector)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
, _name("eeprom")
|
||||
, _user_defined_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
EEPROMClass::EEPROMClass(const char* name, uint32_t user_defined_size)
|
||||
EEPROMClass::EEPROMClass(const char* name)
|
||||
: _handle(0)
|
||||
, _data(0)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
, _name(name)
|
||||
, _user_defined_size(user_defined_size)
|
||||
{
|
||||
}
|
||||
|
||||
@ -133,7 +130,7 @@ bool EEPROMClass::begin(size_t size) {
|
||||
|
||||
_data = (uint8_t*) malloc(size);
|
||||
if(!_data) {
|
||||
log_e("Not enough memory for %d bytes in EEPROM");
|
||||
log_e("Not enough memory for %d bytes in EEPROM", size);
|
||||
return false;
|
||||
}
|
||||
_size = size;
|
||||
@ -215,7 +212,7 @@ uint8_t * EEPROMClass::getDataPtr() {
|
||||
*/
|
||||
uint16_t EEPROMClass::length ()
|
||||
{
|
||||
return _user_defined_size;
|
||||
return _size;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -35,7 +35,7 @@ typedef uint32_t nvs_handle;
|
||||
class EEPROMClass {
|
||||
public:
|
||||
EEPROMClass(uint32_t sector);
|
||||
EEPROMClass(const char* name, uint32_t user_defined_size);
|
||||
EEPROMClass(const char* name);
|
||||
EEPROMClass(void);
|
||||
~EEPROMClass(void);
|
||||
|
||||
@ -112,7 +112,6 @@ class EEPROMClass {
|
||||
size_t _size;
|
||||
bool _dirty;
|
||||
const char* _name;
|
||||
uint32_t _user_defined_size;
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM)
|
||||
|
@ -14,6 +14,7 @@
|
||||
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
|
||||
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
|
||||
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
|
||||
|
||||
|
@ -113,6 +113,25 @@
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_M5STACK_UNITCAM)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM 15
|
||||
#define XCLK_GPIO_NUM 27
|
||||
#define SIOD_GPIO_NUM 25
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 19
|
||||
#define Y8_GPIO_NUM 36
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y6_GPIO_NUM 39
|
||||
#define Y5_GPIO_NUM 5
|
||||
#define Y4_GPIO_NUM 34
|
||||
#define Y3_GPIO_NUM 35
|
||||
#define Y2_GPIO_NUM 32
|
||||
#define VSYNC_GPIO_NUM 22
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_AI_THINKER)
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM -1
|
||||
|
@ -168,7 +168,7 @@ size_t F_Fat::freeBytes()
|
||||
|
||||
bool F_Fat::exists(const char* path)
|
||||
{
|
||||
File f = open(path, "r");
|
||||
File f = open(path, "r",false);
|
||||
return (f == true) && !f.isDirectory();
|
||||
}
|
||||
|
||||
|
@ -186,18 +186,18 @@ void File::rewindDirectory(void)
|
||||
_p->rewindDirectory();
|
||||
}
|
||||
|
||||
File FS::open(const String& path, const char* mode)
|
||||
File FS::open(const String& path, const char* mode, const bool create)
|
||||
{
|
||||
return open(path.c_str(), mode);
|
||||
return open(path.c_str(), mode, create);
|
||||
}
|
||||
|
||||
File FS::open(const char* path, const char* mode)
|
||||
File FS::open(const char* path, const char* mode, const bool create)
|
||||
{
|
||||
if (!_impl) {
|
||||
return File();
|
||||
}
|
||||
|
||||
return File(_impl->open(path, mode));
|
||||
return File(_impl->open(path, mode, create));
|
||||
}
|
||||
|
||||
bool FS::exists(const char* path)
|
||||
|
@ -89,8 +89,8 @@ class FS
|
||||
public:
|
||||
FS(FSImplPtr impl) : _impl(impl) { }
|
||||
|
||||
File open(const char* path, const char* mode = FILE_READ);
|
||||
File open(const String& path, const char* mode = FILE_READ);
|
||||
File open(const char* path, const char* mode = FILE_READ, const bool create = false);
|
||||
File open(const String& path, const char* mode = FILE_READ, const bool create = false);
|
||||
|
||||
bool exists(const char* path);
|
||||
bool exists(const String& path);
|
||||
|
@ -53,7 +53,7 @@ protected:
|
||||
public:
|
||||
FSImpl() : _mountpoint(NULL) { }
|
||||
virtual ~FSImpl() { }
|
||||
virtual FileImplPtr open(const char* path, const char* mode) = 0;
|
||||
virtual FileImplPtr open(const char* path, const char* mode, const bool create) = 0;
|
||||
virtual bool exists(const char* path) = 0;
|
||||
virtual bool rename(const char* pathFrom, const char* pathTo) = 0;
|
||||
virtual bool remove(const char* path) = 0;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
using namespace fs;
|
||||
|
||||
FileImplPtr VFSImpl::open(const char* fpath, const char* mode)
|
||||
FileImplPtr VFSImpl::open(const char* fpath, const char* mode, const bool create)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
@ -37,7 +37,7 @@ FileImplPtr VFSImpl::open(const char* fpath, const char* mode)
|
||||
sprintf(temp,"%s%s", _mountpoint, fpath);
|
||||
|
||||
struct stat st;
|
||||
//file lound
|
||||
//file found
|
||||
if(!stat(temp, &st)) {
|
||||
free(temp);
|
||||
if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
@ -47,12 +47,6 @@ FileImplPtr VFSImpl::open(const char* fpath, const char* mode)
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
//file not found but mode permits creation
|
||||
if(mode && mode[0] != 'r') {
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
|
||||
//try to open this as directory (might be mount point)
|
||||
DIR * d = opendir(temp);
|
||||
if(d) {
|
||||
@ -61,7 +55,51 @@ FileImplPtr VFSImpl::open(const char* fpath, const char* mode)
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
|
||||
log_e("%s does not exist", temp);
|
||||
//file not found but mode permits file creation without folder creation
|
||||
if((mode && mode[0] != 'r') && (!create)){
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
|
||||
////file not found but mode permits file creation and folder creation
|
||||
if((mode && mode[0] != 'r') && create){
|
||||
|
||||
char *token;
|
||||
char *folder = (char *)malloc(strlen(fpath));
|
||||
|
||||
int start_index = 0;
|
||||
int end_index = 0;
|
||||
|
||||
token = strchr(fpath+1,'/');
|
||||
end_index = (token-fpath);
|
||||
|
||||
while (token != NULL)
|
||||
{
|
||||
memcpy(folder,fpath + start_index, end_index-start_index);
|
||||
folder[end_index-start_index] = '\0';
|
||||
|
||||
if(!VFSImpl::mkdir(folder))
|
||||
{
|
||||
log_e("Creating folder: %s failed!",folder);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
token=strchr(token+1,'/');
|
||||
if(token != NULL)
|
||||
{
|
||||
end_index = (token-fpath);
|
||||
memset(folder, 0, strlen(folder));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(folder);
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
|
||||
}
|
||||
|
||||
log_e("%s does not exist, no permits for creation", temp);
|
||||
free(temp);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ protected:
|
||||
friend class VFSFileImpl;
|
||||
|
||||
public:
|
||||
FileImplPtr open(const char* path, const char* mode) override;
|
||||
FileImplPtr open(const char* path, const char* mode, const bool create) override;
|
||||
bool exists(const char* path) override;
|
||||
bool rename(const char* pathFrom, const char* pathTo) override;
|
||||
bool remove(const char* path) override;
|
||||
|
@ -261,6 +261,10 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol)
|
||||
url.remove(0, (index + 3)); // remove http:// or https://
|
||||
|
||||
index = url.indexOf('/');
|
||||
if (index == -1) {
|
||||
index = url.length();
|
||||
url += '/';
|
||||
}
|
||||
String host = url.substring(0, index);
|
||||
url.remove(0, index); // remove host part
|
||||
|
||||
|
@ -45,7 +45,7 @@ LittleFSImpl::LittleFSImpl()
|
||||
|
||||
bool LittleFSImpl::exists(const char* path)
|
||||
{
|
||||
File f = open(path, "r");
|
||||
File f = open(path, "r",false);
|
||||
return (f == true);
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -43,7 +44,7 @@ bool Preferences::begin(const char * name, bool readOnly, const char* partition_
|
||||
}
|
||||
err = nvs_open_from_partition(partition_label, name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle);
|
||||
} else {
|
||||
err = nvs_open(name, readOnly?NVS_READONLY:NVS_READWRITE, &_handle);
|
||||
err = nvs_open(name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle);
|
||||
}
|
||||
if(err){
|
||||
log_e("nvs_open failed: %s", nvs_error(err));
|
||||
@ -74,6 +75,11 @@ bool Preferences::clear(){
|
||||
log_e("nvs_erase_all fail: %s", nvs_error(err));
|
||||
return false;
|
||||
}
|
||||
err = nvs_commit(_handle);
|
||||
if(err){
|
||||
log_e("nvs_commit fail: %s", nvs_error(err));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -90,6 +96,11 @@ bool Preferences::remove(const char * key){
|
||||
log_e("nvs_erase_key fail: %s %s", key, nvs_error(err));
|
||||
return false;
|
||||
}
|
||||
err = nvs_commit(_handle);
|
||||
if(err){
|
||||
log_e("nvs_commit fail: %s %s", key, nvs_error(err));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ SDMMCFS::SDMMCFS(FSImplPtr impl)
|
||||
: FS(impl), _card(NULL)
|
||||
{}
|
||||
|
||||
bool SDMMCFS::begin(const char * mountpoint, bool mode1bit, bool format_if_mount_failed)
|
||||
bool SDMMCFS::begin(const char * mountpoint, bool mode1bit, bool format_if_mount_failed, int sdmmc_frequency)
|
||||
{
|
||||
if(_card) {
|
||||
return true;
|
||||
@ -46,7 +46,7 @@ bool SDMMCFS::begin(const char * mountpoint, bool mode1bit, bool format_if_mount
|
||||
sdmmc_host_t host;
|
||||
host.flags = SDMMC_HOST_FLAG_4BIT;
|
||||
host.slot = SDMMC_HOST_SLOT_1;
|
||||
host.max_freq_khz = SDMMC_FREQ_DEFAULT;
|
||||
host.max_freq_khz = sdmmc_frequency;
|
||||
host.io_voltage = 3.3f;
|
||||
host.init = &sdmmc_host_init;
|
||||
host.set_bus_width = &sdmmc_host_set_bus_width;
|
||||
@ -54,11 +54,10 @@ bool SDMMCFS::begin(const char * mountpoint, bool mode1bit, bool format_if_mount
|
||||
host.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode;
|
||||
host.set_card_clk = &sdmmc_host_set_card_clk;
|
||||
host.do_transaction = &sdmmc_host_do_transaction;
|
||||
host.deinit_p = &sdspi_host_remove_device;
|
||||
host.deinit = &sdmmc_host_deinit;
|
||||
host.io_int_enable = &sdmmc_host_io_int_enable;
|
||||
host.io_int_wait = &sdmmc_host_io_int_wait;
|
||||
host.command_timeout_ms = 0;
|
||||
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
|
||||
#ifdef BOARD_HAS_1BIT_SDMMC
|
||||
mode1bit = true;
|
||||
#endif
|
||||
|
@ -21,6 +21,13 @@
|
||||
#include "driver/sdmmc_types.h"
|
||||
#include "sd_defines.h"
|
||||
|
||||
// If reading/writing to the SD card is unstable,
|
||||
// you can define BOARD_MAX_SDMMC_FREQ with lower value (Ex. SDMMC_FREQ_DEFAULT)
|
||||
// in pins_arduino.h for your board variant.
|
||||
#ifndef BOARD_MAX_SDMMC_FREQ
|
||||
#define BOARD_MAX_SDMMC_FREQ SDMMC_FREQ_HIGHSPEED
|
||||
#endif
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
||||
@ -31,7 +38,7 @@ protected:
|
||||
|
||||
public:
|
||||
SDMMCFS(FSImplPtr impl);
|
||||
bool begin(const char * mountpoint="/sdcard", bool mode1bit=false, bool format_if_mount_failed=false);
|
||||
bool begin(const char * mountpoint="/sdcard", bool mode1bit=false, bool format_if_mount_failed=false, int sdmmc_frequency=BOARD_MAX_SDMMC_FREQ);
|
||||
void end();
|
||||
sdcard_type_t cardType();
|
||||
uint64_t cardSize();
|
||||
|
@ -76,36 +76,24 @@ void setup() {
|
||||
|
||||
//set up slave select pins as outputs as the Arduino API
|
||||
//doesn't handle automatically pulling SS low
|
||||
pinMode(VSPI_SS, OUTPUT); //VSPI SS
|
||||
pinMode(HSPI_SS, OUTPUT); //HSPI SS
|
||||
pinMode(vspi->pinSS(), OUTPUT); //VSPI SS
|
||||
pinMode(hspi->pinSS(), OUTPUT); //HSPI SS
|
||||
|
||||
}
|
||||
|
||||
// the loop function runs over and over again until power down or reset
|
||||
void loop() {
|
||||
//use the SPI buses
|
||||
vspiCommand();
|
||||
hspiCommand();
|
||||
spiCommand(vspi, 0b01010101); // junk data to illustrate usage
|
||||
spiCommand(hspi, 0b11001100);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void vspiCommand() {
|
||||
byte data = 0b01010101; // junk data to illustrate usage
|
||||
|
||||
void spiCommand(SPIClass *spi, byte data) {
|
||||
//use it as you would the regular arduino SPI API
|
||||
vspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(VSPI_SS, LOW); //pull SS slow to prep other end for transfer
|
||||
vspi->transfer(data);
|
||||
digitalWrite(VSPI_SS, HIGH); //pull ss high to signify end of data transfer
|
||||
vspi->endTransaction();
|
||||
}
|
||||
|
||||
void hspiCommand() {
|
||||
byte stuff = 0b11001100;
|
||||
|
||||
hspi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(HSPI_SS, LOW);
|
||||
hspi->transfer(stuff);
|
||||
digitalWrite(HSPI_SS, HIGH);
|
||||
hspi->endTransaction();
|
||||
spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer
|
||||
spi->transfer(data);
|
||||
digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer
|
||||
spi->endTransaction();
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ public:
|
||||
void writePattern(const uint8_t * data, uint8_t size, uint32_t repeat);
|
||||
|
||||
spi_t * bus(){ return _spi; }
|
||||
int8_t pinSS() { return _ss; }
|
||||
};
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
@ -39,7 +39,7 @@ SPIFFSImpl::SPIFFSImpl()
|
||||
|
||||
bool SPIFFSImpl::exists(const char* path)
|
||||
{
|
||||
File f = open(path, "r");
|
||||
File f = open(path, "r",false);
|
||||
return (f == true) && !f.isDirectory();
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){
|
||||
// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
|
||||
void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){
|
||||
log_v("instance: %u, protocol:%u", instance, protocol);
|
||||
arduino_usb_hid_event_data_t p = {0};
|
||||
arduino_usb_hid_event_data_t p;
|
||||
p.instance = instance;
|
||||
p.set_protocol.protocol = protocol;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_PROTOCOL_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY);
|
||||
@ -241,7 +241,7 @@ void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){
|
||||
// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
|
||||
bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate){
|
||||
log_v("instance: %u, idle_rate:%u", instance, idle_rate);
|
||||
arduino_usb_hid_event_data_t p = {0};
|
||||
arduino_usb_hid_event_data_t p;
|
||||
p.instance = instance;
|
||||
p.set_idle.idle_rate = idle_rate;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_IDLE_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY);
|
||||
|
@ -61,7 +61,7 @@ void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_h
|
||||
|
||||
void USBHIDKeyboard::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){
|
||||
if(report_id == HID_REPORT_ID_KEYBOARD){
|
||||
arduino_usb_hid_keyboard_event_data_t p = {0};
|
||||
arduino_usb_hid_keyboard_event_data_t p;
|
||||
p.leds = buffer[0];
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ uint16_t USBHIDVendor::_onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, feature, len);
|
||||
arduino_usb_hid_vendor_event_data_t p = {0};
|
||||
arduino_usb_hid_vendor_event_data_t p;
|
||||
p.buffer = feature;
|
||||
p.len = len;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY);
|
||||
@ -136,7 +136,7 @@ void USBHIDVendor::_onSetFeature(uint8_t report_id, const uint8_t* buffer, uint1
|
||||
return;
|
||||
}
|
||||
memcpy(feature, buffer, len);
|
||||
arduino_usb_hid_vendor_event_data_t p = {0};
|
||||
arduino_usb_hid_vendor_event_data_t p;
|
||||
p.buffer = feature;
|
||||
p.len = len;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY);
|
||||
@ -153,7 +153,7 @@ void USBHIDVendor::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t
|
||||
break;
|
||||
}
|
||||
}
|
||||
arduino_usb_hid_vendor_event_data_t p = {0};
|
||||
arduino_usb_hid_vendor_event_data_t p;
|
||||
p.buffer = buffer;
|
||||
p.len = len;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_VENDOR_EVENTS, ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT, &p, sizeof(arduino_usb_hid_vendor_event_data_t), portMAX_DELAY);
|
||||
|
@ -40,8 +40,8 @@ uint16_t tusb_vendor_load_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
}
|
||||
|
||||
void tud_vendor_rx_cb(uint8_t itf){
|
||||
log_v("%u", len);
|
||||
size_t len = tud_vendor_n_available(itf);
|
||||
log_v("%u", len);
|
||||
if(len){
|
||||
uint8_t buffer[len];
|
||||
len = tud_vendor_n_read(itf, buffer, len);
|
||||
@ -146,7 +146,7 @@ void USBVendor::_onRX(const uint8_t* buffer, size_t len){
|
||||
break;
|
||||
}
|
||||
}
|
||||
arduino_usb_vendor_event_data_t p = {0};
|
||||
arduino_usb_vendor_event_data_t p;
|
||||
p.data.len = len;
|
||||
arduino_usb_event_post(ARDUINO_USB_VENDOR_EVENTS, ARDUINO_USB_VENDOR_DATA_EVENT, &p, sizeof(arduino_usb_vendor_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
index.htm is the default index (works on subfolders as well)
|
||||
|
||||
upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
|
||||
To retrieve the contents of SDcard, visit http://esp32sd.local/list?dir=/
|
||||
dir is the argument that needs to be passed to the function PrintDirectory via HTTP Get request.
|
||||
|
||||
*/
|
||||
#include <WiFi.h>
|
||||
|
@ -237,12 +237,6 @@ bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_typ
|
||||
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
esp_netif_t *eth_netif = esp_netif_new(&cfg);
|
||||
|
||||
if(esp_eth_set_default_handlers(eth_netif) != ESP_OK){
|
||||
log_e("esp_eth_set_default_handlers failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
esp_eth_mac_t *eth_mac = NULL;
|
||||
#if CONFIG_ETH_SPI_ETHERNET_DM9051
|
||||
if(type == ETH_PHY_DM9051){
|
||||
@ -288,7 +282,12 @@ bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_typ
|
||||
break;
|
||||
#endif
|
||||
case ETH_PHY_KSZ8081:
|
||||
#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4,3,0)
|
||||
eth_phy = esp_eth_phy_new_ksz8081(&phy_config);
|
||||
#else
|
||||
log_e("unsupported ethernet type 'ETH_PHY_KSZ8081'");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -542,6 +542,20 @@ bool tcpipInit(){
|
||||
* */
|
||||
|
||||
static bool lowLevelInitDone = false;
|
||||
bool WiFiGenericClass::_wifiUseStaticBuffers = false;
|
||||
|
||||
bool WiFiGenericClass::useStaticBuffers(){
|
||||
return _wifiUseStaticBuffers;
|
||||
}
|
||||
|
||||
void WiFiGenericClass::useStaticBuffers(bool bufferMode){
|
||||
if (lowLevelInitDone) {
|
||||
log_w("WiFi already started. Call WiFi.mode(WIFI_MODE_NULL) before setting Static Buffer Mode.");
|
||||
}
|
||||
_wifiUseStaticBuffers = bufferMode;
|
||||
}
|
||||
|
||||
|
||||
bool wifiLowLevelInit(bool persistent){
|
||||
if(!lowLevelInitDone){
|
||||
lowLevelInitDone = true;
|
||||
@ -557,6 +571,16 @@ bool wifiLowLevelInit(bool persistent){
|
||||
}
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
|
||||
if(!WiFiGenericClass::useStaticBuffers()) {
|
||||
cfg.static_tx_buf_num = 0;
|
||||
cfg.dynamic_tx_buf_num = 32;
|
||||
cfg.tx_buf_type = 1;
|
||||
cfg.cache_tx_buf_num = 1; // can't be zero!
|
||||
cfg.static_rx_buf_num = 4;
|
||||
cfg.dynamic_rx_buf_num = 32;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_wifi_init(&cfg);
|
||||
if(err){
|
||||
log_e("esp_wifi_init %d", err);
|
||||
@ -644,7 +668,6 @@ wifi_ps_type_t WiFiGenericClass::_sleepEnabled = WIFI_PS_MIN_MODEM;
|
||||
|
||||
WiFiGenericClass::WiFiGenericClass()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char * WiFiGenericClass::getHostname()
|
||||
|
@ -179,12 +179,16 @@ class WiFiGenericClass
|
||||
static bool hostname(const String& aHostname) { return setHostname(aHostname.c_str()); }
|
||||
|
||||
static esp_err_t _eventCallback(arduino_event_t *event);
|
||||
|
||||
static void useStaticBuffers(bool bufferMode);
|
||||
static bool useStaticBuffers();
|
||||
|
||||
protected:
|
||||
static bool _persistent;
|
||||
static bool _long_range;
|
||||
static wifi_mode_t _forceSleepLastMode;
|
||||
static wifi_ps_type_t _sleepEnabled;
|
||||
static bool _wifiUseStaticBuffers;
|
||||
|
||||
static int setStatusBits(int bits);
|
||||
static int clearStatusBits(int bits);
|
||||
|
@ -66,3 +66,18 @@ To use PSK:
|
||||
encryption for the connection
|
||||
|
||||
Please see the WiFiClientPSK example.
|
||||
|
||||
Specifying the ALPN Protocol
|
||||
----------------------------
|
||||
|
||||
Application-Layer Protocol Negotiation (ALPN) is a Transport Layer Security (TLS) extension that allows
|
||||
the application layer to negotiate which protocol should be performed over a secure connection in a manner
|
||||
that avoids additional round trips and which is independent of the application-layer protocols.
|
||||
|
||||
For example, this is used with AWS IoT Custom Authorizers where an MQTT client must set the ALPN protocol to ```mqtt```:
|
||||
|
||||
```
|
||||
const char *aws_protos[] = {"mqtt", NULL};
|
||||
...
|
||||
wiFiClient.setAlpnProtocols(aws_protos);
|
||||
```
|
@ -0,0 +1,97 @@
|
||||
// WiFiClientShowPeerCredentials
|
||||
//
|
||||
// Example of a establishing a secure connection and then
|
||||
// showing the fingerprint of the certificate. This can
|
||||
// be useful in an IoT setting to know for sure that you
|
||||
// are connecting to the right server. Especally in
|
||||
// situations where you cannot hardcode a trusted root
|
||||
// certificate for long periods of time (as they tend to
|
||||
// get replaced more often than the lifecycle of IoT
|
||||
// hardware).
|
||||
//
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#ifndef WIFI_NETWORK
|
||||
#define WIFI_NETWORK "MyWifiNetwork"
|
||||
#endif
|
||||
|
||||
#ifndef WIFI_PASSWD
|
||||
#define WIFI_PASSWD "MySecretWifiPassword"
|
||||
#endif
|
||||
|
||||
#define URL "https://arduino.cc"
|
||||
|
||||
void demo() {
|
||||
WiFiClientSecure *client = new WiFiClientSecure;
|
||||
client->setInsecure(); //
|
||||
|
||||
HTTPClient https;
|
||||
if (!https.begin(*client, URL )) {
|
||||
Serial.println("HTTPS setup failed");
|
||||
return;
|
||||
};
|
||||
|
||||
https.setTimeout(5000);
|
||||
|
||||
int httpCode = https.GET();
|
||||
if (httpCode != 200) {
|
||||
Serial.print("Connect failed: ");
|
||||
Serial.println(https.errorToString(httpCode));
|
||||
return;
|
||||
}
|
||||
|
||||
const mbedtls_x509_crt* peer = client->getPeerCertificate();
|
||||
|
||||
// Show general output / certificate information
|
||||
//
|
||||
char buf[1024];
|
||||
int l = mbedtls_x509_crt_info (buf, sizeof(buf), "", peer);
|
||||
if (l <= 0) {
|
||||
Serial.println("Peer conversion to printable buffer failed");
|
||||
return;
|
||||
};
|
||||
Serial.println();
|
||||
Serial.println(buf);
|
||||
|
||||
uint8_t fingerprint_remote[32];
|
||||
if (!client->getFingerprintSHA256(fingerprint_remote)) {
|
||||
Serial.println("Failed to get the fingerprint");
|
||||
return;
|
||||
}
|
||||
// Fingerprint late 2021
|
||||
Serial.println("Expecting Fingerprint (SHA256): 70 CF A4 B7 5D 09 E9 2A 52 A8 B6 85 B5 0B D6 BE 83 47 83 5B 3A 4D 3C 3E 32 30 EC 1D 61 98 D7 0F");
|
||||
Serial.print( " Received Fingerprint (SHA256): ");
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
Serial.print(fingerprint_remote[i], HEX);
|
||||
Serial.print(" ");
|
||||
};
|
||||
Serial.println("");
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Started " __FILE__ " build " __DATE__ " " __TIME__);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(WIFI_NETWORK, WIFI_PASSWD);
|
||||
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
Serial.println("Wifi fail - rebooting");
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
bool already_tried = false;
|
||||
if ((millis() < 1000) || already_tried)
|
||||
return;
|
||||
already_tried = true;
|
||||
|
||||
// Run the test just once.
|
||||
demo();
|
||||
}
|
@ -29,6 +29,7 @@ connected KEYWORD2
|
||||
setCACert KEYWORD2
|
||||
setCertificate KEYWORD2
|
||||
setPrivateKey KEYWORD2
|
||||
setAlpnProtocols KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
@ -43,6 +43,7 @@ WiFiClientSecure::WiFiClientSecure()
|
||||
_pskIdent = NULL;
|
||||
_psKey = NULL;
|
||||
next = NULL;
|
||||
_alpn_protos = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -66,6 +67,7 @@ WiFiClientSecure::WiFiClientSecure(int sock)
|
||||
_pskIdent = NULL;
|
||||
_psKey = NULL;
|
||||
next = NULL;
|
||||
_alpn_protos = NULL;
|
||||
}
|
||||
|
||||
WiFiClientSecure::~WiFiClientSecure()
|
||||
@ -127,7 +129,7 @@ int WiFiClientSecure::connect(const char *host, uint16_t port, const char *CA_ce
|
||||
if(_timeout > 0){
|
||||
sslclient->handshake_timeout = _timeout;
|
||||
}
|
||||
int ret = start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure);
|
||||
int ret = start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure, _alpn_protos);
|
||||
_lastError = ret;
|
||||
if (ret < 0) {
|
||||
log_e("start_ssl_client: %d", ret);
|
||||
@ -147,7 +149,7 @@ int WiFiClientSecure::connect(const char *host, uint16_t port, const char *pskId
|
||||
if(_timeout > 0){
|
||||
sslclient->handshake_timeout = _timeout;
|
||||
}
|
||||
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure);
|
||||
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure, _alpn_protos);
|
||||
_lastError = ret;
|
||||
if (ret < 0) {
|
||||
log_e("start_ssl_client: %d", ret);
|
||||
@ -341,3 +343,8 @@ void WiFiClientSecure::setHandshakeTimeout(unsigned long handshake_timeout)
|
||||
{
|
||||
sslclient->handshake_timeout = handshake_timeout * 1000;
|
||||
}
|
||||
|
||||
void WiFiClientSecure::setAlpnProtocols(const char **alpn_protos)
|
||||
{
|
||||
_alpn_protos = alpn_protos;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ protected:
|
||||
sslclient_context *sslclient;
|
||||
|
||||
int _lastError = 0;
|
||||
int _peek = -1;
|
||||
int _peek = -1;
|
||||
int _timeout = 0;
|
||||
bool _use_insecure;
|
||||
const char *_CA_cert;
|
||||
@ -39,6 +39,7 @@ protected:
|
||||
const char *_private_key;
|
||||
const char *_pskIdent; // identity for PSK cipher suites
|
||||
const char *_psKey; // key in hex for PSK cipher suites
|
||||
const char **_alpn_protos;
|
||||
|
||||
public:
|
||||
WiFiClientSecure *next;
|
||||
@ -53,7 +54,7 @@ public:
|
||||
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
int peek();
|
||||
int peek();
|
||||
size_t write(uint8_t data);
|
||||
size_t write(const uint8_t *buf, size_t size);
|
||||
int available();
|
||||
@ -73,7 +74,9 @@ public:
|
||||
bool loadPrivateKey(Stream& stream, size_t size);
|
||||
bool verify(const char* fingerprint, const char* domain_name);
|
||||
void setHandshakeTimeout(unsigned long handshake_timeout);
|
||||
|
||||
void setAlpnProtocols(const char **alpn_protos);
|
||||
const mbedtls_x509_crt* getPeerCertificate() { return mbedtls_ssl_get_peer_cert(&sslclient->ssl_ctx); };
|
||||
bool getFingerprintSHA256(uint8_t sha256_result[32]) { return get_peer_fingerprint(sslclient, sha256_result); };
|
||||
int setTimeout(uint32_t seconds){ return 0; }
|
||||
|
||||
operator bool()
|
||||
|
@ -51,7 +51,7 @@ void ssl_init(sslclient_context *ssl_client)
|
||||
}
|
||||
|
||||
|
||||
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure)
|
||||
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure, const char **alpn_protos)
|
||||
{
|
||||
char buf[512];
|
||||
int ret, flags;
|
||||
@ -156,6 +156,13 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
|
||||
return handle_error(ret);
|
||||
}
|
||||
|
||||
if (alpn_protos != NULL) {
|
||||
log_v("Setting ALPN protocols");
|
||||
if ((ret = mbedtls_ssl_conf_alpn_protocols(&ssl_client->ssl_conf, alpn_protos) ) != 0) {
|
||||
return handle_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
// MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and
|
||||
// MBEDTLS_SSL_VERIFY_NONE if not.
|
||||
|
||||
@ -418,22 +425,10 @@ bool verify_ssl_fingerprint(sslclient_context *ssl_client, const char* fp, const
|
||||
fingerprint_local[i] = low | (high << 4);
|
||||
}
|
||||
|
||||
// Get certificate provided by the peer
|
||||
const mbedtls_x509_crt* crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
|
||||
|
||||
if (!crt)
|
||||
{
|
||||
log_d("could not fetch peer certificate");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate certificate's SHA256 fingerprint
|
||||
uint8_t fingerprint_remote[32];
|
||||
mbedtls_sha256_context sha256_ctx;
|
||||
mbedtls_sha256_init(&sha256_ctx);
|
||||
mbedtls_sha256_starts(&sha256_ctx, false);
|
||||
mbedtls_sha256_update(&sha256_ctx, crt->raw.p, crt->raw.len);
|
||||
mbedtls_sha256_finish(&sha256_ctx, fingerprint_remote);
|
||||
if(!get_peer_fingerprint(ssl_client, fingerprint_remote))
|
||||
return false;
|
||||
|
||||
// Check if fingerprints match
|
||||
if (memcmp(fingerprint_local, fingerprint_remote, 32))
|
||||
@ -449,6 +444,28 @@ bool verify_ssl_fingerprint(sslclient_context *ssl_client, const char* fp, const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_peer_fingerprint(sslclient_context *ssl_client, uint8_t sha256[32])
|
||||
{
|
||||
if (!ssl_client) {
|
||||
log_d("Invalid ssl_client pointer");
|
||||
return false;
|
||||
};
|
||||
|
||||
const mbedtls_x509_crt* crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx);
|
||||
if (!crt) {
|
||||
log_d("Failed to get peer cert.");
|
||||
return false;
|
||||
};
|
||||
|
||||
mbedtls_sha256_context sha256_ctx;
|
||||
mbedtls_sha256_init(&sha256_ctx);
|
||||
mbedtls_sha256_starts(&sha256_ctx, false);
|
||||
mbedtls_sha256_update(&sha256_ctx, crt->raw.p, crt->raw.len);
|
||||
mbedtls_sha256_finish(&sha256_ctx, sha256);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if peer certificate has specified domain in CN or SANs
|
||||
bool verify_ssl_dn(sslclient_context *ssl_client, const char* domain_name)
|
||||
{
|
||||
|
@ -29,12 +29,12 @@ typedef struct sslclient_context {
|
||||
|
||||
|
||||
void ssl_init(sslclient_context *ssl_client);
|
||||
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure);
|
||||
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure, const char **alpn_protos);
|
||||
void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int data_to_read(sslclient_context *ssl_client);
|
||||
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, size_t len);
|
||||
int get_ssl_receive(sslclient_context *ssl_client, uint8_t *data, int length);
|
||||
bool verify_ssl_fingerprint(sslclient_context *ssl_client, const char* fp, const char* domain_name);
|
||||
bool verify_ssl_dn(sslclient_context *ssl_client, const char* domain_name);
|
||||
|
||||
bool get_peer_fingerprint(sslclient_context *ssl_client, uint8_t sha256[32]);
|
||||
#endif
|
||||
|
@ -1,276 +0,0 @@
|
||||
# Debugging I2C
|
||||
|
||||
With the release of Arduino-ESP32 V1.0.1 the I2C subsystem contains code to exhaustively report communication errors.
|
||||
* Basic debugging can be enable by setting the *CORE DEBUG LEVEL* at or above *ERROR*. All errors will be directed the the *DEBUG OUTPUT* normally connected to `Serial()`.
|
||||
* Enhanced debugging can be used to generate specified information at specific positions during the i2c communication sequence. Increase *CORE DEBUG LEVEL* to ***DEBUG***
|
||||
|
||||
## Enable Debug Buffer
|
||||
The Enhanced debug features are enabled by uncommenting the `\\#define ENABLE_I2C_DEBUG_BUFFER` at line 45 of `esp32-hal-i2c.c`.
|
||||
* When Arduino-Esp32 is installed in Windows with Arduino Boards Manager, `esp32-hal-i2c.c` can be found in:
|
||||
`C:\Users\{user}\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\`
|
||||
* When Arduino-Esp32 Development version is installed from GitHub, `esp32-hal-i2c.c` can be found in:
|
||||
`{arduino Sketch}\hardware\espressif\esp32\cores\esp32\`
|
||||
|
||||
|
||||
```c++
|
||||
//#define ENABLE_I2C_DEBUG_BUFFER
|
||||
```
|
||||
Change it to:
|
||||
```c++
|
||||
#define ENABLE_I2C_DEBUG_BUFFER
|
||||
```
|
||||
and recompile/upload the resulting code to your ESP32.
|
||||
|
||||
Enabling this `#define` will consume an additional 2570 bytes of RAM and include a commensurate amount of code FLASH. If you see the message `"Debug Buffer not Enabled"` in your console log I would suggest you un-comment the line and regenerate the error. Additional information will be supplied on the log console.
|
||||
|
||||
## Manually controlled Debugging
|
||||
Manual logging of the i2c control data buffers can be accomplished by using the debug control function of `Wire()`:
|
||||
```c++
|
||||
uint32_t setDebugFlags( uint32_t setBits, uint32_t resetBits);
|
||||
```
|
||||
`setBits`, and `resetBits` manually cause output of the control structures to the log console. They are bit fields that enable/disable the reporting of individual control structures during specific phases of the i2c communications sequence. The 32bit values are divided into four 8bit fields. Currently only five bits are defined. ***If an error is detected during normal operations, the relevant control structure will bit added to the log irrespective of the current debug flags.***
|
||||
|
||||
* **bit 0** causes DumpI2c to execute
|
||||
header information about current communications event,
|
||||
and the dataQueue elements showing the logical i2c transaction commands
|
||||
* **bit 1** causes DumpInts to execute
|
||||
Actual sequence of interrupts handled during last communications event, cleared on entry into `ProcQueue()`.
|
||||
* **bit 2** causes DumpCmdqueue to execute
|
||||
The last block of commands to the i2c peripheral.
|
||||
* **bit 3** causes DumpStatus to execute
|
||||
A descriptive display of the 32bit i2c peripheral status word.
|
||||
* **bit 4** causes DumpFifo to execute
|
||||
A buffer listing the sequence of data added to the txFifo of the i2c peripheral.
|
||||
|
||||
Of the four division, only three are currently implemented:
|
||||
* 0xXX - - - - - - : at entry of ProcQueue (`bitFlags << 24`)
|
||||
* 0x - - XX - - - - : at exit of ProcQueue (`bitFlags << 16`)
|
||||
* 0x - - - - - - XX : at entry of Flush (`bitFlags`)
|
||||
|
||||
For example, to display the sequence of Interrupts processed during the i2c communication transaction, **bit 1** would be set, and, since this information on Interrupt usage would only be valid after the communications have completed, the locus would be *at exit of ProcQueue*. The following code would be necessary.
|
||||
### code
|
||||
```c++
|
||||
uint8_t flag = 1 << 1; // turn on bit 1
|
||||
uint32_t debugFlag = flag << 16; // correctly position the 8bits of flag as the second byte of setBits.
|
||||
Wire.setDebugFlags(debugFlag,0);// resetBits=0 says leave all current setBits as is.
|
||||
|
||||
Wire.requestFrom(id,byteCount); // read byteCount bytes from slave at id
|
||||
|
||||
Wire.setDebugFlags(0,debugFlag); // don't add any new debug, remove debugFlag
|
||||
```
|
||||
### output of log console
|
||||
```
|
||||
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
|
||||
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x005baac5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x005baac5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x005baac6
|
||||
```
|
||||
# Debug Log example
|
||||
### Code
|
||||
To read eight bytes of data from a DS1307 RTCC
|
||||
```
|
||||
uint32_t debugFlag = 0x001F0000;
|
||||
uint8_t ID = 0x68;
|
||||
uint8_t block=8;
|
||||
|
||||
if(debugFlag >0){
|
||||
Wire.setDebugFlags(debugFlag,0);
|
||||
}
|
||||
|
||||
Wire.beginTransmission(ID);
|
||||
Wire.write(lowByte(addr));
|
||||
if((err=Wire.endTransmission(false))!=0) {
|
||||
Serial.printf(" EndTransmission=%d(%s)",Wire.lastError(),Wire.getErrorText(Wire.lastError()));
|
||||
|
||||
if(err!=2) {
|
||||
Serial.printf(", resetting\n");
|
||||
if( !Wire.begin()) Serial.printf(" Reset Failed\n");
|
||||
if(debugFlag >0) Wire.setDebugFlags(0,debugFlag);
|
||||
return;
|
||||
} else {
|
||||
Serial.printf(", No Device present, aborting\n");
|
||||
currentCommand= NO_COMMAND;
|
||||
return;
|
||||
}
|
||||
}
|
||||
err = Wire.requestFrom(ID,block,true);
|
||||
if(debugFlag >0){
|
||||
Wire.setDebugFlags(0,debugFlag);
|
||||
}
|
||||
```
|
||||
### output of log console
|
||||
```
|
||||
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
|
||||
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78
|
||||
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
|
||||
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
|
||||
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
|
||||
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
|
||||
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
|
||||
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
|
||||
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10
|
||||
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4
|
||||
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c
|
||||
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2
|
||||
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1
|
||||
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0
|
||||
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
|
||||
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000
|
||||
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101
|
||||
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00
|
||||
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111
|
||||
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00
|
||||
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6)
|
||||
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0
|
||||
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68
|
||||
```
|
||||
## Explaination of log output
|
||||
### DumpI2c
|
||||
```
|
||||
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
|
||||
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78
|
||||
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
|
||||
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
|
||||
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
|
||||
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
|
||||
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
|
||||
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
|
||||
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10
|
||||
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4
|
||||
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c
|
||||
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2
|
||||
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1
|
||||
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0
|
||||
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
|
||||
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000
|
||||
```
|
||||
variable | description
|
||||
---- | ----
|
||||
**i2c** | *memory address for control block*
|
||||
**dev** | *memory address for access to i2c peripheral registers*
|
||||
**date** | *revision date of peripheral silicon 2016, 42 week*
|
||||
**lock** | *hal lock handle*
|
||||
**num** | *0,1 which peripheral is being controlled*
|
||||
**mode** | *configuration of driver 0=none, 1=MASTER, 2=SLAVE, 3=MASTER and SLAVE*
|
||||
**stage** | *internal STATE of driver 0=not configured, 1=startup, 2=running, 3=done*
|
||||
**error** | *internal ERROR status 0=not configured, 1=ok, 2=error, 3=address NAK, 4=data NAK, 5=arbitration loss, 6=timeout*
|
||||
**event** | *handle for interprocess FreeRTOS eventSemaphore for communication between ISR and APP*
|
||||
**intr_handle** | *FreeRTOS handle for allocated interrupt*
|
||||
**dq** | *memory address for data queue control block*
|
||||
**queueCount** | *number of data operations in queue control block*
|
||||
**queuePos** | *last executed data block*
|
||||
**errorByteCnt** | *position in current data block when error occured -1=address byte*
|
||||
**errorQueue** | *queue that was executing when error occurred*
|
||||
**debugFlags** | *current specified error bits*
|
||||
|
||||
### DQ data
|
||||
```
|
||||
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101
|
||||
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00
|
||||
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111
|
||||
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00
|
||||
```
|
||||
variable | description
|
||||
--- | ---
|
||||
**[n]** | *index of data queue element*
|
||||
**i2c address** | *7bit= 7bit i2c slave address, 10bit= 10bit i2c slave address*
|
||||
**direction** | *W=Write, R=READ*
|
||||
**STOP** | *command issued a I2C STOP, else if blank, a RESTART was issued by next dq element.*
|
||||
**buf@** | *pointer to data buffer*
|
||||
**len** | *length of data buffer*
|
||||
**pos** | *last position used in buffer*
|
||||
**ctrl** | *bit field for data queue control, this bits describe if all necessary commands have been added to peripheral command buffer. in order(START,ADDRESS_Write,DATA,STOP,ADDRESS_value*
|
||||
**0xnnnn** | *data buffer content, displayable followed by HEX, 32 bytes on a line.*
|
||||
|
||||
### DumpInts
|
||||
```
|
||||
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5
|
||||
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6
|
||||
```
|
||||
variable | description
|
||||
---- | ----
|
||||
**row** | *array index*
|
||||
**count** | *number of consecutive, duplicate interrupts*
|
||||
**INTR** | *bit value of active interrupt (from ..\esp32\tools\sdk\include\soc\soc\i2c_struct.h)*
|
||||
**TX** | *number of bytes added to txFifo*
|
||||
**RX** | *number of bytes read from rxFifo*
|
||||
**Tick** | *current tick counter from xTaskGetTickCountFromISR()*
|
||||
|
||||
### DumpCmdQueue
|
||||
```
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0]
|
||||
```
|
||||
Column | description
|
||||
---- | ----
|
||||
**command** | *RSTART= generate i2c START sequence, WRITE= output byte(s), READ= input byte(s), STOP= generate i2c STOP sequence, END= continuation flag for peripheral to pause execution waiting for a refilled command list*
|
||||
**val** | *value for ACK bit, 0 = LOW, 1= HIGH*
|
||||
**exp** | *test of ACK bit 0=no, 1=yes*
|
||||
**en** | *output of val, 0=no, 1=yes*
|
||||
**bytes** | *number of byte to send(WRITE) or receive(READ) 1..255*
|
||||
|
||||
### DumpStatus
|
||||
```
|
||||
[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6)
|
||||
```
|
||||
variable | description
|
||||
---- | ----
|
||||
**ack** | *last value for ACK bit*
|
||||
**sl_rw** | *mode for SLAVE operation 0=write, 1=read*
|
||||
**to** | *timeout*
|
||||
**arb** | *arbitration loss*
|
||||
**busy** | *bus is inuse by other Master, or SLAVE is holding SCL,SDA*
|
||||
**sl** | *last address on bus was equal to slave_addr*
|
||||
**trans** | *a byte has moved though peripheral*
|
||||
**rx** | *count of bytes in rxFifo*
|
||||
**tx** | *count of bytes in txFifo*
|
||||
**sclMain** | *state machine for i2c module. 0: SCL_MAIN_IDLE, 1: SCL_ADDRESS_SHIFT, 2: SCL_ACK_ADDRESS, 3: SCL_RX_DATA, 4: SCL_TX_DATA, 5: SCL_SEND_ACK, 6 :SCL_WAIT_ACK*
|
||||
**scl** | *SCL clock state. 0: SCL_IDLE, 1: SCL_START, 2: SCL_LOW_EDGE, 3: SCL_LOW, 4: SCL_HIGH_EDGE, 5: SCL_HIGH, 6:SCL_STOP*
|
||||
|
||||
### DumpFifo
|
||||
```
|
||||
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0
|
||||
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68
|
||||
```
|
||||
Mode | datavalues
|
||||
--- | ---
|
||||
**WRITE** | the following bytes added to the txFifo are in response to a WRITE command
|
||||
**READ** | the following bytes added to the txFifo are in response to a READ command
|
||||
|
30
libraries/Wire/examples/WireMaster/WireMaster.ino
Normal file
30
libraries/Wire/examples/WireMaster/WireMaster.ino
Normal file
@ -0,0 +1,30 @@
|
||||
#include "Wire.h"
|
||||
|
||||
#define I2C_DEV_ADDR 0x55
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.setDebugOutput(true);
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(5000);
|
||||
|
||||
//Write message to the slave
|
||||
Wire.beginTransmission(I2C_DEV_ADDR);
|
||||
Wire.printf("Hello World! %u", i++);
|
||||
uint8_t error = Wire.endTransmission(true);
|
||||
Serial.printf("endTransmission: %u\n", error);
|
||||
|
||||
//Read 16 bytes from the slave
|
||||
error = Wire.requestFrom(I2C_DEV_ADDR, 16);
|
||||
Serial.printf("requestFrom: %u\n", error);
|
||||
if(error){
|
||||
uint8_t temp[error];
|
||||
Wire.readBytes(temp, error);
|
||||
log_print_buf(temp, error);
|
||||
}
|
||||
}
|
28
libraries/Wire/examples/WireScan/WireScan.ino
Normal file
28
libraries/Wire/examples/WireScan/WireScan.ino
Normal file
@ -0,0 +1,28 @@
|
||||
#include "Wire.h"
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
byte error, address;
|
||||
int nDevices = 0;
|
||||
|
||||
delay(5000);
|
||||
|
||||
Serial.println("Scanning for I2C devices ...");
|
||||
for(address = 0x01; address < 0x7f; address++){
|
||||
Wire.beginTransmission(address);
|
||||
error = Wire.endTransmission();
|
||||
if (error == 0){
|
||||
Serial.printf("I2C device found at address 0x%02X\n", address);
|
||||
nDevices++;
|
||||
} else if(error != 2){
|
||||
Serial.printf("Error %d at address 0x%02X\n", error, address);
|
||||
}
|
||||
}
|
||||
if (nDevices == 0){
|
||||
Serial.println("No I2C devices found");
|
||||
}
|
||||
}
|
37
libraries/Wire/examples/WireSlave/WireSlave.ino
Normal file
37
libraries/Wire/examples/WireSlave/WireSlave.ino
Normal file
@ -0,0 +1,37 @@
|
||||
#include "Wire.h"
|
||||
|
||||
#define I2C_DEV_ADDR 0x55
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
void onRequest(){
|
||||
Wire.print(i++);
|
||||
Wire.print(" Packets.");
|
||||
Serial.println("onRequest");
|
||||
}
|
||||
|
||||
void onReceive(int len){
|
||||
Serial.printf("onReceive[%d]: ", len);
|
||||
while(Wire.available()){
|
||||
Serial.write(Wire.read());
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.setDebugOutput(true);
|
||||
Wire.onReceive(onReceive);
|
||||
Wire.onRequest(onRequest);
|
||||
Wire.begin((uint8_t)I2C_DEV_ADDR);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
char message[64];
|
||||
snprintf(message, 64, "%u Packets.", i++);
|
||||
Wire.slaveWrite((uint8_t *)message, strlen(message));
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
}
|
@ -11,13 +11,14 @@
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
end KEYWORD2
|
||||
setClock KEYWORD2
|
||||
setClockStretchLimit KEYWORD2
|
||||
getClock KEYWORD2
|
||||
setTimeOut KEYWORD2
|
||||
getTimeOut KEYWORD2
|
||||
beginTransmission KEYWORD2
|
||||
endTransmission KEYWORD2
|
||||
requestFrom KEYWORD2
|
||||
send KEYWORD2
|
||||
receive KEYWORD2
|
||||
onReceive KEYWORD2
|
||||
onRequest KEYWORD2
|
||||
|
||||
@ -26,6 +27,7 @@ onRequest KEYWORD2
|
||||
#######################################
|
||||
|
||||
Wire KEYWORD2
|
||||
TwoWire KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
@ -20,6 +20,7 @@
|
||||
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
|
||||
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
|
||||
Modified Nov 2017 by Chuck Todd (ctodd@cableone.net) - ESP32 ISR Support
|
||||
Modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
@ -29,6 +30,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "esp32-hal-i2c.h"
|
||||
#include "esp32-hal-i2c-slave.h"
|
||||
#include "Wire.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
@ -36,40 +38,32 @@ TwoWire::TwoWire(uint8_t bus_num)
|
||||
:num(bus_num & 1)
|
||||
,sda(-1)
|
||||
,scl(-1)
|
||||
,i2c(NULL)
|
||||
,rxIndex(0)
|
||||
,rxLength(0)
|
||||
,rxQueued(0)
|
||||
,txIndex(0)
|
||||
,txLength(0)
|
||||
,txAddress(0)
|
||||
,txQueued(0)
|
||||
,transmitting(0)
|
||||
,last_error(I2C_ERROR_OK)
|
||||
,_timeOutMillis(50)
|
||||
,nonStop(false)
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
,nonStopTask(NULL)
|
||||
,lock(NULL)
|
||||
#endif
|
||||
,is_slave(false)
|
||||
,user_onRequest(NULL)
|
||||
,user_onReceive(NULL)
|
||||
{}
|
||||
|
||||
TwoWire::~TwoWire()
|
||||
{
|
||||
flush();
|
||||
if(i2c) {
|
||||
i2cRelease(i2c);
|
||||
i2c=NULL;
|
||||
end();
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(lock != NULL){
|
||||
vSemaphoreDelete(lock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TwoWire::setPins(int sdaPin, int sclPin)
|
||||
{
|
||||
if(i2c) {
|
||||
log_e("can not set pins if begin was already called");
|
||||
return false;
|
||||
}
|
||||
sda = sdaPin;
|
||||
scl = sclPin;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
|
||||
bool TwoWire::initPins(int sdaPin, int sclPin)
|
||||
{
|
||||
if(sdaPin < 0) { // default param passed
|
||||
if(num == 0) {
|
||||
@ -107,14 +101,195 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
|
||||
|
||||
sda = sdaPin;
|
||||
scl = sclPin;
|
||||
i2c = i2cInit(num, sda, scl, frequency);
|
||||
if(!i2c) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TwoWire::setPins(int sdaPin, int sclPin)
|
||||
{
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(lock == NULL){
|
||||
lock = xSemaphoreCreateMutex();
|
||||
if(lock == NULL){
|
||||
log_e("xSemaphoreCreateMutex failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//acquire lock
|
||||
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(!i2cIsInit(num)){
|
||||
initPins(sdaPin, sclPin);
|
||||
} else {
|
||||
log_e("bus already initialized. change pins only when not.");
|
||||
}
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
return !i2cIsInit(num);
|
||||
}
|
||||
|
||||
flush();
|
||||
return true;
|
||||
// Slave Begin
|
||||
bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
|
||||
{
|
||||
bool started = false;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(lock == NULL){
|
||||
lock = xSemaphoreCreateMutex();
|
||||
if(lock == NULL){
|
||||
log_e("xSemaphoreCreateMutex failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//acquire lock
|
||||
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(is_slave){
|
||||
log_w("Bus already started in Slave Mode.");
|
||||
started = true;
|
||||
goto end;
|
||||
}
|
||||
if(i2cIsInit(num)){
|
||||
log_e("Bus already started in Master Mode.");
|
||||
goto end;
|
||||
}
|
||||
if(!initPins(sdaPin, sclPin)){
|
||||
goto end;
|
||||
}
|
||||
i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this);
|
||||
if(i2cSlaveInit(num, sda, scl, addr, frequency, I2C_BUFFER_LENGTH, I2C_BUFFER_LENGTH) != ESP_OK){
|
||||
log_e("Slave Init ERROR");
|
||||
goto end;
|
||||
}
|
||||
is_slave = true;
|
||||
started = true;
|
||||
end:
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
return started;
|
||||
}
|
||||
|
||||
// Master Begin
|
||||
bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
|
||||
{
|
||||
bool started = false;
|
||||
esp_err_t err = ESP_OK;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(lock == NULL){
|
||||
lock = xSemaphoreCreateMutex();
|
||||
if(lock == NULL){
|
||||
log_e("xSemaphoreCreateMutex failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//acquire lock
|
||||
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(is_slave){
|
||||
log_e("Bus already started in Slave Mode.");
|
||||
goto end;
|
||||
}
|
||||
if(i2cIsInit(num)){
|
||||
log_w("Bus already started in Master Mode.");
|
||||
started = true;
|
||||
goto end;
|
||||
}
|
||||
if(!initPins(sdaPin, sclPin)){
|
||||
goto end;
|
||||
}
|
||||
err = i2cInit(num, sda, scl, frequency);
|
||||
started = (err == ESP_OK);
|
||||
|
||||
end:
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
return started;
|
||||
|
||||
}
|
||||
|
||||
bool TwoWire::end()
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(lock != NULL){
|
||||
//acquire lock
|
||||
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(is_slave){
|
||||
err = i2cSlaveDeinit(num);
|
||||
if(err == ESP_OK){
|
||||
is_slave = false;
|
||||
}
|
||||
} else if(i2cIsInit(num)){
|
||||
err = i2cDeinit(num);
|
||||
}
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
}
|
||||
#endif
|
||||
return (err == ESP_OK);
|
||||
}
|
||||
|
||||
uint32_t TwoWire::getClock()
|
||||
{
|
||||
uint32_t frequency = 0;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//acquire lock
|
||||
if(lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
} else {
|
||||
#endif
|
||||
if(is_slave){
|
||||
log_e("Bus is in Slave Mode");
|
||||
} else {
|
||||
i2cGetClock(num, &frequency);
|
||||
}
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
}
|
||||
#endif
|
||||
return frequency;
|
||||
}
|
||||
|
||||
bool TwoWire::setClock(uint32_t frequency)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//acquire lock
|
||||
if(lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(is_slave){
|
||||
log_e("Bus is in Slave Mode");
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
err = i2cSetClock(num, frequency);
|
||||
}
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
return (err == ESP_OK);
|
||||
}
|
||||
|
||||
void TwoWire::setTimeOut(uint16_t timeOutMillis)
|
||||
@ -127,118 +302,104 @@ uint16_t TwoWire::getTimeOut()
|
||||
return _timeOutMillis;
|
||||
}
|
||||
|
||||
void TwoWire::setClock(uint32_t frequency)
|
||||
void TwoWire::beginTransmission(uint16_t address)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
i2c = i2cInit(num, sda, scl, frequency);
|
||||
if(!i2c) {
|
||||
if(is_slave){
|
||||
log_e("Bus is in Slave Mode");
|
||||
return;
|
||||
}
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(nonStop && nonStopTask == xTaskGetCurrentTaskHandle()){
|
||||
log_e("Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing...");
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
}
|
||||
//acquire lock
|
||||
if(lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
i2cSetFrequency(i2c, frequency);
|
||||
}
|
||||
|
||||
size_t TwoWire::getClock()
|
||||
{
|
||||
return i2cGetFrequency(i2c);
|
||||
}
|
||||
|
||||
/* stickBreaker Nov 2017 ISR, and bigblock 64k-1
|
||||
*/
|
||||
i2c_err_t TwoWire::writeTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop)
|
||||
{
|
||||
last_error = i2cWrite(i2c, address, buff, size, sendStop, _timeOutMillis);
|
||||
return last_error;
|
||||
}
|
||||
|
||||
i2c_err_t TwoWire::readTransmission(uint16_t address, uint8_t *buff, uint16_t size, bool sendStop, uint32_t *readCount)
|
||||
{
|
||||
last_error = i2cRead(i2c, address, buff, size, sendStop, _timeOutMillis, readCount);
|
||||
return last_error;
|
||||
}
|
||||
|
||||
void TwoWire::beginTransmission(uint16_t address)
|
||||
{
|
||||
transmitting = 1;
|
||||
nonStop = false;
|
||||
txAddress = address;
|
||||
txIndex = txQueued; // allow multiple beginTransmission(),write(),endTransmission(false) until endTransmission(true)
|
||||
txLength = txQueued;
|
||||
last_error = I2C_ERROR_OK;
|
||||
}
|
||||
|
||||
/*stickbreaker isr
|
||||
*/
|
||||
uint8_t TwoWire::endTransmission(bool sendStop) // Assumes Wire.beginTransaction(), Wire.write()
|
||||
{
|
||||
if(transmitting == 1) {
|
||||
// txlength is howmany bytes in txbuffer have been use
|
||||
last_error = writeTransmission(txAddress, &txBuffer[txQueued], txLength - txQueued, sendStop);
|
||||
if(last_error == I2C_ERROR_CONTINUE){
|
||||
txQueued = txLength;
|
||||
} else if( last_error == I2C_ERROR_OK){
|
||||
rxIndex = 0;
|
||||
rxLength = rxQueued;
|
||||
rxQueued = 0;
|
||||
txQueued = 0; // the SendStop=true will restart all Queueing
|
||||
}
|
||||
} else {
|
||||
last_error = I2C_ERROR_NO_BEGIN;
|
||||
flush();
|
||||
}
|
||||
txIndex = 0;
|
||||
txLength = 0;
|
||||
transmitting = 0;
|
||||
return (last_error == I2C_ERROR_CONTINUE)?I2C_ERROR_OK:last_error; // Don't return Continue for compatibility.
|
||||
}
|
||||
|
||||
/* @stickBreaker 11/2017 fix for ReSTART timeout, ISR
|
||||
*/
|
||||
uint8_t TwoWire::endTransmission(bool sendStop)
|
||||
{
|
||||
if(is_slave){
|
||||
log_e("Bus is in Slave Mode");
|
||||
return 4;
|
||||
}
|
||||
esp_err_t err = ESP_OK;
|
||||
if(sendStop){
|
||||
err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis);
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
} else {
|
||||
//mark as non-stop
|
||||
nonStop = true;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
nonStopTask = xTaskGetCurrentTaskHandle();
|
||||
#endif
|
||||
}
|
||||
switch(err){
|
||||
case ESP_OK: return 0;
|
||||
case ESP_FAIL: return 2;
|
||||
case ESP_ERR_TIMEOUT: return 5;
|
||||
default: break;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop)
|
||||
{
|
||||
//use internal Wire rxBuffer, multiple requestFrom()'s may be pending, try to share rxBuffer
|
||||
uint32_t cnt = rxQueued; // currently queued reads, next available position in rxBuffer
|
||||
if(cnt < (I2C_BUFFER_LENGTH-1) && (size + cnt) <= I2C_BUFFER_LENGTH) { // any room left in rxBuffer
|
||||
rxQueued += size;
|
||||
} else { // no room to receive more!
|
||||
log_e("rxBuff overflow %d", cnt + size);
|
||||
cnt = 0;
|
||||
last_error = I2C_ERROR_MEMORY;
|
||||
flush();
|
||||
return cnt;
|
||||
if(is_slave){
|
||||
log_e("Bus is in Slave Mode");
|
||||
return 0;
|
||||
}
|
||||
|
||||
last_error = readTransmission(address, &rxBuffer[cnt], size, sendStop, &cnt);
|
||||
rxIndex = 0;
|
||||
|
||||
rxLength = cnt;
|
||||
|
||||
if( last_error != I2C_ERROR_CONTINUE){ // not a buffered ReSTART operation
|
||||
// so this operation actually moved data, queuing is done.
|
||||
rxQueued = 0;
|
||||
txQueued = 0; // the SendStop=true will restart all Queueing or error condition
|
||||
esp_err_t err = ESP_OK;
|
||||
if(nonStop
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
&& nonStopTask == xTaskGetCurrentTaskHandle()
|
||||
#endif
|
||||
){
|
||||
if(address != txAddress){
|
||||
log_e("Unfinished Repeated Start transaction! Expected address do not match! %u != %u", address, txAddress);
|
||||
return 0;
|
||||
}
|
||||
nonStop = false;
|
||||
rxIndex = 0;
|
||||
rxLength = 0;
|
||||
err = i2cWriteReadNonStop(num, address, txBuffer, txLength, rxBuffer, size, _timeOutMillis, &rxLength);
|
||||
} else {
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//acquire lock
|
||||
if(lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
|
||||
log_e("could not acquire lock");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
rxIndex = 0;
|
||||
rxLength = 0;
|
||||
err = i2cRead(num, address, rxBuffer, size, _timeOutMillis, &rxLength);
|
||||
}
|
||||
|
||||
if(last_error != I2C_ERROR_OK){ // ReSTART on read does not return any data
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
//release lock
|
||||
xSemaphoreGive(lock);
|
||||
#endif
|
||||
return rxLength;
|
||||
}
|
||||
|
||||
size_t TwoWire::write(uint8_t data)
|
||||
{
|
||||
if(transmitting) {
|
||||
if(txLength >= I2C_BUFFER_LENGTH) {
|
||||
last_error = I2C_ERROR_MEMORY;
|
||||
return 0;
|
||||
}
|
||||
txBuffer[txIndex] = data;
|
||||
++txIndex;
|
||||
txLength = txIndex;
|
||||
return 1;
|
||||
if(txLength >= I2C_BUFFER_LENGTH) {
|
||||
return 0;
|
||||
}
|
||||
last_error = I2C_ERROR_NO_BEGIN; // no begin, not transmitting
|
||||
return 0;
|
||||
txBuffer[txLength++] = data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t TwoWire::write(const uint8_t *data, size_t quantity)
|
||||
@ -262,8 +423,7 @@ int TwoWire::read(void)
|
||||
{
|
||||
int value = -1;
|
||||
if(rxIndex < rxLength) {
|
||||
value = rxBuffer[rxIndex];
|
||||
++rxIndex;
|
||||
value = rxBuffer[rxIndex++];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -281,11 +441,8 @@ void TwoWire::flush(void)
|
||||
{
|
||||
rxIndex = 0;
|
||||
rxLength = 0;
|
||||
txIndex = 0;
|
||||
txLength = 0;
|
||||
rxQueued = 0;
|
||||
txQueued = 0;
|
||||
i2cFlush(i2c); // cleanup
|
||||
//i2cFlush(num); // cleanup
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop)
|
||||
@ -333,56 +490,49 @@ uint8_t TwoWire::endTransmission(void)
|
||||
return endTransmission(true);
|
||||
}
|
||||
|
||||
/* stickbreaker Nov2017 better error reporting
|
||||
*/
|
||||
uint8_t TwoWire::lastError()
|
||||
size_t TwoWire::slaveWrite(const uint8_t * buffer, size_t len)
|
||||
{
|
||||
return (uint8_t)last_error;
|
||||
return i2cSlaveWrite(num, buffer, len, _timeOutMillis);
|
||||
}
|
||||
|
||||
const char ERRORTEXT[] =
|
||||
"OK\0"
|
||||
"DEVICE\0"
|
||||
"ACK\0"
|
||||
"TIMEOUT\0"
|
||||
"BUS\0"
|
||||
"BUSY\0"
|
||||
"MEMORY\0"
|
||||
"CONTINUE\0"
|
||||
"NO_BEGIN\0"
|
||||
"\0";
|
||||
|
||||
|
||||
char * TwoWire::getErrorText(uint8_t err)
|
||||
void TwoWire::onReceiveService(uint8_t num, uint8_t* inBytes, size_t numBytes, bool stop, void * arg)
|
||||
{
|
||||
uint8_t t = 0;
|
||||
bool found = false;
|
||||
char * message = (char*)&ERRORTEXT;
|
||||
|
||||
while(!found && message[0]) {
|
||||
found = t == err;
|
||||
if(!found) {
|
||||
message = message + strlen(message) + 1;
|
||||
t++;
|
||||
}
|
||||
TwoWire * wire = (TwoWire*)arg;
|
||||
if(!wire->user_onReceive){
|
||||
return;
|
||||
}
|
||||
if(!found) {
|
||||
return NULL;
|
||||
} else {
|
||||
return message;
|
||||
for(uint8_t i = 0; i < numBytes; ++i){
|
||||
wire->rxBuffer[i] = inBytes[i];
|
||||
}
|
||||
wire->rxIndex = 0;
|
||||
wire->rxLength = numBytes;
|
||||
wire->user_onReceive(numBytes);
|
||||
}
|
||||
|
||||
void TwoWire::onRequestService(uint8_t num, void * arg)
|
||||
{
|
||||
TwoWire * wire = (TwoWire*)arg;
|
||||
if(!wire->user_onRequest){
|
||||
return;
|
||||
}
|
||||
wire->txLength = 0;
|
||||
wire->user_onRequest();
|
||||
if(wire->txLength){
|
||||
wire->slaveWrite((uint8_t*)wire->txBuffer, wire->txLength);
|
||||
}
|
||||
}
|
||||
|
||||
/*stickbreaker Dump i2c Interrupt buffer, i2c isr Debugging
|
||||
*/
|
||||
|
||||
uint32_t TwoWire::setDebugFlags( uint32_t setBits, uint32_t resetBits){
|
||||
return i2cDebug(i2c,setBits,resetBits);
|
||||
void TwoWire::onReceive( void (*function)(int) )
|
||||
{
|
||||
user_onReceive = function;
|
||||
}
|
||||
|
||||
bool TwoWire::busy(void){
|
||||
return ((i2cGetStatus(i2c) & 16 )==16);
|
||||
// sets function called on slave read
|
||||
void TwoWire::onRequest( void (*function)(void) )
|
||||
{
|
||||
user_onRequest = function;
|
||||
}
|
||||
|
||||
|
||||
TwoWire Wire = TwoWire(0);
|
||||
TwoWire Wire1 = TwoWire(1);
|
||||
|
@ -20,17 +20,20 @@
|
||||
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
|
||||
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
|
||||
Modified November 2017 by Chuck Todd <stickbreaker on GitHub> to use ISR and increase stability.
|
||||
Modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
|
||||
*/
|
||||
|
||||
#ifndef TwoWire_h
|
||||
#define TwoWire_h
|
||||
|
||||
#include <esp32-hal.h>
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#endif
|
||||
#include "Stream.h"
|
||||
|
||||
#define STICKBREAKER 'V1.1.0'
|
||||
#ifndef I2C_BUFFER_LENGTH
|
||||
#define I2C_BUFFER_LENGTH 128
|
||||
#endif
|
||||
@ -43,28 +46,28 @@ protected:
|
||||
uint8_t num;
|
||||
int8_t sda;
|
||||
int8_t scl;
|
||||
i2c_t * i2c;
|
||||
|
||||
uint8_t rxBuffer[I2C_BUFFER_LENGTH];
|
||||
uint16_t rxIndex;
|
||||
uint16_t rxLength;
|
||||
uint16_t rxQueued; //@stickBreaker
|
||||
size_t rxIndex;
|
||||
size_t rxLength;
|
||||
|
||||
uint8_t txBuffer[I2C_BUFFER_LENGTH];
|
||||
uint16_t txIndex;
|
||||
uint16_t txLength;
|
||||
size_t txLength;
|
||||
uint16_t txAddress;
|
||||
uint16_t txQueued; //@stickbreaker
|
||||
|
||||
uint8_t transmitting;
|
||||
/* slave Mode, not yet Stickbreaker
|
||||
static user_onRequest uReq[2];
|
||||
static user_onReceive uRcv[2];
|
||||
void onRequestService(void);
|
||||
void onReceiveService(uint8_t*, int);
|
||||
*/
|
||||
i2c_err_t last_error; // @stickBreaker from esp32-hal-i2c.h
|
||||
uint16_t _timeOutMillis;
|
||||
uint32_t _timeOutMillis;
|
||||
bool nonStop;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
TaskHandle_t nonStopTask;
|
||||
SemaphoreHandle_t lock;
|
||||
#endif
|
||||
private:
|
||||
bool is_slave;
|
||||
void (*user_onRequest)(void);
|
||||
void (*user_onReceive)(int);
|
||||
static void onRequestService(uint8_t, void *);
|
||||
static void onReceiveService(uint8_t, uint8_t*, size_t, bool, void *);
|
||||
bool initPins(int sdaPin, int sclPin);
|
||||
|
||||
public:
|
||||
TwoWire(uint8_t bus_num);
|
||||
@ -74,20 +77,14 @@ public:
|
||||
bool setPins(int sda, int scl);
|
||||
|
||||
bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus
|
||||
// calling will attemp to recover hung bus
|
||||
|
||||
void setClock(uint32_t frequency); // change bus clock without initing hardware
|
||||
size_t getClock(); // current bus clock rate in hz
|
||||
bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);
|
||||
bool end();
|
||||
|
||||
void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms
|
||||
uint16_t getTimeOut();
|
||||
|
||||
uint8_t lastError();
|
||||
char * getErrorText(uint8_t err);
|
||||
|
||||
//@stickBreaker for big blocks and ISR model
|
||||
i2c_err_t writeTransmission(uint16_t address, uint8_t* buff, uint16_t size, bool sendStop=true);
|
||||
i2c_err_t readTransmission(uint16_t address, uint8_t* buff, uint16_t size, bool sendStop=true, uint32_t *readCount=NULL);
|
||||
bool setClock(uint32_t);
|
||||
uint32_t getClock();
|
||||
|
||||
void beginTransmission(uint16_t address);
|
||||
void beginTransmission(uint8_t address);
|
||||
@ -134,22 +131,10 @@ public:
|
||||
|
||||
void onReceive( void (*)(int) );
|
||||
void onRequest( void (*)(void) );
|
||||
|
||||
uint32_t setDebugFlags( uint32_t setBits, uint32_t resetBits);
|
||||
bool busy();
|
||||
size_t slaveWrite(const uint8_t *, size_t);
|
||||
};
|
||||
|
||||
extern TwoWire Wire;
|
||||
extern TwoWire Wire1;
|
||||
|
||||
|
||||
/*
|
||||
V1.1.0 08JAN2019 Support CPU Clock frequency changes
|
||||
V1.0.2 30NOV2018 stop returning I2C_ERROR_CONTINUE on ReSTART operations, regain compatibility with Arduino libs
|
||||
V1.0.1 02AUG2018 First Fix after release, Correct ReSTART handling, change Debug control, change begin()
|
||||
to a function, this allow reporting if bus cannot be initialized, Wire.begin() can be used to recover
|
||||
a hung bus busy condition.
|
||||
V0.2.2 13APR2018 preserve custom SCL,SDA,Frequency when no parameters passed to begin()
|
||||
V0.2.1 15MAR2018 Hardware reset, Glitch prevention, adding destructor for second i2c testing
|
||||
*/
|
||||
#endif
|
||||
|
44
platform.txt
44
platform.txt
File diff suppressed because one or more lines are too long
876
tools/esptool.py
876
tools/esptool.py
File diff suppressed because it is too large
Load Diff
@ -73,6 +73,7 @@ SUBTYPES = {
|
||||
'coredump': 0x03,
|
||||
'nvs_keys': 0x04,
|
||||
'efuse': 0x05,
|
||||
'undefined': 0x06,
|
||||
'esphttpd': 0x80,
|
||||
'fat': 0x81,
|
||||
'spiffs': 0x82,
|
||||
@ -91,6 +92,19 @@ def get_subtype_as_int(ptype, subtype):
|
||||
return subtype
|
||||
|
||||
|
||||
ALIGNMENT = {
|
||||
APP_TYPE: 0x10000,
|
||||
DATA_TYPE: 0x4,
|
||||
}
|
||||
|
||||
|
||||
STRICT_DATA_ALIGNMENT = 0x1000
|
||||
|
||||
|
||||
def get_alignment_for_type(ptype):
|
||||
return ALIGNMENT.get(ptype, ALIGNMENT[DATA_TYPE])
|
||||
|
||||
|
||||
quiet = False
|
||||
md5sum = True
|
||||
secure = False
|
||||
@ -143,8 +157,8 @@ class PartitionTable(list):
|
||||
continue
|
||||
try:
|
||||
res.append(PartitionDefinition.from_csv(line, line_no + 1))
|
||||
except InputError as e:
|
||||
raise InputError('Error at line %d: %s' % (line_no + 1, e))
|
||||
except InputError as err:
|
||||
raise InputError('Error at line %d: %s' % (line_no + 1, err))
|
||||
except Exception:
|
||||
critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line))
|
||||
raise
|
||||
@ -160,7 +174,7 @@ class PartitionTable(list):
|
||||
raise InputError('CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x'
|
||||
% (e.line_no, e.offset, last_end))
|
||||
if e.offset is None:
|
||||
pad_to = 0x10000 if e.type == APP_TYPE else 4
|
||||
pad_to = get_alignment_for_type(e.type)
|
||||
if last_end % pad_to != 0:
|
||||
last_end += pad_to - (last_end % pad_to)
|
||||
e.offset = last_end
|
||||
@ -210,10 +224,10 @@ class PartitionTable(list):
|
||||
|
||||
# print sorted duplicate partitions by name
|
||||
if len(duplicates) != 0:
|
||||
print('A list of partitions that have the same name:')
|
||||
critical('A list of partitions that have the same name:')
|
||||
for p in sorted(self, key=lambda x:x.name):
|
||||
if len(duplicates.intersection([p.name])) != 0:
|
||||
print('%s' % (p.to_csv()))
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('Partition names must be unique')
|
||||
|
||||
# check for overlaps
|
||||
@ -225,6 +239,18 @@ class PartitionTable(list):
|
||||
raise InputError('Partition at 0x%x overlaps 0x%x-0x%x' % (p.offset, last.offset, last.offset + last.size - 1))
|
||||
last = p
|
||||
|
||||
# check that otadata should be unique
|
||||
otadata_duplicates = [p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['ota']]
|
||||
if len(otadata_duplicates) > 1:
|
||||
for p in otadata_duplicates:
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('Found multiple otadata partitions. Only one partition can be defined with type="data"(1) and subtype="ota"(0).')
|
||||
|
||||
if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000:
|
||||
p = otadata_duplicates[0]
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('otadata partition must have size = 0x2000')
|
||||
|
||||
def flash_size(self):
|
||||
""" Return the size that partitions will occupy in flash
|
||||
(ie the offset the last partition ends at)
|
||||
@ -274,11 +300,6 @@ class PartitionTable(list):
|
||||
class PartitionDefinition(object):
|
||||
MAGIC_BYTES = b'\xAA\x50'
|
||||
|
||||
ALIGNMENT = {
|
||||
APP_TYPE: 0x10000,
|
||||
DATA_TYPE: 0x04,
|
||||
}
|
||||
|
||||
# dictionary maps flag name (as used in CSV flags list, property name)
|
||||
# to bit set in flags words in binary format
|
||||
FLAGS = {
|
||||
@ -358,7 +379,9 @@ class PartitionDefinition(object):
|
||||
|
||||
def parse_subtype(self, strval):
|
||||
if strval == '':
|
||||
return 0 # default
|
||||
if self.type == TYPES['app']:
|
||||
raise InputError('App partition cannot have an empty subtype')
|
||||
return SUBTYPES[DATA_TYPE]['undefined']
|
||||
return parse_int(strval, SUBTYPES.get(self.type, {}))
|
||||
|
||||
def parse_address(self, strval):
|
||||
@ -373,10 +396,15 @@ class PartitionDefinition(object):
|
||||
raise ValidationError(self, 'Subtype field is not set')
|
||||
if self.offset is None:
|
||||
raise ValidationError(self, 'Offset field is not set')
|
||||
align = self.ALIGNMENT.get(self.type, 4)
|
||||
align = get_alignment_for_type(self.type)
|
||||
if self.offset % align:
|
||||
raise ValidationError(self, 'Offset 0x%x is not aligned to 0x%x' % (self.offset, align))
|
||||
if self.size % align and secure:
|
||||
# The alignment requirement for non-app partition is 4 bytes, but it should be 4 kB.
|
||||
# Print a warning for now, make it an error in IDF 5.0 (IDF-3742).
|
||||
if self.type != APP_TYPE and self.offset % STRICT_DATA_ALIGNMENT:
|
||||
critical('WARNING: Partition %s not aligned to 0x%x.'
|
||||
'This is deprecated and will be considered an error in the future release.' % (self.name, STRICT_DATA_ALIGNMENT))
|
||||
if self.size % align and secure and self.type == APP_TYPE:
|
||||
raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, align))
|
||||
if self.size is None:
|
||||
raise ValidationError(self, 'Size field is not set')
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -244,6 +244,14 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
|
||||
*/
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
|
||||
|
||||
/**
|
||||
* @brief Returns number of ota partitions provided in partition table.
|
||||
*
|
||||
* @return
|
||||
* - Number of OTA partitions
|
||||
*/
|
||||
uint8_t esp_ota_get_app_partition_count(void);
|
||||
|
||||
/**
|
||||
* @brief This function is called to indicate that the running app is working well.
|
||||
*
|
||||
|
@ -18,6 +18,11 @@
|
||||
# define ASIO_NO_TYPEID
|
||||
# endif // CONFIG_COMPILER_RTTI
|
||||
|
||||
//
|
||||
// Supress OpenSSL deprecation warning, when building ASIO
|
||||
//
|
||||
#define ESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
|
||||
//
|
||||
// LWIP compatibility inet and address macros/functions
|
||||
//
|
||||
|
@ -119,6 +119,15 @@ bool bootloader_common_label_search(const char *list, char *label);
|
||||
*/
|
||||
void bootloader_configure_spi_pins(int drv);
|
||||
|
||||
/**
|
||||
* @brief Get flash CS IO
|
||||
*
|
||||
* Can be determined by eFuse values, or the default value
|
||||
*
|
||||
* @return Flash CS IO
|
||||
*/
|
||||
uint8_t bootloader_flash_get_cs_io(void);
|
||||
|
||||
/**
|
||||
* @brief Calculates a sha-256 for a given partition or returns a appended digest.
|
||||
*
|
||||
|
@ -10,6 +10,18 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Read flash ID by sending RDID command (0x9F)
|
||||
* @return flash raw ID
|
||||
* mfg_id = (ID >> 16) & 0xFF;
|
||||
flash_id = ID & 0xffff;
|
||||
*/
|
||||
uint32_t bootloader_read_flash_id(void);
|
||||
|
||||
#if SOC_CACHE_SUPPORT_WRAP
|
||||
/**
|
||||
* @brief Set the burst mode setting command for specified wrap mode.
|
||||
@ -19,3 +31,22 @@
|
||||
*/
|
||||
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Unlock Flash write protect.
|
||||
* Please do not call this function in SDK.
|
||||
*
|
||||
* @note This can be overridden because it's attribute weak.
|
||||
*/
|
||||
esp_err_t bootloader_flash_unlock(void);
|
||||
|
||||
/**
|
||||
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
|
||||
*
|
||||
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
|
||||
*/
|
||||
esp_err_t bootloader_flash_xmc_startup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -77,4 +77,8 @@ period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void);
|
||||
|
||||
// This function returns whether the given |alarm| is active or not.
|
||||
// Return true if active, false otherwise.
|
||||
bool osi_alarm_is_active(osi_alarm_t *alarm);
|
||||
|
||||
#endif /*_ALARM_H_*/
|
||||
|
@ -467,7 +467,7 @@ typedef struct
|
||||
{
|
||||
uint16_t rx_len; /*!< pkt rx data length value */
|
||||
uint16_t tx_len; /*!< pkt tx data length value */
|
||||
}esp_ble_pkt_data_length_params_t;
|
||||
} esp_ble_pkt_data_length_params_t;
|
||||
|
||||
/**
|
||||
* @brief BLE encryption keys
|
||||
@ -648,7 +648,7 @@ typedef enum {
|
||||
typedef enum{
|
||||
ESP_BLE_WHITELIST_REMOVE = 0X00, /*!< remove mac from whitelist */
|
||||
ESP_BLE_WHITELIST_ADD = 0X01, /*!< add address to whitelist */
|
||||
}esp_ble_wl_opration_t;
|
||||
} esp_ble_wl_opration_t;
|
||||
#if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
typedef enum {
|
||||
ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD = 0, /*!< Add device info into duplicate scan exceptional list */
|
||||
@ -998,7 +998,7 @@ typedef union {
|
||||
uint16_t conn_int; /*!< Current connection interval */
|
||||
uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80.
|
||||
Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec */
|
||||
}update_conn_params; /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
|
||||
} update_conn_params; /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT
|
||||
*/
|
||||
@ -1018,13 +1018,13 @@ typedef union {
|
||||
struct ble_remove_bond_dev_cmpl_evt_param {
|
||||
esp_bt_status_t status; /*!< Indicate the remove bond device operation success status */
|
||||
esp_bd_addr_t bd_addr; /*!< The device address which has been remove from the bond list */
|
||||
}remove_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
|
||||
} remove_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT
|
||||
*/
|
||||
struct ble_clear_bond_dev_cmpl_evt_param {
|
||||
esp_bt_status_t status; /*!< Indicate the clear bond device operation success status */
|
||||
}clear_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
|
||||
} clear_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT
|
||||
*/
|
||||
@ -1032,7 +1032,7 @@ typedef union {
|
||||
esp_bt_status_t status; /*!< Indicate the get bond device operation success status */
|
||||
uint8_t dev_num; /*!< Indicate the get number device in the bond list */
|
||||
esp_ble_bond_dev_t *bond_dev; /*!< the pointer to the bond device Structure */
|
||||
}get_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
|
||||
} get_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
|
||||
*/
|
||||
|
@ -380,7 +380,7 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
|
||||
/**
|
||||
* @brief Find all the service with the given service uuid in the gattc cache, if the svc_uuid is NULL, find all the service.
|
||||
* Note: It just get service from local cache, won't get from remote devices. If want to get it from remote device, need
|
||||
* to used the esp_ble_gattc_search_service.
|
||||
* to used the esp_ble_gattc_cache_refresh, then call esp_ble_gattc_get_service again.
|
||||
*
|
||||
* @param[in] gattc_if: Gatt client access interface.
|
||||
* @param[in] conn_id: connection ID which identify the server.
|
||||
|
@ -0,0 +1,379 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2019 Blake Felt
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESP_HIDD_API_H__
|
||||
#define __ESP_HIDD_API_H__
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* sub_class of hid device */
|
||||
#define ESP_HID_CLASS_UNKNOWN (0x00<<2)
|
||||
#define ESP_HID_CLASS_JOS (0x01<<2) /* joy stick */
|
||||
#define ESP_HID_CLASS_GPD (0x02<<2) /* game pad */
|
||||
#define ESP_HID_CLASS_RMC (0x03<<2) /* remote control */
|
||||
#define ESP_HID_CLASS_SED (0x04<<2) /* sensing device */
|
||||
#define ESP_HID_CLASS_DGT (0x05<<2) /* Digitizer tablet */
|
||||
#define ESP_HID_CLASS_CDR (0x06<<2) /* card reader */
|
||||
#define ESP_HID_CLASS_KBD (0x10<<2) /* keyboard */
|
||||
#define ESP_HID_CLASS_MIC (0x20<<2) /* pointing device */
|
||||
#define ESP_HID_CLASS_COM (0x30<<2) /* Combo keyboard/pointing */
|
||||
|
||||
/**
|
||||
* @brief HIDD handshake error
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_SUCCESS = 0,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_NOT_READY = 1,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID = 2,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ = 3,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM = 4,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN = 14,
|
||||
ESP_HID_PAR_HANDSHAKE_RSP_ERR_FATAL = 15
|
||||
} esp_hidd_handshake_error_t;
|
||||
|
||||
/**
|
||||
* @brief HIDD report types
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDD_REPORT_TYPE_OTHER = 0,
|
||||
ESP_HIDD_REPORT_TYPE_INPUT,
|
||||
ESP_HIDD_REPORT_TYPE_OUTPUT,
|
||||
ESP_HIDD_REPORT_TYPE_FEATURE,
|
||||
// special value for reports to be sent on INTR(INPUT is assumed)
|
||||
ESP_HIDD_REPORT_TYPE_INTRDATA
|
||||
} esp_hidd_report_type_t;
|
||||
|
||||
/**
|
||||
* @brief HIDD connection state
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDD_CONN_STATE_CONNECTED,
|
||||
ESP_HIDD_CONN_STATE_CONNECTING,
|
||||
ESP_HIDD_CONN_STATE_DISCONNECTED,
|
||||
ESP_HIDD_CONN_STATE_DISCONNECTING,
|
||||
ESP_HIDD_CONN_STATE_UNKNOWN
|
||||
} esp_hidd_connection_state_t;
|
||||
|
||||
/**
|
||||
* @brief HID device protocol modes
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDD_REPORT_MODE = 0x00,
|
||||
ESP_HIDD_BOOT_MODE = 0x01,
|
||||
ESP_HIDD_UNSUPPORTED_MODE = 0xff
|
||||
} esp_hidd_protocol_mode_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief HIDD characteristics for SDP report
|
||||
*/
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *description;
|
||||
const char *provider;
|
||||
uint8_t subclass;
|
||||
uint8_t *desc_list;
|
||||
int desc_list_len;
|
||||
} esp_hidd_app_param_t;
|
||||
|
||||
/**
|
||||
* @brief HIDD Quality of Service parameters
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t service_type;
|
||||
uint32_t token_rate;
|
||||
uint32_t token_bucket_size;
|
||||
uint32_t peak_bandwidth;
|
||||
uint32_t access_latency;
|
||||
uint32_t delay_variation;
|
||||
} esp_hidd_qos_param_t;
|
||||
|
||||
/**
|
||||
* @brief HID device callback function events
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDD_INIT_EVT = 0, /*!< When HID device is inited, the event comes */
|
||||
ESP_HIDD_DEINIT_EVT, /*!< When HID device is deinited, the event comes */
|
||||
ESP_HIDD_REGISTER_APP_EVT, /*!< When HID device application registered, the event comes */
|
||||
ESP_HIDD_UNREGISTER_APP_EVT, /*!< When HID device application unregistered, the event comes */
|
||||
ESP_HIDD_OPEN_EVT, /*!< When HID device connection to host opened, the event comes */
|
||||
ESP_HIDD_CLOSE_EVT, /*!< When HID device connection to host closed, the event comes */
|
||||
ESP_HIDD_SEND_REPORT_EVT, /*!< When HID device send report to lower layer, the event comes */
|
||||
ESP_HIDD_REPORT_ERR_EVT, /*!< When HID device report handshanke error to lower layer, the event comes */
|
||||
ESP_HIDD_GET_REPORT_EVT, /*!< When HID device receives GET_REPORT request from host, the event comes */
|
||||
ESP_HIDD_SET_REPORT_EVT, /*!< When HID device receives SET_REPORT request from host, the event comes */
|
||||
ESP_HIDD_SET_PROTOCOL_EVT, /*!< When HID device receives SET_PROTOCOL request from host, the event comes */
|
||||
ESP_HIDD_INTR_DATA_EVT, /*!< When HID device receives DATA from host on intr, the event comes */
|
||||
ESP_HIDD_VC_UNPLUG_EVT, /*!< When HID device initiates Virtual Cable Unplug, the event comes */
|
||||
ESP_HIDD_API_ERR_EVT /*!< When HID device has API error, the event comes */
|
||||
} esp_hidd_cb_event_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_HIDD_SUCCESS,
|
||||
ESP_HIDD_ERROR, /*!< general ESP HD error */
|
||||
ESP_HIDD_NO_RES, /*!< out of system resources */
|
||||
ESP_HIDD_BUSY, /*!< Temporarily can not handle this request. */
|
||||
ESP_HIDD_NO_DATA, /*!< No data. */
|
||||
ESP_HIDD_NEED_INIT, /*!< HIDD module shall init first */
|
||||
ESP_HIDD_NEED_DEINIT, /*!< HIDD module shall deinit first */
|
||||
ESP_HIDD_NEED_REG, /*!< HIDD module shall register first */
|
||||
ESP_HIDD_NEED_DEREG, /*!< HIDD module shall deregister first */
|
||||
ESP_HIDD_NO_CONNECTION, /*!< connection may have been closed */
|
||||
} esp_hidd_status_t;
|
||||
|
||||
/**
|
||||
* @brief HID device callback parameters union
|
||||
*/
|
||||
typedef union {
|
||||
/**
|
||||
* @brief ESP_HIDD_INIT_EVT
|
||||
*/
|
||||
struct hidd_init_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
} init; /*!< HIDD callback param of ESP_HIDD_INIT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_DEINIT_EVT
|
||||
*/
|
||||
struct hidd_deinit_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
} deinit; /*!< HIDD callback param of ESP_HIDD_DEINIT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_REGISTER_APP_EVT
|
||||
*/
|
||||
struct hidd_register_app_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
bool in_use; /*!< indicate whether use virtual cable plug host address */
|
||||
esp_bd_addr_t bd_addr; /*!< host address */
|
||||
} register_app; /*!< HIDD callback param of ESP_HIDD_REGISTER_APP_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_UNREGISTER_APP_EVT
|
||||
*/
|
||||
struct hidd_unregister_app_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
} unregister_app; /*!< HIDD callback param of ESP_HIDD_UNREGISTER_APP_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_OPEN_EVT
|
||||
*/
|
||||
struct hidd_open_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
esp_hidd_connection_state_t conn_status; /*!< connection status */
|
||||
esp_bd_addr_t bd_addr; /*!< host address */
|
||||
} open; /*!< HIDD callback param of ESP_HIDD_OPEN_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_CLOSE_EVT
|
||||
*/
|
||||
struct hidd_close_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
esp_hidd_connection_state_t conn_status; /*!< connection status */
|
||||
} close; /*!< HIDD callback param of ESP_HIDD_CLOSE_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_SEND_REPORT_EVT
|
||||
*/
|
||||
struct hidd_send_report_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
|
||||
esp_hidd_report_type_t report_type; /*!< report type */
|
||||
uint8_t report_id; /*!< report id */
|
||||
} send_report; /*!< HIDD callback param of ESP_HIDD_SEND_REPORT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_REPORT_ERR_EVT
|
||||
*/
|
||||
struct hidd_report_err_evt_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
|
||||
} report_err; /*!< HIDD callback param of ESP_HIDD_REPORT_ERR_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_GET_REPORT_EVT
|
||||
*/
|
||||
struct hidd_get_report_evt_param {
|
||||
esp_hidd_report_type_t report_type; /*!< report type */
|
||||
uint8_t report_id; /*!< report id */
|
||||
uint16_t buffer_size; /*!< buffer size */
|
||||
} get_report; /*!< HIDD callback param of ESP_HIDD_GET_REPORT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_SET_REPORT_EVT
|
||||
*/
|
||||
struct hidd_set_report_evt_param {
|
||||
esp_hidd_report_type_t report_type; /*!< report type */
|
||||
uint8_t report_id; /*!< report id */
|
||||
uint16_t len; /*!< set_report data length */
|
||||
uint8_t *data; /*!< set_report data pointer */
|
||||
} set_report; /*!< HIDD callback param of ESP_HIDD_SET_REPORT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_SET_PROTOCOL_EVT
|
||||
*/
|
||||
struct hidd_set_protocol_evt_param {
|
||||
esp_hidd_protocol_mode_t protocol_mode; /*!< protocol mode */
|
||||
} set_protocol; /*!< HIDD callback param of ESP_HIDD_SET_PROTOCOL_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_INTR_DATA_EVT
|
||||
*/
|
||||
struct hidd_intr_data_evt_param {
|
||||
uint8_t report_id; /*!< interrupt channel report id */
|
||||
uint16_t len; /*!< interrupt channel report data length */
|
||||
uint8_t *data; /*!< interrupt channel report data pointer */
|
||||
} intr_data; /*!< HIDD callback param of ESP_HIDD_INTR_DATA_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDD_VC_UNPLUG_EVT
|
||||
*/
|
||||
struct hidd_vc_unplug_param {
|
||||
esp_hidd_status_t status; /*!< operation status */
|
||||
esp_hidd_connection_state_t conn_status; /*!< connection status */
|
||||
} vc_unplug; /*!< HIDD callback param of ESP_HIDD_VC_UNPLUG_EVT */
|
||||
} esp_hidd_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief HID device callback function type.
|
||||
* @param event: Event type
|
||||
* @param param: Point to callback parameter, currently is union type
|
||||
*/
|
||||
typedef void (esp_hd_cb_t)(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief This function is called to init callbacks with HID device module.
|
||||
*
|
||||
* @param[in] callback: pointer to the init callback function.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t callback);
|
||||
|
||||
/**
|
||||
* @brief This function initializes HIDD. This function should be called after esp_bluedroid_enable and
|
||||
* esp_blueroid_init success, and should be called after esp_bt_hid_device_register_callback.
|
||||
* When the operation is complete the callback function will be called with ESP_HIDD_INIT_EVT.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_init(void);
|
||||
|
||||
/**
|
||||
* @brief This function de-initializes HIDD interface. This function should be called after esp_bluedroid_enable() and
|
||||
* esp_blueroid_init() success, and should be called after esp_bt_hid_device_init(). When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_DEINIT_EVT.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be called after
|
||||
* esp_bluedroid_enable and esp_blueroid_init success, and must be done after esp_bt_hid_device_init. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_REGISTER_APP_EVT.
|
||||
*
|
||||
* @param[in] app_param: HIDD parameters
|
||||
* @param[in] in_qos: incoming QoS parameters
|
||||
* @param[in] out_qos: outgoing QoS parameters
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t *app_param, esp_hidd_qos_param_t *in_qos,
|
||||
esp_hidd_qos_param_t *out_qos);
|
||||
|
||||
/**
|
||||
* @brief Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be called after esp_bluedroid_enable and
|
||||
* esp_blueroid_init success, and should be called after esp_bt_hid_device_init. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_UNREGISTER_APP_EVT.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_unregister_app(void);
|
||||
|
||||
/**
|
||||
* @brief This function connects HIDD interface to connected bluetooth device, if not done already. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_OPEN_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote host bluetooth device address.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief This function disconnects HIDD interface. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_CLOSE_EVT.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_disconnect(void);
|
||||
|
||||
/**
|
||||
* @brief Send HIDD report. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_SEND_REPORT_EVT.
|
||||
*
|
||||
* @param[in] type: type of report
|
||||
* @param[in] id: report id as defined by descriptor
|
||||
* @param[in] len: length of report
|
||||
* @param[in] data: report data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief Sends HIDD handshake with error info for invalid set_report. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_REPORT_ERR_EVT.
|
||||
*
|
||||
* @param[in] error: type of error
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error);
|
||||
|
||||
/**
|
||||
* @brief Unplug virtual cable of HIDD. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDD_VC_UNPLUG_EVT.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,465 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2019 Blake Felt
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESP_HIDH_API_H__
|
||||
#define __ESP_HIDH_API_H__
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BTHH_MAX_DSC_LEN 884
|
||||
|
||||
/**
|
||||
* @brief HID host connection state
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDH_CONN_STATE_CONNECTED = 0, /*!< connected state */
|
||||
ESP_HIDH_CONN_STATE_CONNECTING, /*!< connecting state */
|
||||
ESP_HIDH_CONN_STATE_DISCONNECTED, /*!< disconnected state */
|
||||
ESP_HIDH_CONN_STATE_DISCONNECTING, /*!< disconnecting state */
|
||||
ESP_HIDH_CONN_STATE_UNKNOWN /*!< unknown state(initial state) */
|
||||
} esp_hidh_connection_state_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_HIDH_OK,
|
||||
ESP_HIDH_HS_HID_NOT_READY, /*!< handshake error : device not ready */
|
||||
ESP_HIDH_HS_INVALID_RPT_ID, /*!< handshake error : invalid report ID */
|
||||
ESP_HIDH_HS_TRANS_NOT_SPT, /*!< handshake error : transaction not spt */
|
||||
ESP_HIDH_HS_INVALID_PARAM, /*!< handshake error : invalid paremter */
|
||||
ESP_HIDH_HS_ERROR, /*!< handshake error : unspecified HS error */
|
||||
ESP_HIDH_ERR, /*!< general ESP HH error */
|
||||
ESP_HIDH_ERR_SDP, /*!< SDP error */
|
||||
ESP_HIDH_ERR_PROTO, /*!< SET_Protocol error,
|
||||
only used in ESP_HIDH_OPEN_EVT callback */
|
||||
|
||||
ESP_HIDH_ERR_DB_FULL, /*!< device database full error, used in
|
||||
ESP_HIDH_OPEN_EVT/ESP_HIDH_ADD_DEV_EVT */
|
||||
ESP_HIDH_ERR_TOD_UNSPT, /*!< type of device not supported */
|
||||
ESP_HIDH_ERR_NO_RES, /*!< out of system resources */
|
||||
ESP_HIDH_ERR_AUTH_FAILED, /*!< authentication fail */
|
||||
ESP_HIDH_ERR_HDL, /*!< connection handle error */
|
||||
ESP_HIDH_ERR_SEC, /*!< encryption error */
|
||||
// self_defined
|
||||
ESP_HIDH_BUSY, /*!< Temporarily can not handle this request. */
|
||||
ESP_HIDH_NO_DATA, /*!< No data. */
|
||||
ESP_HIDH_NEED_INIT, /*!< HIDH module shall init first */
|
||||
ESP_HIDH_NEED_DEINIT, /*!< HIDH module shall deinit first */
|
||||
ESP_HIDH_NO_CONNECTION, /*!< connection may have been closed */
|
||||
} esp_hidh_status_t;
|
||||
|
||||
/**
|
||||
* @brief HID host protocol modes
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDH_BOOT_MODE = 0x00, /*!< boot protocol mode */
|
||||
ESP_HIDH_REPORT_MODE = 0x01, /*!< report protocol mode */
|
||||
ESP_HIDH_UNSUPPORTED_MODE = 0xff /*!< unsupported protocol mode */
|
||||
} esp_hidh_protocol_mode_t;
|
||||
|
||||
/**
|
||||
* @brief HID host report types
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDH_REPORT_TYPE_OTHER = 0, /*!< unsupported report type */
|
||||
ESP_HIDH_REPORT_TYPE_INPUT, /*!< input report type */
|
||||
ESP_HIDH_REPORT_TYPE_OUTPUT, /*!< output report type */
|
||||
ESP_HIDH_REPORT_TYPE_FEATURE, /*!< feature report type */
|
||||
} esp_hidh_report_type_t;
|
||||
|
||||
/**
|
||||
* @brief HID host callback function events
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_HIDH_INIT_EVT = 0, /*!< When HID host is inited, the event comes */
|
||||
ESP_HIDH_DEINIT_EVT, /*!< When HID host is deinited, the event comes */
|
||||
ESP_HIDH_OPEN_EVT, /*!< When HID host connection opened, the event comes */
|
||||
ESP_HIDH_CLOSE_EVT, /*!< When HID host connection closed, the event comes */
|
||||
ESP_HIDH_GET_RPT_EVT, /*!< When Get_Report command is called, the event comes */
|
||||
ESP_HIDH_SET_RPT_EVT, /*!< When Set_Report command is called, the event comes */
|
||||
ESP_HIDH_GET_PROTO_EVT, /*!< When Get_Protocol command is called, the event comes */
|
||||
ESP_HIDH_SET_PROTO_EVT, /*!< When Set_Protocol command is called, the event comes */
|
||||
ESP_HIDH_GET_IDLE_EVT, /*!< When Get_Idle command is called, the event comes */
|
||||
ESP_HIDH_SET_IDLE_EVT, /*!< When Set_Idle command is called, the event comes */
|
||||
ESP_HIDH_GET_DSCP_EVT, /*!< When HIDH is inited, the event comes */
|
||||
ESP_HIDH_ADD_DEV_EVT, /*!< When a device is added, the event comes */
|
||||
ESP_HIDH_RMV_DEV_EVT, /*!< When a device is removed, the event comes */
|
||||
ESP_HIDH_VC_UNPLUG_EVT, /*!< When virtually unplugged, the event comes */
|
||||
ESP_HIDH_DATA_EVT, /*!< When send data on interrupt channel, the event comes */
|
||||
ESP_HIDH_DATA_IND_EVT, /*!< When receive data on interrupt channel, the event comes */
|
||||
ESP_HIDH_SET_INFO_EVT /*!< When set the HID device descriptor, the event comes */
|
||||
} esp_hidh_cb_event_t;
|
||||
|
||||
typedef struct {
|
||||
int attr_mask;
|
||||
uint8_t sub_class;
|
||||
uint8_t app_id;
|
||||
int vendor_id;
|
||||
int product_id;
|
||||
int version;
|
||||
uint8_t ctry_code;
|
||||
int dl_len;
|
||||
uint8_t dsc_list[BTHH_MAX_DSC_LEN];
|
||||
} esp_hidh_hid_info_t;
|
||||
|
||||
/**
|
||||
* @brief HID host callback parameters union
|
||||
*/
|
||||
typedef union {
|
||||
/**
|
||||
* @brief ESP_HIDH_INIT_EVT
|
||||
*/
|
||||
struct hidh_init_evt_param {
|
||||
esp_hidh_status_t status; /*!< status */
|
||||
} init; /*!< HIDH callback param of ESP_HIDH_INIT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_DEINIT_EVT
|
||||
*/
|
||||
struct hidh_uninit_evt_param {
|
||||
esp_hidh_status_t status; /*!< status */
|
||||
} deinit; /*!< HIDH callback param of ESP_HIDH_DEINIT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_OPEN_EVT
|
||||
*/
|
||||
struct hidh_open_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
esp_hidh_connection_state_t conn_status; /*!< connection status */
|
||||
bool is_orig; /*!< indicate if host intiate the connection */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_bd_addr_t bd_addr; /*!< device address */
|
||||
} open; /*!< HIDH callback param of ESP_HIDH_OPEN_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_CLOSE_EVT
|
||||
*/
|
||||
struct hidh_close_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
|
||||
esp_hidh_connection_state_t conn_status; /*!< connection status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
} close; /*!< HIDH callback param of ESP_HIDH_CLOSE_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_VC_UNPLUG_EVT
|
||||
*/
|
||||
struct hidh_unplug_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
esp_hidh_connection_state_t conn_status; /*!< connection status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
} unplug; /*!< HIDH callback param of ESP_HIDH_VC_UNPLUG_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_GET_PROTO_EVT
|
||||
*/
|
||||
struct hidh_get_proto_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
|
||||
} get_proto; /*!< HIDH callback param of ESP_HIDH_GET_PROTO_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_SET_PROTO_EVT
|
||||
*/
|
||||
struct hidh_set_proto_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
} set_proto; /*!< HIDH callback param of ESP_HIDH_SET_PROTO_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_GET_RPT_EVT
|
||||
*/
|
||||
struct hidh_get_rpt_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
uint16_t len; /*!< data length */
|
||||
uint8_t *data; /*!< data pointer */
|
||||
} get_rpt; /*!< HIDH callback param of ESP_HIDH_GET_RPT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_SET_RPT_EVT
|
||||
*/
|
||||
struct hidh_set_rpt_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
} set_rpt; /*!< HIDH callback param of ESP_HIDH_SET_RPT_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_DATA_EVT
|
||||
*/
|
||||
struct hidh_send_data_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
|
||||
} send_data; /*!< HIDH callback param of ESP_HIDH_DATA_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_GET_IDLE_EVT
|
||||
*/
|
||||
struct hidh_get_idle_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
uint8_t idle_rate; /*!< idle rate */
|
||||
} get_idle; /*!< HIDH callback param of ESP_HIDH_GET_IDLE_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_SET_IDLE_EVT
|
||||
*/
|
||||
struct hidh_set_idle_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
} set_idle; /*!< HIDH callback param of ESP_HIDH_SET_IDLE_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_DATA_IND_EVT
|
||||
*/
|
||||
struct hidh_data_ind_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
|
||||
uint16_t len; /*!< data length */
|
||||
uint8_t *data; /*!< data pointer */
|
||||
} data_ind; /*!< HIDH callback param of ESP_HIDH_DATA_IND_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_ADD_DEV_EVT
|
||||
*/
|
||||
struct hidh_add_dev_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_bd_addr_t bd_addr; /*!< device address */
|
||||
} add_dev; /*!< HIDH callback param of ESP_HIDH_ADD_DEV_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_RMV_DEV_EVT
|
||||
*/
|
||||
struct hidh_rmv_dev_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_bd_addr_t bd_addr; /*!< device address */
|
||||
} rmv_dev; /*!< HIDH callback param of ESP_HIDH_RMV_DEV_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_GET_DSCP_EVT
|
||||
*/
|
||||
struct hidh_get_dscp_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
bool added; /*!< Indicate if added */
|
||||
uint16_t vendor_id; /*!< Vendor ID */
|
||||
uint16_t product_id; /*!< Product ID */
|
||||
uint16_t version; /*!< Version */
|
||||
uint16_t ssr_max_latency; /*!< SSR max latency */
|
||||
uint16_t ssr_min_tout; /*!< SSR min timeout */
|
||||
uint8_t ctry_code; /*!< Country Code */
|
||||
uint16_t dl_len; /*!< Device descriptor length */
|
||||
uint8_t *dsc_list; /*!< Device descriptor pointer */
|
||||
} dscp; /*!< HIDH callback param of ESP_HIDH_GET_DSCP_EVT */
|
||||
|
||||
/**
|
||||
* @brief ESP_HIDH_SET_INFO_EVT
|
||||
*/
|
||||
struct hidh_set_info_evt_param {
|
||||
esp_hidh_status_t status; /*!< operation status */
|
||||
uint8_t handle; /*!< device handle */
|
||||
esp_bd_addr_t bd_addr; /*!< device address */
|
||||
} set_info; /*!< HIDH callback param of ESP_HIDH_SET_INFO_EVT */
|
||||
} esp_hidh_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief HID host callback function type
|
||||
* @param event: Event type
|
||||
* @param param: Point to callback parameter, currently is union type
|
||||
*/
|
||||
typedef void (esp_hh_cb_t)(esp_hidh_cb_event_t event, esp_hidh_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* @brief This function is called to init callbacks with HID host module.
|
||||
*
|
||||
* @param[in] callback: pointer to the init callback function.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t callback);
|
||||
|
||||
/**
|
||||
* @brief This function initializes HID host. This function should be called after esp_bluedroid_enable() and
|
||||
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_register_callback().
|
||||
* When the operation is complete the callback function will be called with ESP_HIDH_INIT_EVT.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_init(void);
|
||||
|
||||
/**
|
||||
* @brief Closes the interface. This function should be called after esp_bluedroid_enable() and
|
||||
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_init().
|
||||
* When the operation is complete the callback function will be called with ESP_HIDH_DEINIT_EVT.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Connect to hid device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_OPEN_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Disconnect from hid device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_CLOSE_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Virtual UnPlug (VUP) the specified HID device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_VC_UNPLUG_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Set the HID device descriptor for the specified HID device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_SET_INFO_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] hid_info: HID device descriptor structure.
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info);
|
||||
|
||||
/**
|
||||
* @brief Get the HID proto mode. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_GET_PROTO_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Set the HID proto mode. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_SET_PROTO_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] protocol_mode: Protocol mode type.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode);
|
||||
|
||||
/**
|
||||
* @brief Get the HID Idle Time. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_GET_IDLE_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief Set the HID Idle Time. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_SET_IDLE_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] idle_time: Idle time rate
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time);
|
||||
|
||||
/**
|
||||
* @brief Send a GET_REPORT to HID device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_GET_RPT_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] report_type: Report type
|
||||
* @param[in] report_id: Report id
|
||||
* @param[in] buffer_size: Buffer size
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
|
||||
int buffer_size);
|
||||
|
||||
/**
|
||||
* @brief Send a SET_REPORT to HID device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_SET_RPT_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] report_type: Report type
|
||||
* @param[in] report: Report data pointer
|
||||
* @param[in] len: Report data length
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* @brief Send data to HID device. When the operation is complete the callback
|
||||
* function will be called with ESP_HIDH_DATA_EVT.
|
||||
*
|
||||
* @param[in] bd_addr: Remote device bluetooth device address.
|
||||
* @param[in] data: Data pointer
|
||||
* @param[in] len: Data length
|
||||
*
|
||||
* @return - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_BT_H__
|
||||
#define __ESP_BT_H__
|
||||
@ -149,6 +141,12 @@ the adv packet will be discarded until the memory is restored. */
|
||||
#define BTDM_CTRL_AUTO_LATENCY_EFF false
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BTDM_CTRL_HLI
|
||||
#define BTDM_CTRL_HLI CONFIG_BTDM_CTRL_HLI
|
||||
#else
|
||||
#define BTDM_CTRL_HLI false
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
||||
#define BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
||||
#else
|
||||
@ -183,6 +181,7 @@ the adv packet will be discarded until the memory is restored. */
|
||||
.ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF, \
|
||||
.pcm_role = CONFIG_BTDM_CTRL_PCM_ROLE_EFF, \
|
||||
.pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \
|
||||
.hli = BTDM_CTRL_HLI, \
|
||||
.magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \
|
||||
};
|
||||
|
||||
@ -224,6 +223,7 @@ typedef struct {
|
||||
uint8_t ble_sca; /*!< BLE low power crystal accuracy index */
|
||||
uint8_t pcm_role; /*!< PCM role (master & slave)*/
|
||||
uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */
|
||||
bool hli; /*!< Using high level interrupt or not */
|
||||
uint32_t magic; /*!< Magic number */
|
||||
} esp_bt_controller_config_t;
|
||||
|
||||
@ -383,12 +383,6 @@ esp_err_t esp_bt_controller_disable(void);
|
||||
*/
|
||||
esp_bt_controller_status_t esp_bt_controller_get_status(void);
|
||||
|
||||
/**
|
||||
* @brief Get BT MAC address.
|
||||
* @return Array pointer of length 6 storing MAC address value.
|
||||
*/
|
||||
uint8_t* esp_bt_get_mac(void);
|
||||
|
||||
/** @brief esp_vhci_host_callback
|
||||
* used for vhci call host function to notify what host need to do
|
||||
*/
|
||||
@ -528,6 +522,16 @@ esp_err_t esp_bt_sleep_disable(void);
|
||||
*/
|
||||
esp_err_t esp_ble_scan_dupilcate_list_flush(void);
|
||||
|
||||
/**
|
||||
* @brief bt Wi-Fi power domain power on
|
||||
*/
|
||||
void esp_wifi_bt_power_domain_on(void);
|
||||
|
||||
/**
|
||||
* @brief bt Wi-Fi power domain power off
|
||||
*/
|
||||
void esp_wifi_bt_power_domain_off(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,148 +0,0 @@
|
||||
/*
|
||||
* async.h -- state management for asynchronous messages
|
||||
*
|
||||
* Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
|
||||
*
|
||||
* This file is part of the CoAP library libcoap. Please see README for terms
|
||||
* of use.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file async.h
|
||||
* @brief State management for asynchronous messages
|
||||
*/
|
||||
|
||||
#ifndef COAP_ASYNC_H_
|
||||
#define COAP_ASYNC_H_
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#ifndef WITHOUT_ASYNC
|
||||
|
||||
/**
|
||||
* @defgroup coap_async Asynchronous Messaging
|
||||
* @{
|
||||
* Structure for managing asynchronous state of CoAP resources. A
|
||||
* coap_resource_t object holds a list of coap_async_state_t objects that can be
|
||||
* used to generate a separate response in case a result of an operation cannot
|
||||
* be delivered in time, or the resource has been explicitly subscribed to with
|
||||
* the option @c observe.
|
||||
*/
|
||||
typedef struct coap_async_state_t {
|
||||
unsigned char flags; /**< holds the flags to control behaviour */
|
||||
|
||||
/**
|
||||
* Holds the internal time when the object was registered with a
|
||||
* resource. This field will be updated whenever
|
||||
* coap_register_async() is called for a specific resource.
|
||||
*/
|
||||
coap_tick_t created;
|
||||
|
||||
/**
|
||||
* This field can be used to register opaque application data with the
|
||||
* asynchronous state object.
|
||||
*/
|
||||
void *appdata;
|
||||
coap_session_t *session; /**< transaction session */
|
||||
coap_tid_t id; /**< transaction id */
|
||||
struct coap_async_state_t *next; /**< internally used for linking */
|
||||
size_t tokenlen; /**< length of the token */
|
||||
uint8_t token[8]; /**< the token to use in a response */
|
||||
} coap_async_state_t;
|
||||
|
||||
/* Definitions for Async Status Flags These flags can be used to control the
|
||||
* behaviour of asynchronous response generation.
|
||||
*/
|
||||
#define COAP_ASYNC_CONFIRM 0x01 /**< send confirmable response */
|
||||
#define COAP_ASYNC_SEPARATE 0x02 /**< send separate response */
|
||||
#define COAP_ASYNC_OBSERVED 0x04 /**< the resource is being observed */
|
||||
|
||||
/** release application data on destruction */
|
||||
#define COAP_ASYNC_RELEASE_DATA 0x08
|
||||
|
||||
/**
|
||||
* Allocates a new coap_async_state_t object and fills its fields according to
|
||||
* the given @p request. The @p flags are used to control generation of empty
|
||||
* ACK responses to stop retransmissions and to release registered @p data when
|
||||
* the resource is deleted by coap_free_async(). This function returns a pointer
|
||||
* to the registered coap_async_t object or @c NULL on error. Note that this
|
||||
* function will return @c NULL in case that an object with the same identifier
|
||||
* is already registered.
|
||||
*
|
||||
* @param context The context to use.
|
||||
* @param session The session that is used for asynchronous transmissions.
|
||||
* @param request The request that is handled asynchronously.
|
||||
* @param flags Flags to control state management.
|
||||
* @param data Opaque application data to register. Note that the
|
||||
* storage occupied by @p data is released on destruction
|
||||
* only if flag COAP_ASYNC_RELEASE_DATA is set.
|
||||
*
|
||||
* @return A pointer to the registered coap_async_state_t object or @c
|
||||
* NULL in case of an error.
|
||||
*/
|
||||
coap_async_state_t *
|
||||
coap_register_async(coap_context_t *context,
|
||||
coap_session_t *session,
|
||||
coap_pdu_t *request,
|
||||
unsigned char flags,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* Removes the state object identified by @p id from @p context. The removed
|
||||
* object is returned in @p s, if found. Otherwise, @p s is undefined. This
|
||||
* function returns @c 1 if the object was removed, @c 0 otherwise. Note that
|
||||
* the storage allocated for the stored object is not released by this
|
||||
* functions. You will have to call coap_free_async() to do so.
|
||||
*
|
||||
* @param context The context where the async object is registered.
|
||||
* @param session The session that is used for asynchronous transmissions.
|
||||
* @param id The identifier of the asynchronous transaction.
|
||||
* @param s Will be set to the object identified by @p id after removal.
|
||||
*
|
||||
* @return @c 1 if object was removed and @p s updated, or @c 0 if no
|
||||
* object was found with the given id. @p s is valid only if the
|
||||
* return value is @c 1.
|
||||
*/
|
||||
int coap_remove_async(coap_context_t *context,
|
||||
coap_session_t *session,
|
||||
coap_tid_t id,
|
||||
coap_async_state_t **s);
|
||||
|
||||
/**
|
||||
* Releases the memory that was allocated by coap_async_state_init() for the
|
||||
* object @p s. The registered application data will be released automatically
|
||||
* if COAP_ASYNC_RELEASE_DATA is set.
|
||||
*
|
||||
* @param state The object to delete.
|
||||
*/
|
||||
void
|
||||
coap_free_async(coap_async_state_t *state);
|
||||
|
||||
/**
|
||||
* Retrieves the object identified by @p id from the list of asynchronous
|
||||
* transactions that are registered with @p context. This function returns a
|
||||
* pointer to that object or @c NULL if not found.
|
||||
*
|
||||
* @param context The context where the asynchronous objects are registered
|
||||
* with.
|
||||
* @param session The session that is used for asynchronous transmissions.
|
||||
* @param id The id of the object to retrieve.
|
||||
*
|
||||
* @return A pointer to the object identified by @p id or @c NULL if
|
||||
* not found.
|
||||
*/
|
||||
coap_async_state_t *coap_find_async(coap_context_t *context, coap_session_t *session, coap_tid_t id);
|
||||
|
||||
/**
|
||||
* Updates the time stamp of @p s.
|
||||
*
|
||||
* @param s The state object to update.
|
||||
*/
|
||||
COAP_STATIC_INLINE void
|
||||
coap_touch_async(coap_async_state_t *s) { coap_ticks(&s->created); }
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* WITHOUT_ASYNC */
|
||||
|
||||
#endif /* COAP_ASYNC_H_ */
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* bits.h -- bit vector manipulation
|
||||
*
|
||||
* Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
|
||||
*
|
||||
* This file is part of the CoAP library libcoap. Please see README for terms
|
||||
* of use.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file bits.h
|
||||
* @brief Bit vector manipulation
|
||||
*/
|
||||
|
||||
#ifndef COAP_BITS_H_
|
||||
#define COAP_BITS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Sets the bit @p bit in bit-vector @p vec. This function returns @c 1 if bit
|
||||
* was set or @c -1 on error (i.e. when the given bit does not fit in the
|
||||
* vector).
|
||||
*
|
||||
* @param vec The bit-vector to change.
|
||||
* @param size The size of @p vec in bytes.
|
||||
* @param bit The bit to set in @p vec.
|
||||
*
|
||||
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
|
||||
*/
|
||||
COAP_STATIC_INLINE int
|
||||
bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
|
||||
if (size <= ((size_t)bit >> 3))
|
||||
return -1;
|
||||
|
||||
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the bit @p bit from bit-vector @p vec. This function returns @c 1 if
|
||||
* bit was cleared or @c -1 on error (i.e. when the given bit does not fit in
|
||||
* the vector).
|
||||
*
|
||||
* @param vec The bit-vector to change.
|
||||
* @param size The size of @p vec in bytes.
|
||||
* @param bit The bit to clear from @p vec.
|
||||
*
|
||||
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
|
||||
*/
|
||||
COAP_STATIC_INLINE int
|
||||
bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
|
||||
if (size <= ((size_t)bit >> 3))
|
||||
return -1;
|
||||
|
||||
*(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of bit @p bit from bit-vector @p vec. This function returns
|
||||
* @c 1 if the bit is set, @c 0 otherwise (even in case of an error).
|
||||
*
|
||||
* @param vec The bit-vector to read from.
|
||||
* @param size The size of @p vec in bytes.
|
||||
* @param bit The bit to get from @p vec.
|
||||
*
|
||||
* @return @c 1 if the bit is set, @c 0 otherwise.
|
||||
*/
|
||||
COAP_STATIC_INLINE int
|
||||
bits_getb(const uint8_t *vec, size_t size, uint8_t bit) {
|
||||
if (size <= ((size_t)bit >> 3))
|
||||
return -1;
|
||||
|
||||
return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
|
||||
}
|
||||
|
||||
#endif /* COAP_BITS_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user