| | |
| | | # Compiled Object files |
| | | *.slo |
| | | *.lo |
| | | *.o |
| | | *.obj |
| | | |
| | | # Compiled Dynamic libraries |
| | | *.so |
| | | *.dylib |
| | | *.dll |
| | | |
| | | # Compiled Static libraries |
| | | *.lai |
| | | *.la |
| | | *.a |
| | | *.lib |
| | | |
| | | # Executables |
| | | *.exe |
| | | *.out |
| | | *.app |
| | | tools/xtensa-esp32-elf |
| | | tools/dist |
| | | tools/esptool |
| | | tools/esptool.exe |
| | | tools/mkspiffs/mkspiffs |
| | | tools/mkspiffs/mkspiffs.exe |
| | | .DS_Store |
| New file |
| | |
| | | [submodule "libraries/AzureIoT"] |
| | | path = libraries/AzureIoT |
| | | url = https://github.com/VSChina/ESP32_AzureIoT_Arduino |
| New file |
| | |
| | | sudo: false |
| | | |
| | | language: python |
| | | python: |
| | | - "2.7" |
| | | |
| | | os: |
| | | - linux |
| | | |
| | | git: |
| | | depth: false |
| | | |
| | | env: |
| | | global: |
| | | - secure: "l/4Dt+KQ/mACtGAHDUsPr66fUte840PZoQ4xpPikqWZI0uARu4l+Ym7+sHinnT6fBqrj8AJeBYGz4nFa8NK4LutZn9mSD40w+sxl0wSV4oHV8rzKe3Cd8+sMG3+o33yWoikMNjSvqa73Q0rm+SgrlInNdZbuAyixL+a2alaWSnGPm4F2xwUGj+S33TOy5P/Xp77CYtCV5S8vzyk/eEdNhoF0GYePJVdfuzCOUjXMyT5OWxORkzzQ7Hnn/Ka/RDfV8Si4HgujLQBrK5q6iPnNBFqBSqilYBepSMn4opnOBpIm0SCgePz7XQEFC83buA7GUcnCnfg38bf+dCwHaODf1d1PmqVRYt2QmfinexXtM4afAtL0iBUDtvrfnXHzwW9w82VeZhpbJSVh9DUQvB0IlsZeCz9J9PUBAi3N+SMX+9l+BomYwRUlPuKY+Ef2JKk9q6mxtUkky5R0daAlVxEhpVdQks1rT+T+NMoDMemxQ3SKEiqAHh6EgHecruszffmZ71uLX9MpERpew0qN+UFiafws+jkTjx+3yF9yut0Hf9sMbeAYzzkGzRqJTUEBJ6B29Cql8M0yRXCNN/8wuuTHhG8esstozga4ZQoIVrq7mEAgup376PTcNfr1+imbbWVQ7lJdYIuDe6OS5V3OX6np11vgK/DbhfyzvQv9Z1zAGnM=" |
| | | - REMOTE_URL=https://github.com/$TRAVIS_REPO_SLUG/releases/download/$TRAVIS_TAG |
| | | |
| | | script: |
| | | - bash $TRAVIS_BUILD_DIR/tools/build.sh |
| | | |
| | | deploy: |
| | | provider: script |
| | | skip_cleanup: true |
| | | script: bash $TRAVIS_BUILD_DIR/tools/deploy.sh -t$TRAVIS_TAG -a$ESP32_GITHUB_TOKEN -s$TRAVIS_REPO_SLUG -drelease |
| | | |
| | | on: |
| | | tags: true |
| | | |
| | | |
| | | notifications: |
| | | email: |
| | | on_success: change |
| | | on_failure: change |
| | | webhooks: |
| | | urls: |
| | | - https://webhooks.gitter.im/e/cb057279c430d91a47a8 |
| | | on_success: change # options: [always|never|change] default: always |
| | | on_failure: always # options: [always|never|change] default: always |
| | | on_start: never # options: [always|never|change] default: always |
| New file |
| | |
| | | set(CORE_SRCS |
| | | cores/esp32/base64.cpp |
| | | cores/esp32/cbuf.cpp |
| | | cores/esp32/esp32-hal-adc.c |
| | | cores/esp32/esp32-hal-bt.c |
| | | cores/esp32/esp32-hal-cpu.c |
| | | cores/esp32/esp32-hal-dac.c |
| | | cores/esp32/esp32-hal-gpio.c |
| | | cores/esp32/esp32-hal-i2c.c |
| | | cores/esp32/esp32-hal-ledc.c |
| | | cores/esp32/esp32-hal-matrix.c |
| | | cores/esp32/esp32-hal-misc.c |
| | | cores/esp32/esp32-hal-psram.c |
| | | cores/esp32/esp32-hal-sigmadelta.c |
| | | cores/esp32/esp32-hal-spi.c |
| | | cores/esp32/esp32-hal-time.c |
| | | cores/esp32/esp32-hal-timer.c |
| | | cores/esp32/esp32-hal-touch.c |
| | | cores/esp32/esp32-hal-uart.c |
| | | cores/esp32/esp32-hal-rmt.c |
| | | cores/esp32/Esp.cpp |
| | | cores/esp32/FunctionalInterrupt.cpp |
| | | cores/esp32/HardwareSerial.cpp |
| | | cores/esp32/IPAddress.cpp |
| | | cores/esp32/IPv6Address.cpp |
| | | cores/esp32/libb64/cdecode.c |
| | | cores/esp32/libb64/cencode.c |
| | | cores/esp32/main.cpp |
| | | cores/esp32/MD5Builder.cpp |
| | | cores/esp32/Print.cpp |
| | | cores/esp32/stdlib_noniso.c |
| | | cores/esp32/Stream.cpp |
| | | cores/esp32/StreamString.cpp |
| | | cores/esp32/wiring_pulse.c |
| | | cores/esp32/wiring_shift.c |
| | | cores/esp32/WMath.cpp |
| | | cores/esp32/WString.cpp |
| | | ) |
| | | |
| | | set(LIBRARY_SRCS |
| | | libraries/ArduinoOTA/src/ArduinoOTA.cpp |
| | | libraries/AsyncUDP/src/AsyncUDP.cpp |
| | | libraries/BluetoothSerial/src/BluetoothSerial.cpp |
| | | libraries/DNSServer/src/DNSServer.cpp |
| | | libraries/EEPROM/src/EEPROM.cpp |
| | | libraries/ESPmDNS/src/ESPmDNS.cpp |
| | | libraries/FFat/src/FFat.cpp |
| | | libraries/FS/src/FS.cpp |
| | | libraries/FS/src/vfs_api.cpp |
| | | libraries/HTTPClient/src/HTTPClient.cpp |
| | | libraries/HTTPUpdate/src/HTTPUpdate.cpp |
| | | libraries/NetBIOS/src/NetBIOS.cpp |
| | | libraries/Preferences/src/Preferences.cpp |
| | | libraries/SD_MMC/src/SD_MMC.cpp |
| | | libraries/SD/src/SD.cpp |
| | | libraries/SD/src/sd_diskio.cpp |
| | | libraries/SD/src/sd_diskio_crc.c |
| | | libraries/SimpleBLE/src/SimpleBLE.cpp |
| | | libraries/SPIFFS/src/SPIFFS.cpp |
| | | libraries/SPI/src/SPI.cpp |
| | | libraries/Ticker/src/Ticker.cpp |
| | | libraries/Update/src/Updater.cpp |
| | | libraries/WebServer/src/WebServer.cpp |
| | | libraries/WebServer/src/Parsing.cpp |
| | | libraries/WebServer/src/detail/mimetable.cpp |
| | | libraries/WiFiClientSecure/src/ssl_client.cpp |
| | | libraries/WiFiClientSecure/src/WiFiClientSecure.cpp |
| | | libraries/WiFi/src/ETH.cpp |
| | | libraries/WiFi/src/WiFiAP.cpp |
| | | libraries/WiFi/src/WiFiClient.cpp |
| | | libraries/WiFi/src/WiFi.cpp |
| | | libraries/WiFi/src/WiFiGeneric.cpp |
| | | libraries/WiFi/src/WiFiMulti.cpp |
| | | libraries/WiFi/src/WiFiScan.cpp |
| | | libraries/WiFi/src/WiFiServer.cpp |
| | | libraries/WiFi/src/WiFiSTA.cpp |
| | | libraries/WiFi/src/WiFiUdp.cpp |
| | | libraries/Wire/src/Wire.cpp |
| | | ) |
| | | |
| | | set(AZURE_SRCS |
| | | libraries/AzureIoT/src/az_iot/azureiotcerts.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/agenttime.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/dns_async.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/lock.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/threadapi.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/tickcounter.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/lwip/sntp_lwip.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/socket_async.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/src/platform_openssl_compact.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/src/tlsio_openssl_compact.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/pal/tlsio_options.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/base64.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/buffer.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/connection_string_parser.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/consolelogger.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/constbuffer.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/constmap.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/crt_abstractions.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/doublylinkedlist.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/gballoc.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/gb_stdio.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/gb_time.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/hmac.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/hmacsha256.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/httpapiex.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/httpapiexsas.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/httpheaders.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/http_proxy_io.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/map.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/optionhandler.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/sastoken.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/sha1.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/sha224.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/sha384-512.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/singlylinkedlist.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/strings.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/string_tokenizer.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/urlencode.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/usha.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/vector.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/xio.c |
| | | libraries/AzureIoT/src/az_iot/c-utility/src/xlogging.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/blob.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_authorization.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_ll.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_retry_control.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_message.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransportmqtt.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c |
| | | libraries/AzureIoT/src/az_iot/iothub_client/src/version.c |
| | | libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_client.c |
| | | libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_codec.c |
| | | libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_message.c |
| | | libraries/AzureIoT/src/AzureIotHub.cpp |
| | | libraries/AzureIoT/src/Esp32MQTTClient.cpp |
| | | ) |
| | | |
| | | set(BLE_SRCS |
| | | libraries/BLE/src/BLE2902.cpp |
| | | libraries/BLE/src/BLE2904.cpp |
| | | libraries/BLE/src/BLEAddress.cpp |
| | | libraries/BLE/src/BLEAdvertisedDevice.cpp |
| | | libraries/BLE/src/BLEAdvertising.cpp |
| | | libraries/BLE/src/BLEBeacon.cpp |
| | | libraries/BLE/src/BLECharacteristic.cpp |
| | | libraries/BLE/src/BLECharacteristicMap.cpp |
| | | libraries/BLE/src/BLEClient.cpp |
| | | libraries/BLE/src/BLEDescriptor.cpp |
| | | libraries/BLE/src/BLEDescriptorMap.cpp |
| | | libraries/BLE/src/BLEDevice.cpp |
| | | libraries/BLE/src/BLEEddystoneTLM.cpp |
| | | libraries/BLE/src/BLEEddystoneURL.cpp |
| | | libraries/BLE/src/BLEExceptions.cpp |
| | | libraries/BLE/src/BLEHIDDevice.cpp |
| | | libraries/BLE/src/BLERemoteCharacteristic.cpp |
| | | libraries/BLE/src/BLERemoteDescriptor.cpp |
| | | libraries/BLE/src/BLERemoteService.cpp |
| | | libraries/BLE/src/BLEScan.cpp |
| | | libraries/BLE/src/BLESecurity.cpp |
| | | libraries/BLE/src/BLEServer.cpp |
| | | libraries/BLE/src/BLEService.cpp |
| | | libraries/BLE/src/BLEServiceMap.cpp |
| | | libraries/BLE/src/BLEUtils.cpp |
| | | libraries/BLE/src/BLEUUID.cpp |
| | | libraries/BLE/src/BLEValue.cpp |
| | | libraries/BLE/src/FreeRTOS.cpp |
| | | libraries/BLE/src/GeneralUtils.cpp |
| | | ) |
| | | |
| | | set(COMPONENT_SRCS ${CORE_SRCS} ${LIBRARY_SRCS} ${AZURE_SRCS} ${BLE_SRCS}) |
| | | |
| | | set(COMPONENT_ADD_INCLUDEDIRS |
| | | variants/esp32/ |
| | | cores/esp32/ |
| | | libraries/ArduinoOTA/src |
| | | libraries/AsyncUDP/src |
| | | libraries/AzureIoT/src |
| | | libraries/BLE/src |
| | | libraries/BluetoothSerial/src |
| | | libraries/DNSServer/src |
| | | libraries/EEPROM/src |
| | | libraries/ESP32/src |
| | | libraries/ESPmDNS/src |
| | | libraries/FFat/src |
| | | libraries/FS/src |
| | | libraries/HTTPClient/src |
| | | libraries/HTTPUpdate/src |
| | | libraries/NetBIOS/src |
| | | libraries/Preferences/src |
| | | libraries/SD_MMC/src |
| | | libraries/SD/src |
| | | libraries/SimpleBLE/src |
| | | libraries/SPIFFS/src |
| | | libraries/SPI/src |
| | | libraries/Ticker/src |
| | | libraries/Update/src |
| | | libraries/WebServer/src |
| | | libraries/WiFiClientSecure/src |
| | | libraries/WiFi/src |
| | | libraries/Wire/src |
| | | ) |
| | | |
| | | set(COMPONENT_PRIV_INCLUDEDIRS cores/esp32/libb64) |
| | | |
| | | set(COMPONENT_REQUIRES spi_flash mbedtls mdns ethernet) |
| | | set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl bt) |
| | | |
| | | register_component() |
| | | |
| | | set_source_files_properties(libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c |
| | | PROPERTIES COMPILE_FLAGS |
| | | -Wno-maybe-uninitialized |
| | | ) |
| New file |
| | |
| | | menu "Arduino Configuration" |
| | | |
| | | config ENABLE_ARDUINO_DEPENDS |
| | | bool |
| | | select LWIP_SO_RCVBUF |
| | | select ETHERNET |
| | | select WIFI_ENABLED |
| | | select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE |
| | | select MEMMAP_SMP |
| | | default "y" |
| | | |
| | | config AUTOSTART_ARDUINO |
| | | bool "Autostart Arduino setup and loop on boot" |
| | | default "n" |
| | | help |
| | | Enabling this option will implement app_main and start Arduino. |
| | | All you need to implement in your main.cpp is setup() and loop() |
| | | and include Arduino.h |
| | | If disabled, you can call initArduino() to run any preparations |
| | | required by the framework |
| | | |
| | | choice ARDUINO_RUNNING_CORE |
| | | bool "Core on which Arduino's setup() and loop() are running" |
| | | default ARDUINO_RUN_CORE1 |
| | | help |
| | | Select on which core Arduino's setup() and loop() functions run |
| | | |
| | | config ARDUINO_RUN_CORE0 |
| | | bool "CORE 0" |
| | | config ARDUINO_RUN_CORE1 |
| | | bool "CORE 1" |
| | | config ARDUINO_RUN_NO_AFFINITY |
| | | bool "BOTH" |
| | | |
| | | endchoice |
| | | |
| | | config ARDUINO_RUNNING_CORE |
| | | int |
| | | default 0 if ARDUINO_RUN_CORE0 |
| | | default 1 if ARDUINO_RUN_CORE1 |
| | | default -1 if ARDUINO_RUN_NO_AFFINITY |
| | | |
| | | choice ARDUINO_EVENT_RUNNING_CORE |
| | | bool "Core on which Arduino's event handler is running" |
| | | default ARDUINO_EVENT_RUN_CORE1 |
| | | help |
| | | Select on which core Arduino's WiFi.onEvent() run |
| | | |
| | | config ARDUINO_EVENT_RUN_CORE0 |
| | | bool "CORE 0" |
| | | config ARDUINO_EVENT_RUN_CORE1 |
| | | bool "CORE 1" |
| | | config ARDUINO_EVENT_RUN_NO_AFFINITY |
| | | bool "BOTH" |
| | | |
| | | endchoice |
| | | |
| | | config ARDUINO_EVENT_RUNNING_CORE |
| | | int |
| | | default 0 if ARDUINO_EVENT_RUN_CORE0 |
| | | default 1 if ARDUINO_EVENT_RUN_CORE1 |
| | | default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY |
| | | |
| | | choice ARDUINO_UDP_RUNNING_CORE |
| | | bool "Core on which Arduino's UDP is running" |
| | | default ARDUINO_UDP_RUN_CORE1 |
| | | help |
| | | Select on which core Arduino's UDP run |
| | | |
| | | config ARDUINO_UDP_RUN_CORE0 |
| | | bool "CORE 0" |
| | | config ARDUINO_UDP_RUN_CORE1 |
| | | bool "CORE 1" |
| | | config ARDUINO_UDP_RUN_NO_AFFINITY |
| | | bool "BOTH" |
| | | |
| | | endchoice |
| | | |
| | | config ARDUINO_UDP_RUNNING_CORE |
| | | int |
| | | default 0 if ARDUINO_UDP_RUN_CORE0 |
| | | default 1 if ARDUINO_UDP_RUN_CORE1 |
| | | default -1 if ARDUINO_UDP_RUN_NO_AFFINITY |
| | | |
| | | |
| | | config DISABLE_HAL_LOCKS |
| | | bool "Disable mutex locks for HAL" |
| | | default "n" |
| | | help |
| | | Enabling this option will run all hardware abstraction without locks. |
| | | While communication with external hardware will be faster, you need to |
| | | make sure that there is no option to use the same bus from another thread |
| | | or interrupt at the same time. Option is best used with Arduino enabled |
| | | and code implemented only in setup/loop and Arduino callbacks |
| | | |
| | | menu "Debug Log Configuration" |
| | | choice ARDUHAL_LOG_DEFAULT_LEVEL |
| | | bool "Default log level" |
| | | default ARDUHAL_LOG_DEFAULT_LEVEL_ERROR |
| | | help |
| | | Specify how much output to see in logs by default. |
| | | |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_NONE |
| | | bool "No output" |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_ERROR |
| | | bool "Error" |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_WARN |
| | | bool "Warning" |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_INFO |
| | | bool "Info" |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_DEBUG |
| | | bool "Debug" |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE |
| | | bool "Verbose" |
| | | endchoice |
| | | |
| | | config ARDUHAL_LOG_DEFAULT_LEVEL |
| | | int |
| | | default 0 if ARDUHAL_LOG_DEFAULT_LEVEL_NONE |
| | | default 1 if ARDUHAL_LOG_DEFAULT_LEVEL_ERROR |
| | | default 2 if ARDUHAL_LOG_DEFAULT_LEVEL_WARN |
| | | default 3 if ARDUHAL_LOG_DEFAULT_LEVEL_INFO |
| | | default 4 if ARDUHAL_LOG_DEFAULT_LEVEL_DEBUG |
| | | default 5 if ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE |
| | | |
| | | config ARDUHAL_LOG_COLORS |
| | | bool "Use ANSI terminal colors in log output" |
| | | default "n" |
| | | help |
| | | Enable ANSI terminal color codes in bootloader output. |
| | | In order to view these, your terminal program must support ANSI color codes. |
| | | |
| | | config ARDUHAL_ESP_LOG |
| | | bool "Forward ESP_LOGx to Arduino log output" |
| | | default "n" |
| | | help |
| | | This option will redefine the ESP_LOGx macros to Arduino's log_x macros. |
| | | To enable for your application, add the follwing after your includes: |
| | | #ifdef ARDUINO_ARCH_ESP32 |
| | | #include "esp32-hal-log.h" |
| | | #endif |
| | | |
| | | endmenu |
| | | |
| | | choice ARDUHAL_PARTITION_SCHEME |
| | | bool "Used partition scheme" |
| | | default ARDUHAL_PARTITION_SCHEME_DEFAULT |
| | | help |
| | | Specify which partition scheme to be used. |
| | | |
| | | config ARDUHAL_PARTITION_SCHEME_DEFAULT |
| | | bool "Default" |
| | | config ARDUHAL_PARTITION_SCHEME_MINIMAL |
| | | bool "Minimal (for 2MB FLASH)" |
| | | config ARDUHAL_PARTITION_SCHEME_NO_OTA |
| | | bool "No OTA (for large apps)" |
| | | config ARDUHAL_PARTITION_SCHEME_HUGE_APP |
| | | bool "Huge App (for very large apps)" |
| | | config ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS |
| | | bool "Minimal SPIFFS (for large apps with OTA)" |
| | | endchoice |
| | | |
| | | config ARDUHAL_PARTITION_SCHEME |
| | | string |
| | | default "default" if ARDUHAL_PARTITION_SCHEME_DEFAULT |
| | | default "minimal" if ARDUHAL_PARTITION_SCHEME_MINIMAL |
| | | default "no_ota" if ARDUHAL_PARTITION_SCHEME_NO_OTA |
| | | default "huge_app" if ARDUHAL_PARTITION_SCHEME_HUGE_APP |
| | | default "min_spiffs" if ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS |
| | | |
| | | |
| | | config AUTOCONNECT_WIFI |
| | | bool "Autoconnect WiFi on boot" |
| | | default "n" |
| | | depends on AUTOSTART_ARDUINO |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | help |
| | | If enabled, WiFi will connect to the last used SSID (if station was enabled), |
| | | else connection will be started only after calling WiFi.begin(ssid, password) |
| | | |
| | | config ARDUINO_SELECTIVE_COMPILATION |
| | | bool "Include only specific Arduino libraries" |
| | | default n |
| | | |
| | | config ARDUINO_SELECTIVE_ArduinoOTA |
| | | bool "Enable ArduinoOTA" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | select ARDUINO_SELECTIVE_ESPmDNS |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_AsyncUDP |
| | | bool "Enable AsyncUDP" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_AzureIoT |
| | | bool "Enable AzureIoT" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_HTTPClient |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_BLE |
| | | bool "Enable BLE" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_BluetoothSerial |
| | | bool "Enable BluetoothSerial" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_DNSServer |
| | | bool "Enable DNSServer" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_EEPROM |
| | | bool "Enable EEPROM" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_ESP32 |
| | | bool "Enable ESP32" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_ESPmDNS |
| | | bool "Enable ESPmDNS" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_FS |
| | | bool "Enable FS" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_HTTPClient |
| | | bool "Enable HTTPClient" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | select ARDUINO_SELECTIVE_WiFiClientSecure |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_NetBIOS |
| | | bool "Enable NetBIOS" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_Preferences |
| | | bool "Enable Preferences" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_SD |
| | | bool "Enable SD" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_FS |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_SD_MMC |
| | | bool "Enable SD_MMC" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_FS |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_SimpleBLE |
| | | bool "Enable SimpleBLE" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_SPI |
| | | bool "Enable SPI" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_SPIFFS |
| | | bool "Enable SPIFFS" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_FS |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_Ticker |
| | | bool "Enable Ticker" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_Update |
| | | bool "Enable Update" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_WebServer |
| | | bool "Enable WebServer" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | select ARDUINO_SELECTIVE_FS |
| | | |
| | | config ARDUINO_SELECTIVE_WiFi |
| | | bool "Enable WiFi" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_WiFiClientSecure |
| | | bool "Enable WiFiClientSecure" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | select ARDUINO_SELECTIVE_WiFi |
| | | default y |
| | | |
| | | config ARDUINO_SELECTIVE_Wire |
| | | bool "Enable Wire" |
| | | depends on ARDUINO_SELECTIVE_COMPILATION |
| | | default y |
| | | |
| | | |
| | | endmenu |
| New file |
| | |
| | | ### GNU LESSER GENERAL PUBLIC LICENSE |
| | | |
| | | Version 2.1, February 1999 |
| | | |
| | | Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
| | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Everyone is permitted to copy and distribute verbatim copies |
| | | of this license document, but changing it is not allowed. |
| | | |
| | | [This is the first released version of the Lesser GPL. It also counts |
| | | as the successor of the GNU Library Public License, version 2, hence |
| | | the version number 2.1.] |
| | | |
| | | ### Preamble |
| | | |
| | | The licenses for most software are designed to take away your freedom |
| | | to share and change it. By contrast, the GNU General Public Licenses |
| | | are intended to guarantee your freedom to share and change free |
| | | software--to make sure the software is free for all its users. |
| | | |
| | | This license, the Lesser General Public License, applies to some |
| | | specially designated software packages--typically libraries--of the |
| | | Free Software Foundation and other authors who decide to use it. You |
| | | can use it too, but we suggest you first think carefully about whether |
| | | this license or the ordinary General Public License is the better |
| | | strategy to use in any particular case, based on the explanations |
| | | below. |
| | | |
| | | When we speak of free software, we are referring to freedom of use, |
| | | not price. Our General Public Licenses are designed to make sure that |
| | | you have the freedom to distribute copies of free software (and charge |
| | | for this service if you wish); that you receive source code or can get |
| | | it if you want it; that you can change the software and use pieces of |
| | | it in new free programs; and that you are informed that you can do |
| | | these things. |
| | | |
| | | To protect your rights, we need to make restrictions that forbid |
| | | distributors to deny you these rights or to ask you to surrender these |
| | | rights. These restrictions translate to certain responsibilities for |
| | | you if you distribute copies of the library or if you modify it. |
| | | |
| | | For example, if you distribute copies of the library, whether gratis |
| | | or for a fee, you must give the recipients all the rights that we gave |
| | | you. You must make sure that they, too, receive or can get the source |
| | | code. If you link other code with the library, you must provide |
| | | complete object files to the recipients, so that they can relink them |
| | | with the library after making changes to the library and recompiling |
| | | it. And you must show them these terms so they know their rights. |
| | | |
| | | We protect your rights with a two-step method: (1) we copyright the |
| | | library, and (2) we offer you this license, which gives you legal |
| | | permission to copy, distribute and/or modify the library. |
| | | |
| | | To protect each distributor, we want to make it very clear that there |
| | | is no warranty for the free library. Also, if the library is modified |
| | | by someone else and passed on, the recipients should know that what |
| | | they have is not the original version, so that the original author's |
| | | reputation will not be affected by problems that might be introduced |
| | | by others. |
| | | |
| | | Finally, software patents pose a constant threat to the existence of |
| | | any free program. We wish to make sure that a company cannot |
| | | effectively restrict the users of a free program by obtaining a |
| | | restrictive license from a patent holder. Therefore, we insist that |
| | | any patent license obtained for a version of the library must be |
| | | consistent with the full freedom of use specified in this license. |
| | | |
| | | Most GNU software, including some libraries, is covered by the |
| | | ordinary GNU General Public License. This license, the GNU Lesser |
| | | General Public License, applies to certain designated libraries, and |
| | | is quite different from the ordinary General Public License. We use |
| | | this license for certain libraries in order to permit linking those |
| | | libraries into non-free programs. |
| | | |
| | | When a program is linked with a library, whether statically or using a |
| | | shared library, the combination of the two is legally speaking a |
| | | combined work, a derivative of the original library. The ordinary |
| | | General Public License therefore permits such linking only if the |
| | | entire combination fits its criteria of freedom. The Lesser General |
| | | Public License permits more lax criteria for linking other code with |
| | | the library. |
| | | |
| | | We call this license the "Lesser" General Public License because it |
| | | does Less to protect the user's freedom than the ordinary General |
| | | Public License. It also provides other free software developers Less |
| | | of an advantage over competing non-free programs. These disadvantages |
| | | are the reason we use the ordinary General Public License for many |
| | | libraries. However, the Lesser license provides advantages in certain |
| | | special circumstances. |
| | | |
| | | For example, on rare occasions, there may be a special need to |
| | | encourage the widest possible use of a certain library, so that it |
| | | becomes a de-facto standard. To achieve this, non-free programs must |
| | | be allowed to use the library. A more frequent case is that a free |
| | | library does the same job as widely used non-free libraries. In this |
| | | case, there is little to gain by limiting the free library to free |
| | | software only, so we use the Lesser General Public License. |
| | | |
| | | In other cases, permission to use a particular library in non-free |
| | | programs enables a greater number of people to use a large body of |
| | | free software. For example, permission to use the GNU C Library in |
| | | non-free programs enables many more people to use the whole GNU |
| | | operating system, as well as its variant, the GNU/Linux operating |
| | | system. |
| | | |
| | | Although the Lesser General Public License is Less protective of the |
| | | users' freedom, it does ensure that the user of a program that is |
| | | linked with the Library has the freedom and the wherewithal to run |
| | | that program using a modified version of the Library. |
| | | |
| | | The precise terms and conditions for copying, distribution and |
| | | modification follow. Pay close attention to the difference between a |
| | | "work based on the library" and a "work that uses the library". The |
| | | former contains code derived from the library, whereas the latter must |
| | | be combined with the library in order to run. |
| | | |
| | | ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
| | | |
| | | **0.** This License Agreement applies to any software library or other |
| | | program which contains a notice placed by the copyright holder or |
| | | other authorized party saying it may be distributed under the terms of |
| | | this Lesser General Public License (also called "this License"). Each |
| | | licensee is addressed as "you". |
| | | |
| | | A "library" means a collection of software functions and/or data |
| | | prepared so as to be conveniently linked with application programs |
| | | (which use some of those functions and data) to form executables. |
| | | |
| | | The "Library", below, refers to any such software library or work |
| | | which has been distributed under these terms. A "work based on the |
| | | Library" means either the Library or any derivative work under |
| | | copyright law: that is to say, a work containing the Library or a |
| | | portion of it, either verbatim or with modifications and/or translated |
| | | straightforwardly into another language. (Hereinafter, translation is |
| | | included without limitation in the term "modification".) |
| | | |
| | | "Source code" for a work means the preferred form of the work for |
| | | making modifications to it. For a library, complete source code means |
| | | all the source code for all modules it contains, plus any associated |
| | | interface definition files, plus the scripts used to control |
| | | compilation and installation of the library. |
| | | |
| | | Activities other than copying, distribution and modification are not |
| | | covered by this License; they are outside its scope. The act of |
| | | running a program using the Library is not restricted, and output from |
| | | such a program is covered only if its contents constitute a work based |
| | | on the Library (independent of the use of the Library in a tool for |
| | | writing it). Whether that is true depends on what the Library does and |
| | | what the program that uses the Library does. |
| | | |
| | | **1.** You may copy and distribute verbatim copies of the Library's |
| | | complete source code as you receive it, in any medium, provided that |
| | | you conspicuously and appropriately publish on each copy an |
| | | appropriate copyright notice and disclaimer of warranty; keep intact |
| | | all the notices that refer to this License and to the absence of any |
| | | warranty; and distribute a copy of this License along with the |
| | | Library. |
| | | |
| | | You may charge a fee for the physical act of transferring a copy, and |
| | | you may at your option offer warranty protection in exchange for a |
| | | fee. |
| | | |
| | | **2.** You may modify your copy or copies of the Library or any |
| | | portion of it, thus forming a work based on the Library, and copy and |
| | | distribute such modifications or work under the terms of Section 1 |
| | | above, provided that you also meet all of these conditions: |
| | | |
| | | - **a)** The modified work must itself be a software library. |
| | | - **b)** You must cause the files modified to carry prominent |
| | | notices stating that you changed the files and the date of |
| | | any change. |
| | | - **c)** You must cause the whole of the work to be licensed at no |
| | | charge to all third parties under the terms of this License. |
| | | - **d)** If a facility in the modified Library refers to a function |
| | | or a table of data to be supplied by an application program that |
| | | uses the facility, other than as an argument passed when the |
| | | facility is invoked, then you must make a good faith effort to |
| | | ensure that, in the event an application does not supply such |
| | | function or table, the facility still operates, and performs |
| | | whatever part of its purpose remains meaningful. |
| | | |
| | | (For example, a function in a library to compute square roots has |
| | | a purpose that is entirely well-defined independent of |
| | | the application. Therefore, Subsection 2d requires that any |
| | | application-supplied function or table used by this function must |
| | | be optional: if the application does not supply it, the square |
| | | root function must still compute square roots.) |
| | | |
| | | These requirements apply to the modified work as a whole. If |
| | | identifiable sections of that work are not derived from the Library, |
| | | and can be reasonably considered independent and separate works in |
| | | themselves, then this License, and its terms, do not apply to those |
| | | sections when you distribute them as separate works. But when you |
| | | distribute the same sections as part of a whole which is a work based |
| | | on the Library, the distribution of the whole must be on the terms of |
| | | this License, whose permissions for other licensees extend to the |
| | | entire whole, and thus to each and every part regardless of who wrote |
| | | it. |
| | | |
| | | Thus, it is not the intent of this section to claim rights or contest |
| | | your rights to work written entirely by you; rather, the intent is to |
| | | exercise the right to control the distribution of derivative or |
| | | collective works based on the Library. |
| | | |
| | | In addition, mere aggregation of another work not based on the Library |
| | | with the Library (or with a work based on the Library) on a volume of |
| | | a storage or distribution medium does not bring the other work under |
| | | the scope of this License. |
| | | |
| | | **3.** You may opt to apply the terms of the ordinary GNU General |
| | | Public License instead of this License to a given copy of the Library. |
| | | To do this, you must alter all the notices that refer to this License, |
| | | so that they refer to the ordinary GNU General Public License, version |
| | | 2, instead of to this License. (If a newer version than version 2 of |
| | | the ordinary GNU General Public License has appeared, then you can |
| | | specify that version instead if you wish.) Do not make any other |
| | | change in these notices. |
| | | |
| | | Once this change is made in a given copy, it is irreversible for that |
| | | copy, so the ordinary GNU General Public License applies to all |
| | | subsequent copies and derivative works made from that copy. |
| | | |
| | | This option is useful when you wish to copy part of the code of the |
| | | Library into a program that is not a library. |
| | | |
| | | **4.** You may copy and distribute the Library (or a portion or |
| | | derivative of it, under Section 2) in object code or executable form |
| | | under the terms of Sections 1 and 2 above provided that you accompany |
| | | it with the complete corresponding machine-readable source code, which |
| | | must be distributed under the terms of Sections 1 and 2 above on a |
| | | medium customarily used for software interchange. |
| | | |
| | | If distribution of object code is made by offering access to copy from |
| | | a designated place, then offering equivalent access to copy the source |
| | | code from the same place satisfies the requirement to distribute the |
| | | source code, even though third parties are not compelled to copy the |
| | | source along with the object code. |
| | | |
| | | **5.** A program that contains no derivative of any portion of the |
| | | Library, but is designed to work with the Library by being compiled or |
| | | linked with it, is called a "work that uses the Library". Such a work, |
| | | in isolation, is not a derivative work of the Library, and therefore |
| | | falls outside the scope of this License. |
| | | |
| | | However, linking a "work that uses the Library" with the Library |
| | | creates an executable that is a derivative of the Library (because it |
| | | contains portions of the Library), rather than a "work that uses the |
| | | library". The executable is therefore covered by this License. Section |
| | | 6 states terms for distribution of such executables. |
| | | |
| | | When a "work that uses the Library" uses material from a header file |
| | | that is part of the Library, the object code for the work may be a |
| | | derivative work of the Library even though the source code is not. |
| | | Whether this is true is especially significant if the work can be |
| | | linked without the Library, or if the work is itself a library. The |
| | | threshold for this to be true is not precisely defined by law. |
| | | |
| | | If such an object file uses only numerical parameters, data structure |
| | | layouts and accessors, and small macros and small inline functions |
| | | (ten lines or less in length), then the use of the object file is |
| | | unrestricted, regardless of whether it is legally a derivative work. |
| | | (Executables containing this object code plus portions of the Library |
| | | will still fall under Section 6.) |
| | | |
| | | Otherwise, if the work is a derivative of the Library, you may |
| | | distribute the object code for the work under the terms of Section 6. |
| | | Any executables containing that work also fall under Section 6, |
| | | whether or not they are linked directly with the Library itself. |
| | | |
| | | **6.** As an exception to the Sections above, you may also combine or |
| | | link a "work that uses the Library" with the Library to produce a work |
| | | containing portions of the Library, and distribute that work under |
| | | terms of your choice, provided that the terms permit modification of |
| | | the work for the customer's own use and reverse engineering for |
| | | debugging such modifications. |
| | | |
| | | You must give prominent notice with each copy of the work that the |
| | | Library is used in it and that the Library and its use are covered by |
| | | this License. You must supply a copy of this License. If the work |
| | | during execution displays copyright notices, you must include the |
| | | copyright notice for the Library among them, as well as a reference |
| | | directing the user to the copy of this License. Also, you must do one |
| | | of these things: |
| | | |
| | | - **a)** Accompany the work with the complete corresponding |
| | | machine-readable source code for the Library including whatever |
| | | changes were used in the work (which must be distributed under |
| | | Sections 1 and 2 above); and, if the work is an executable linked |
| | | with the Library, with the complete machine-readable "work that |
| | | uses the Library", as object code and/or source code, so that the |
| | | user can modify the Library and then relink to produce a modified |
| | | executable containing the modified Library. (It is understood that |
| | | the user who changes the contents of definitions files in the |
| | | Library will not necessarily be able to recompile the application |
| | | to use the modified definitions.) |
| | | - **b)** Use a suitable shared library mechanism for linking with |
| | | the Library. A suitable mechanism is one that (1) uses at run time |
| | | a copy of the library already present on the user's computer |
| | | system, rather than copying library functions into the executable, |
| | | and (2) will operate properly with a modified version of the |
| | | library, if the user installs one, as long as the modified version |
| | | is interface-compatible with the version that the work was |
| | | made with. |
| | | - **c)** Accompany the work with a written offer, valid for at least |
| | | three years, to give the same user the materials specified in |
| | | Subsection 6a, above, for a charge no more than the cost of |
| | | performing this distribution. |
| | | - **d)** If distribution of the work is made by offering access to |
| | | copy from a designated place, offer equivalent access to copy the |
| | | above specified materials from the same place. |
| | | - **e)** Verify that the user has already received a copy of these |
| | | materials or that you have already sent this user a copy. |
| | | |
| | | For an executable, the required form of the "work that uses the |
| | | Library" must include any data and utility programs needed for |
| | | reproducing the executable from it. However, as a special exception, |
| | | the materials to be distributed need not include anything that is |
| | | normally distributed (in either source or binary form) with the major |
| | | components (compiler, kernel, and so on) of the operating system on |
| | | which the executable runs, unless that component itself accompanies |
| | | the executable. |
| | | |
| | | It may happen that this requirement contradicts the license |
| | | restrictions of other proprietary libraries that do not normally |
| | | accompany the operating system. Such a contradiction means you cannot |
| | | use both them and the Library together in an executable that you |
| | | distribute. |
| | | |
| | | **7.** You may place library facilities that are a work based on the |
| | | Library side-by-side in a single library together with other library |
| | | facilities not covered by this License, and distribute such a combined |
| | | library, provided that the separate distribution of the work based on |
| | | the Library and of the other library facilities is otherwise |
| | | permitted, and provided that you do these two things: |
| | | |
| | | - **a)** Accompany the combined library with a copy of the same work |
| | | based on the Library, uncombined with any other |
| | | library facilities. This must be distributed under the terms of |
| | | the Sections above. |
| | | - **b)** Give prominent notice with the combined library of the fact |
| | | that part of it is a work based on the Library, and explaining |
| | | where to find the accompanying uncombined form of the same work. |
| | | |
| | | **8.** You may not copy, modify, sublicense, link with, or distribute |
| | | the Library except as expressly provided under this License. Any |
| | | attempt otherwise to copy, modify, sublicense, link with, or |
| | | distribute the Library is void, and will automatically terminate your |
| | | rights under this License. However, parties who have received copies, |
| | | or rights, from you under this License will not have their licenses |
| | | terminated so long as such parties remain in full compliance. |
| | | |
| | | **9.** You are not required to accept this License, since you have not |
| | | signed it. However, nothing else grants you permission to modify or |
| | | distribute the Library or its derivative works. These actions are |
| | | prohibited by law if you do not accept this License. Therefore, by |
| | | modifying or distributing the Library (or any work based on the |
| | | Library), you indicate your acceptance of this License to do so, and |
| | | all its terms and conditions for copying, distributing or modifying |
| | | the Library or works based on it. |
| | | |
| | | **10.** Each time you redistribute the Library (or any work based on |
| | | the Library), the recipient automatically receives a license from the |
| | | original licensor to copy, distribute, link with or modify the Library |
| | | subject to these terms and conditions. You may not impose any further |
| | | restrictions on the recipients' exercise of the rights granted herein. |
| | | You are not responsible for enforcing compliance by third parties with |
| | | this License. |
| | | |
| | | **11.** If, as a consequence of a court judgment or allegation of |
| | | patent infringement or for any other reason (not limited to patent |
| | | issues), conditions are imposed on you (whether by court order, |
| | | agreement or otherwise) that contradict the conditions of this |
| | | License, they do not excuse you from the conditions of this License. |
| | | If you cannot distribute so as to satisfy simultaneously your |
| | | obligations under this License and any other pertinent obligations, |
| | | then as a consequence you may not distribute the Library at all. For |
| | | example, if a patent license would not permit royalty-free |
| | | redistribution of the Library by all those who receive copies directly |
| | | or indirectly through you, then the only way you could satisfy both it |
| | | and this License would be to refrain entirely from distribution of the |
| | | Library. |
| | | |
| | | If any portion of this section is held invalid or unenforceable under |
| | | any particular circumstance, the balance of the section is intended to |
| | | apply, and the section as a whole is intended to apply in other |
| | | circumstances. |
| | | |
| | | It is not the purpose of this section to induce you to infringe any |
| | | patents or other property right claims or to contest validity of any |
| | | such claims; this section has the sole purpose of protecting the |
| | | integrity of the free software distribution system which is |
| | | implemented by public license practices. Many people have made |
| | | generous contributions to the wide range of software distributed |
| | | through that system in reliance on consistent application of that |
| | | system; it is up to the author/donor to decide if he or she is willing |
| | | to distribute software through any other system and a licensee cannot |
| | | impose that choice. |
| | | |
| | | This section is intended to make thoroughly clear what is believed to |
| | | be a consequence of the rest of this License. |
| | | |
| | | **12.** If the distribution and/or use of the Library is restricted in |
| | | certain countries either by patents or by copyrighted interfaces, the |
| | | original copyright holder who places the Library under this License |
| | | may add an explicit geographical distribution limitation excluding |
| | | those countries, so that distribution is permitted only in or among |
| | | countries not thus excluded. In such case, this License incorporates |
| | | the limitation as if written in the body of this License. |
| | | |
| | | **13.** The Free Software Foundation may publish revised and/or new |
| | | versions of the Lesser General Public License from time to time. Such |
| | | new versions will be similar in spirit to the present version, but may |
| | | differ in detail to address new problems or concerns. |
| | | |
| | | Each version is given a distinguishing version number. If the Library |
| | | specifies a version number of this License which applies to it and |
| | | "any later version", you have the option of following the terms and |
| | | conditions either of that version or of any later version published by |
| | | the Free Software Foundation. If the Library does not specify a |
| | | license version number, you may choose any version ever published by |
| | | the Free Software Foundation. |
| | | |
| | | **14.** If you wish to incorporate parts of the Library into other |
| | | free programs whose distribution conditions are incompatible with |
| | | these, write to the author to ask for permission. For software which |
| | | is copyrighted by the Free Software Foundation, write to the Free |
| | | Software Foundation; we sometimes make exceptions for this. Our |
| | | decision will be guided by the two goals of preserving the free status |
| | | of all derivatives of our free software and of promoting the sharing |
| | | and reuse of software generally. |
| | | |
| | | **NO WARRANTY** |
| | | |
| | | **15.** BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
| | | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
| | | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
| | | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
| | | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
| | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| | | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
| | | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
| | | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
| | | |
| | | **16.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
| | | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
| | | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
| | | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
| | | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
| | | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
| | | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
| | | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
| | | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| | | DAMAGES. |
| | | |
| | | ### END OF TERMS AND CONDITIONS |
| | | |
| | | ### How to Apply These Terms to Your New Libraries |
| | | |
| | | If you develop a new library, and you want it to be of the greatest |
| | | possible use to the public, we recommend making it free software that |
| | | everyone can redistribute and change. You can do so by permitting |
| | | redistribution under these terms (or, alternatively, under the terms |
| | | of the ordinary General Public License). |
| | | |
| | | To apply these terms, attach the following notices to the library. It |
| | | is safest to attach them to the start of each source file to most |
| | | effectively convey the exclusion of warranty; and each file should |
| | | have at least the "copyright" line and a pointer to where the full |
| | | notice is found. |
| | | |
| | | one line to give the library's name and an idea of what it does. |
| | | Copyright (C) year name of author |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Also add information on how to contact you by electronic and paper |
| | | mail. |
| | | |
| | | You should also get your employer (if you work as a programmer) or |
| | | your school, if any, to sign a "copyright disclaimer" for the library, |
| | | if necessary. Here is a sample; alter the names: |
| | | |
| | | Yoyodyne, Inc., hereby disclaims all copyright interest in |
| | | the library `Frob' (a library for tweaking knobs) written |
| | | by James Random Hacker. |
| | | |
| | | signature of Ty Coon, 1 April 1990 |
| | | Ty Coon, President of Vice |
| | | |
| | | That's all there is to it! |
| New file |
| | |
| | | BOOT_APP_BIN_ROOT := $(call dequote,$(COMPONENT_PATH)) |
| | | |
| | | ifndef CONFIG_PARTITION_TABLE_CUSTOM |
| | | PARTITION_TABLE_CSV_PATH = $(call dequote,$(abspath $(BOOT_APP_BIN_ROOT)/$(subst $(quote),,tools/partitions/$(CONFIG_ARDUHAL_PARTITION_SCHEME).csv))) |
| | | endif |
| | | |
| | | CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1 -DBOARD_HAS_PSRAM |
| | |
| | | ## arduino-esp32 |
| | | |
| | | 本项止转自github官方arduino-esp32 传在这里仅为阅读源码方便 |
| | | #本项止转自github官方[arduino-esp32](https://github.com/espressif/arduino-esp32 "") 传在这里仅为阅读源码方便 |
| | | # Arduino core for ESP32 WiFi chip [](https://travis-ci.org/espressif/arduino-esp32) |
| | | |
| | | ### Need help or have a question? Join the chat at [](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |
| | | |
| | | ## Contents |
| | | - [Development Status](#development-status) |
| | | - [Installation Instructions](#installation-instructions) |
| | | - [Decoding Exceptions](#decoding-exceptions) |
| | | - [Issue/Bug report template](#issuebug-report-template) |
| | | - [ESP32Dev Board PINMAP](#esp32dev-board-pinmap) |
| | | |
| | | ## Development Status |
| | | [Latest stable release  ](https://github.com/espressif/arduino-esp32/releases/latest/)  |
| | | |
| | | [Latest development release  ](https://github.com/espressif/arduino-esp32/releases/latest/)  |
| | | |
| | | Most of the framework is implemented. Most noticable is the missing analogWrite. While analogWrite is on it's way, there are a few other options that you can use: |
| | | - 16 channels [LEDC](cores/esp32/esp32-hal-ledc.h) which is PWM |
| | | - 8 channels [SigmaDelta](cores/esp32/esp32-hal-sigmadelta.h) which uses SigmaDelta modulation |
| | | - 2 channels [DAC](cores/esp32/esp32-hal-dac.h) which gives real analog output |
| | | |
| | | ## Installation Instructions |
| | | - Using Arduino IDE Boards Manager (preferred) |
| | | + [Instructions for Boards Manager](docs/arduino-ide/boards_manager.md) |
| | | - Using Arduino IDE with the development repository |
| | | + [Instructions for Windows](docs/arduino-ide/windows.md) |
| | | + [Instructions for Mac](docs/arduino-ide/mac.md) |
| | | + [Instructions for Debian/Ubuntu Linux](docs/arduino-ide/debian_ubuntu.md) |
| | | + [Instructions for Fedora](docs/arduino-ide/fedora.md) |
| | | + [Instructions for openSUSE](docs/arduino-ide/opensuse.md) |
| | | - [Using PlatformIO](docs/platformio.md) |
| | | - [Building with make](docs/make.md) |
| | | - [Using as ESP-IDF component](docs/esp-idf_component.md) |
| | | - [Using OTAWebUpdater](docs/OTAWebUpdate/OTAWebUpdate.md) |
| | | |
| | | #### Decoding exceptions |
| | | |
| | | 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). |
| | | |
| | | Finally, if you're sure no one else had the issue, follow the [ISSUE_TEMPLATE](docs/ISSUE_TEMPLATE.md) while reporting any issue. |
| | | |
| | | |
| | | ## ESP32Dev Board PINMAP |
| | | |
| | |  |
| | | |
| | | ## Hint |
| | | |
| | | Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process |
| New file |
| | |
| | | build: off |
| | | environment: |
| | | |
| | | matrix: |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClient" |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClientBasic" |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClientEvents" |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiIPv6" |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiScan" |
| | | - PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiSmartConfig" |
| | | |
| | | install: |
| | | - cmd: git submodule update --init --recursive |
| | | - cmd: SET PATH=%PATH%;C:\Python27\Scripts |
| | | - cmd: pip install -U https://github.com/platformio/platformio/archive/develop.zip |
| | | - cmd: platformio platform install https://github.com/platformio/platform-espressif32.git#feature/stage |
| | | |
| | | test_script: |
| | | - cmd: platformio ci -b esp32dev -b nano32 -b node32s |
| New file |
| | |
| | | ARDUINO_ALL_LIBRARIES := $(patsubst $(COMPONENT_PATH)/libraries/%,%,$(wildcard $(COMPONENT_PATH)/libraries/*)) |
| | | |
| | | # Macro returns non-empty if Arduino library $(1) should be included in the build |
| | | # (either because selective compilation is of, or this library is enabled |
| | | define ARDUINO_LIBRARY_ENABLED |
| | | $(if $(CONFIG_ARDUINO_SELECTIVE_COMPILATION),$(CONFIG_ARDUINO_SELECTIVE_$(1)),y) |
| | | endef |
| | | |
| | | ARDUINO_ENABLED_LIBRARIES := $(foreach LIBRARY,$(sort $(ARDUINO_ALL_LIBRARIES)),$(if $(call ARDUINO_LIBRARY_ENABLED,$(LIBRARY)),$(LIBRARY))) |
| | | |
| | | $(info Arduino libraries in build: $(ARDUINO_ENABLED_LIBRARIES)) |
| | | |
| | | # Expand all subdirs under $(1) |
| | | define EXPAND_SUBDIRS |
| | | $(sort $(dir $(wildcard $(1)/* $(1)/*/* $(1)/*/*/* $(1)/*/*/*/* $(1)/*/*/*/*/*))) |
| | | endef |
| | | |
| | | # Macro returns SRCDIRS for library |
| | | define ARDUINO_LIBRARY_GET_SRCDIRS |
| | | $(if $(wildcard $(COMPONENT_PATH)/libraries/$(1)/src/.), \ |
| | | $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/src), \ |
| | | $(filter-out $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/examples), \ |
| | | $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)) \ |
| | | ) \ |
| | | ) |
| | | endef |
| | | |
| | | # Make a list of all srcdirs in enabled libraries |
| | | ARDUINO_LIBRARY_SRCDIRS := $(patsubst $(COMPONENT_PATH)/%,%,$(foreach LIBRARY,$(ARDUINO_ENABLED_LIBRARIES),$(call ARDUINO_LIBRARY_GET_SRCDIRS,$(LIBRARY)))) |
| | | |
| | | #$(info Arduino libraries src dirs: $(ARDUINO_LIBRARY_SRCDIRS)) |
| | | |
| | | COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS) |
| | | COMPONENT_PRIV_INCLUDEDIRS := cores/esp32/libb64 |
| | | COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS) |
| | | CXXFLAGS += -fno-rtti |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef Arduino_h |
| | | #define Arduino_h |
| | | |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <stdarg.h> |
| | | #include <stddef.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <inttypes.h> |
| | | |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/semphr.h" |
| | | #include "esp32-hal.h" |
| | | #include "esp8266-compat.h" |
| | | #include "soc/gpio_reg.h" |
| | | |
| | | #include "stdlib_noniso.h" |
| | | #include "binary.h" |
| | | |
| | | #define PI 3.1415926535897932384626433832795 |
| | | #define HALF_PI 1.5707963267948966192313216916398 |
| | | #define TWO_PI 6.283185307179586476925286766559 |
| | | #define DEG_TO_RAD 0.017453292519943295769236907684886 |
| | | #define RAD_TO_DEG 57.295779513082320876798154814105 |
| | | #define EULER 2.718281828459045235360287471352 |
| | | |
| | | #define SERIAL 0x0 |
| | | #define DISPLAY 0x1 |
| | | |
| | | #define LSBFIRST 0 |
| | | #define MSBFIRST 1 |
| | | |
| | | //Interrupt Modes |
| | | #define RISING 0x01 |
| | | #define FALLING 0x02 |
| | | #define CHANGE 0x03 |
| | | #define ONLOW 0x04 |
| | | #define ONHIGH 0x05 |
| | | #define ONLOW_WE 0x0C |
| | | #define ONHIGH_WE 0x0D |
| | | |
| | | #define DEFAULT 1 |
| | | #define EXTERNAL 0 |
| | | |
| | | #ifndef __STRINGIFY |
| | | #define __STRINGIFY(a) #a |
| | | #endif |
| | | |
| | | #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) |
| | | #define radians(deg) ((deg)*DEG_TO_RAD) |
| | | #define degrees(rad) ((rad)*RAD_TO_DEG) |
| | | #define sq(x) ((x)*(x)) |
| | | |
| | | #define sei() |
| | | #define cli() |
| | | #define interrupts() sei() |
| | | #define noInterrupts() cli() |
| | | |
| | | #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) |
| | | #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) |
| | | #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) |
| | | |
| | | #define lowByte(w) ((uint8_t) ((w) & 0xff)) |
| | | #define highByte(w) ((uint8_t) ((w) >> 8)) |
| | | |
| | | #define bitRead(value, bit) (((value) >> (bit)) & 0x01) |
| | | #define bitSet(value, bit) ((value) |= (1UL << (bit))) |
| | | #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) |
| | | #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) |
| | | |
| | | // avr-libc defines _NOP() since 1.6.2 |
| | | #ifndef _NOP |
| | | #define _NOP() do { __asm__ volatile ("nop"); } while (0) |
| | | #endif |
| | | |
| | | #define bit(b) (1UL << (b)) |
| | | #define _BV(b) (1UL << (b)) |
| | | |
| | | #define digitalPinToPort(pin) (((pin)>31)?1:0) |
| | | #define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin))) |
| | | #define digitalPinToTimer(pin) (0) |
| | | #define analogInPinToBit(P) (P) |
| | | #define portOutputRegister(port) ((volatile uint32_t*)((port)?GPIO_OUT1_REG:GPIO_OUT_REG)) |
| | | #define portInputRegister(port) ((volatile uint32_t*)((port)?GPIO_IN1_REG:GPIO_IN_REG)) |
| | | #define portModeRegister(port) ((volatile uint32_t*)((port)?GPIO_ENABLE1_REG:GPIO_ENABLE_REG)) |
| | | |
| | | #define NOT_A_PIN -1 |
| | | #define NOT_A_PORT -1 |
| | | #define NOT_AN_INTERRUPT -1 |
| | | #define NOT_ON_TIMER 0 |
| | | |
| | | typedef bool boolean; |
| | | typedef uint8_t byte; |
| | | typedef unsigned int word; |
| | | |
| | | void setup(void); |
| | | void loop(void); |
| | | |
| | | long random(long, long); |
| | | void randomSeed(unsigned long); |
| | | long map(long, long, long, long, long); |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | void init(void); |
| | | void initVariant(void); |
| | | void initArduino(void); |
| | | |
| | | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); |
| | | unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); |
| | | |
| | | uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); |
| | | void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | |
| | | #include <algorithm> |
| | | #include <cmath> |
| | | |
| | | #include "WCharacter.h" |
| | | #include "WString.h" |
| | | #include "Stream.h" |
| | | #include "Printable.h" |
| | | #include "Print.h" |
| | | #include "IPAddress.h" |
| | | #include "Client.h" |
| | | #include "Server.h" |
| | | #include "Udp.h" |
| | | #include "HardwareSerial.h" |
| | | #include "Esp.h" |
| | | |
| | | using std::abs; |
| | | using std::isinf; |
| | | using std::isnan; |
| | | using std::max; |
| | | using std::min; |
| | | using ::round; |
| | | |
| | | uint16_t makeWord(uint16_t w); |
| | | uint16_t makeWord(byte h, byte l); |
| | | |
| | | #define word(...) makeWord(__VA_ARGS__) |
| | | |
| | | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); |
| | | unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); |
| | | |
| | | extern "C" bool getLocalTime(struct tm * info, uint32_t ms = 5000); |
| | | extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec, |
| | | const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); |
| | | extern "C" void configTzTime(const char* tz, |
| | | const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); |
| | | |
| | | // WMath prototypes |
| | | long random(long); |
| | | #endif /* __cplusplus */ |
| | | |
| | | #define _min(a,b) ((a)<(b)?(a):(b)) |
| | | #define _max(a,b) ((a)>(b)?(a):(b)) |
| | | |
| | | #include "pins_arduino.h" |
| | | |
| | | #endif /* _ESP32_CORE_ARDUINO_H_ */ |
| New file |
| | |
| | | /* |
| | | Client.h - Base class that provides Client |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef client_h |
| | | #define client_h |
| | | #include "Print.h" |
| | | #include "Stream.h" |
| | | #include "IPAddress.h" |
| | | |
| | | class Client: public Stream |
| | | { |
| | | public: |
| | | virtual int connect(IPAddress ip, uint16_t port) =0; |
| | | virtual int connect(const char *host, uint16_t port) =0; |
| | | virtual int connect(IPAddress ip, uint16_t port, int timeout) =0; |
| | | virtual int connect(const char *host, uint16_t port, int timeout) =0; |
| | | virtual size_t write(uint8_t) =0; |
| | | virtual size_t write(const uint8_t *buf, size_t size) =0; |
| | | virtual int available() = 0; |
| | | virtual int read() = 0; |
| | | virtual int read(uint8_t *buf, size_t size) = 0; |
| | | virtual int peek() = 0; |
| | | virtual void flush() = 0; |
| | | virtual void stop() = 0; |
| | | virtual uint8_t connected() = 0; |
| | | virtual operator bool() = 0; |
| | | protected: |
| | | uint8_t* rawIPAddress(IPAddress& addr) |
| | | { |
| | | return addr.raw_address(); |
| | | } |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Esp.cpp - ESP31B-specific APIs |
| | | Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #include "Arduino.h" |
| | | #include "Esp.h" |
| | | #include "rom/spi_flash.h" |
| | | #include "esp_sleep.h" |
| | | #include "esp_spi_flash.h" |
| | | #include <memory> |
| | | #include <soc/soc.h> |
| | | #include <soc/efuse_reg.h> |
| | | #include <esp_partition.h> |
| | | extern "C" { |
| | | #include "esp_ota_ops.h" |
| | | #include "esp_image_format.h" |
| | | } |
| | | #include <MD5Builder.h> |
| | | |
| | | /** |
| | | * User-defined Literals |
| | | * usage: |
| | | * |
| | | * uint32_t = test = 10_MHz; // --> 10000000 |
| | | */ |
| | | |
| | | unsigned long long operator"" _kHz(unsigned long long x) |
| | | { |
| | | return x * 1000; |
| | | } |
| | | |
| | | unsigned long long operator"" _MHz(unsigned long long x) |
| | | { |
| | | return x * 1000 * 1000; |
| | | } |
| | | |
| | | unsigned long long operator"" _GHz(unsigned long long x) |
| | | { |
| | | return x * 1000 * 1000 * 1000; |
| | | } |
| | | |
| | | unsigned long long operator"" _kBit(unsigned long long x) |
| | | { |
| | | return x * 1024; |
| | | } |
| | | |
| | | unsigned long long operator"" _MBit(unsigned long long x) |
| | | { |
| | | return x * 1024 * 1024; |
| | | } |
| | | |
| | | unsigned long long operator"" _GBit(unsigned long long x) |
| | | { |
| | | return x * 1024 * 1024 * 1024; |
| | | } |
| | | |
| | | unsigned long long operator"" _kB(unsigned long long x) |
| | | { |
| | | return x * 1024; |
| | | } |
| | | |
| | | unsigned long long operator"" _MB(unsigned long long x) |
| | | { |
| | | return x * 1024 * 1024; |
| | | } |
| | | |
| | | unsigned long long operator"" _GB(unsigned long long x) |
| | | { |
| | | return x * 1024 * 1024 * 1024; |
| | | } |
| | | |
| | | |
| | | EspClass ESP; |
| | | |
| | | void EspClass::deepSleep(uint32_t time_us) |
| | | { |
| | | esp_deep_sleep(time_us); |
| | | } |
| | | |
| | | uint32_t EspClass::getCycleCount() |
| | | { |
| | | uint32_t ccount; |
| | | __asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount)); |
| | | return ccount; |
| | | } |
| | | |
| | | void EspClass::restart(void) |
| | | { |
| | | esp_restart(); |
| | | } |
| | | |
| | | uint32_t EspClass::getHeapSize(void) |
| | | { |
| | | multi_heap_info_t info; |
| | | heap_caps_get_info(&info, MALLOC_CAP_INTERNAL); |
| | | return info.total_free_bytes + info.total_allocated_bytes; |
| | | } |
| | | |
| | | uint32_t EspClass::getFreeHeap(void) |
| | | { |
| | | return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); |
| | | } |
| | | |
| | | uint32_t EspClass::getMinFreeHeap(void) |
| | | { |
| | | return heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL); |
| | | } |
| | | |
| | | uint32_t EspClass::getMaxAllocHeap(void) |
| | | { |
| | | return heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); |
| | | } |
| | | |
| | | uint32_t EspClass::getPsramSize(void) |
| | | { |
| | | multi_heap_info_t info; |
| | | heap_caps_get_info(&info, MALLOC_CAP_SPIRAM); |
| | | return info.total_free_bytes + info.total_allocated_bytes; |
| | | } |
| | | |
| | | uint32_t EspClass::getFreePsram(void) |
| | | { |
| | | return heap_caps_get_free_size(MALLOC_CAP_SPIRAM); |
| | | } |
| | | |
| | | uint32_t EspClass::getMinFreePsram(void) |
| | | { |
| | | return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM); |
| | | } |
| | | |
| | | uint32_t EspClass::getMaxAllocPsram(void) |
| | | { |
| | | return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM); |
| | | } |
| | | |
| | | static uint32_t sketchSize(sketchSize_t response) { |
| | | esp_image_metadata_t data; |
| | | const esp_partition_t *running = esp_ota_get_running_partition(); |
| | | if (!running) return 0; |
| | | const esp_partition_pos_t running_pos = { |
| | | .offset = running->address, |
| | | .size = running->size, |
| | | }; |
| | | data.start_addr = running_pos.offset; |
| | | esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data); |
| | | if (response) { |
| | | return running_pos.size - data.image_len; |
| | | } else { |
| | | return data.image_len; |
| | | } |
| | | } |
| | | |
| | | uint32_t EspClass::getSketchSize () { |
| | | return sketchSize(SKETCH_SIZE_TOTAL); |
| | | } |
| | | |
| | | String EspClass::getSketchMD5() |
| | | { |
| | | static String result; |
| | | if (result.length()) { |
| | | return result; |
| | | } |
| | | uint32_t lengthLeft = getSketchSize(); |
| | | |
| | | const esp_partition_t *running = esp_ota_get_running_partition(); |
| | | if (!running) { |
| | | log_e("Partition could not be found"); |
| | | |
| | | return String(); |
| | | } |
| | | const size_t bufSize = SPI_FLASH_SEC_SIZE; |
| | | std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]); |
| | | uint32_t offset = 0; |
| | | if(!buf.get()) { |
| | | log_e("Not enough memory to allocate buffer"); |
| | | |
| | | return String(); |
| | | } |
| | | MD5Builder md5; |
| | | md5.begin(); |
| | | while( lengthLeft > 0) { |
| | | size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize; |
| | | if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) { |
| | | log_e("Could not read buffer from flash"); |
| | | |
| | | return String(); |
| | | } |
| | | md5.add(buf.get(), readBytes); |
| | | lengthLeft -= readBytes; |
| | | offset += readBytes; |
| | | } |
| | | md5.calculate(); |
| | | result = md5.toString(); |
| | | return result; |
| | | } |
| | | |
| | | uint32_t EspClass::getFreeSketchSpace () { |
| | | const esp_partition_t* _partition = esp_ota_get_next_update_partition(NULL); |
| | | if(!_partition){ |
| | | return 0; |
| | | } |
| | | |
| | | return _partition->size; |
| | | } |
| | | |
| | | uint8_t EspClass::getChipRevision(void) |
| | | { |
| | | esp_chip_info_t chip_info; |
| | | esp_chip_info(&chip_info); |
| | | return chip_info.revision; |
| | | } |
| | | |
| | | const char * EspClass::getSdkVersion(void) |
| | | { |
| | | return esp_get_idf_version(); |
| | | } |
| | | |
| | | uint32_t EspClass::getFlashChipSize(void) |
| | | { |
| | | esp_image_header_t fhdr; |
| | | if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { |
| | | return 0; |
| | | } |
| | | return magicFlashChipSize(fhdr.spi_size); |
| | | } |
| | | |
| | | uint32_t EspClass::getFlashChipSpeed(void) |
| | | { |
| | | esp_image_header_t fhdr; |
| | | if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { |
| | | return 0; |
| | | } |
| | | return magicFlashChipSpeed(fhdr.spi_speed); |
| | | } |
| | | |
| | | FlashMode_t EspClass::getFlashChipMode(void) |
| | | { |
| | | esp_image_header_t fhdr; |
| | | if(flashRead(0x1000, (uint32_t*)&fhdr, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { |
| | | return FM_UNKNOWN; |
| | | } |
| | | return magicFlashChipMode(fhdr.spi_mode); |
| | | } |
| | | |
| | | uint32_t EspClass::magicFlashChipSize(uint8_t byte) |
| | | { |
| | | switch(byte & 0x0F) { |
| | | case 0x0: // 8 MBit (1MB) |
| | | return (1_MB); |
| | | case 0x1: // 16 MBit (2MB) |
| | | return (2_MB); |
| | | case 0x2: // 32 MBit (4MB) |
| | | return (4_MB); |
| | | case 0x3: // 64 MBit (8MB) |
| | | return (8_MB); |
| | | case 0x4: // 128 MBit (16MB) |
| | | return (16_MB); |
| | | default: // fail? |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) |
| | | { |
| | | switch(byte & 0x0F) { |
| | | case 0x0: // 40 MHz |
| | | return (40_MHz); |
| | | case 0x1: // 26 MHz |
| | | return (26_MHz); |
| | | case 0x2: // 20 MHz |
| | | return (20_MHz); |
| | | case 0xf: // 80 MHz |
| | | return (80_MHz); |
| | | default: // fail? |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) |
| | | { |
| | | FlashMode_t mode = (FlashMode_t) byte; |
| | | if(mode > FM_SLOW_READ) { |
| | | mode = FM_UNKNOWN; |
| | | } |
| | | return mode; |
| | | } |
| | | |
| | | bool EspClass::flashEraseSector(uint32_t sector) |
| | | { |
| | | return spi_flash_erase_sector(sector) == ESP_OK; |
| | | } |
| | | |
| | | // Warning: These functions do not work with encrypted flash |
| | | bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) |
| | | { |
| | | return spi_flash_write(offset, (uint32_t*) data, size) == ESP_OK; |
| | | } |
| | | |
| | | bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) |
| | | { |
| | | return spi_flash_read(offset, (uint32_t*) data, size) == ESP_OK; |
| | | } |
| | | |
| | | |
| | | uint64_t EspClass::getEfuseMac(void) |
| | | { |
| | | uint64_t _chipmacid = 0LL; |
| | | esp_efuse_mac_get_default((uint8_t*) (&_chipmacid)); |
| | | return _chipmacid; |
| | | } |
| New file |
| | |
| | | /* |
| | | Esp.h - ESP31B-specific APIs |
| | | Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef ESP_H |
| | | #define ESP_H |
| | | |
| | | #include <Arduino.h> |
| | | |
| | | /** |
| | | * AVR macros for WDT managment |
| | | */ |
| | | typedef enum { |
| | | WDTO_0MS = 0, //!< WDTO_0MS |
| | | WDTO_15MS = 15, //!< WDTO_15MS |
| | | WDTO_30MS = 30, //!< WDTO_30MS |
| | | WDTO_60MS = 60, //!< WDTO_60MS |
| | | WDTO_120MS = 120, //!< WDTO_120MS |
| | | WDTO_250MS = 250, //!< WDTO_250MS |
| | | WDTO_500MS = 500, //!< WDTO_500MS |
| | | WDTO_1S = 1000,//!< WDTO_1S |
| | | WDTO_2S = 2000,//!< WDTO_2S |
| | | WDTO_4S = 4000,//!< WDTO_4S |
| | | WDTO_8S = 8000 //!< WDTO_8S |
| | | } WDTO_t; |
| | | |
| | | |
| | | typedef enum { |
| | | FM_QIO = 0x00, |
| | | FM_QOUT = 0x01, |
| | | FM_DIO = 0x02, |
| | | FM_DOUT = 0x03, |
| | | FM_FAST_READ = 0x04, |
| | | FM_SLOW_READ = 0x05, |
| | | FM_UNKNOWN = 0xff |
| | | } FlashMode_t; |
| | | |
| | | typedef enum { |
| | | SKETCH_SIZE_TOTAL = 0, |
| | | SKETCH_SIZE_FREE = 1 |
| | | } sketchSize_t; |
| | | |
| | | class EspClass |
| | | { |
| | | public: |
| | | EspClass() {} |
| | | ~EspClass() {} |
| | | void restart(); |
| | | |
| | | //Internal RAM |
| | | uint32_t getHeapSize(); //total heap size |
| | | uint32_t getFreeHeap(); //available heap |
| | | uint32_t getMinFreeHeap(); //lowest level of free heap since boot |
| | | uint32_t getMaxAllocHeap(); //largest block of heap that can be allocated at once |
| | | |
| | | //SPI RAM |
| | | uint32_t getPsramSize(); |
| | | uint32_t getFreePsram(); |
| | | uint32_t getMinFreePsram(); |
| | | uint32_t getMaxAllocPsram(); |
| | | |
| | | uint8_t getChipRevision(); |
| | | uint8_t getCpuFreqMHz(){ return CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; } |
| | | uint32_t getCycleCount(); |
| | | const char * getSdkVersion(); |
| | | |
| | | void deepSleep(uint32_t time_us); |
| | | |
| | | uint32_t getFlashChipSize(); |
| | | uint32_t getFlashChipSpeed(); |
| | | FlashMode_t getFlashChipMode(); |
| | | |
| | | uint32_t magicFlashChipSize(uint8_t byte); |
| | | uint32_t magicFlashChipSpeed(uint8_t byte); |
| | | FlashMode_t magicFlashChipMode(uint8_t byte); |
| | | |
| | | uint32_t getSketchSize(); |
| | | String getSketchMD5(); |
| | | uint32_t getFreeSketchSpace(); |
| | | |
| | | bool flashEraseSector(uint32_t sector); |
| | | bool flashWrite(uint32_t offset, uint32_t *data, size_t size); |
| | | bool flashRead(uint32_t offset, uint32_t *data, size_t size); |
| | | |
| | | uint64_t getEfuseMac(); |
| | | |
| | | }; |
| | | |
| | | extern EspClass ESP; |
| | | |
| | | #endif //ESP_H |
| New file |
| | |
| | | /* |
| | | * FunctionalInterrupt.cpp |
| | | * |
| | | * Created on: 8 jul. 2018 |
| | | * Author: Herman |
| | | */ |
| | | |
| | | #include "FunctionalInterrupt.h" |
| | | #include "Arduino.h" |
| | | |
| | | typedef void (*voidFuncPtr)(void); |
| | | typedef void (*voidFuncPtrArg)(void*); |
| | | |
| | | extern "C" |
| | | { |
| | | extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional); |
| | | } |
| | | |
| | | void IRAM_ATTR interruptFunctional(void* arg) |
| | | { |
| | | InterruptArgStructure* localArg = (InterruptArgStructure*)arg; |
| | | if (localArg->interruptFunction) |
| | | { |
| | | localArg->interruptFunction(); |
| | | } |
| | | } |
| | | |
| | | void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode) |
| | | { |
| | | // use the local interrupt routine which takes the ArgStructure as argument |
| | | __attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true); |
| | | } |
| | | |
| | | extern "C" |
| | | { |
| | | void cleanupFunctional(void* arg) |
| | | { |
| | | delete (InterruptArgStructure*)arg; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * FunctionalInterrupt.h |
| | | * |
| | | * Created on: 8 jul. 2018 |
| | | * Author: Herman |
| | | */ |
| | | |
| | | #ifndef CORE_CORE_FUNCTIONALINTERRUPT_H_ |
| | | #define CORE_CORE_FUNCTIONALINTERRUPT_H_ |
| | | |
| | | #include <functional> |
| | | |
| | | struct InterruptArgStructure { |
| | | std::function<void(void)> interruptFunction; |
| | | }; |
| | | |
| | | void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode); |
| | | |
| | | |
| | | #endif /* CORE_CORE_FUNCTIONALINTERRUPT_H_ */ |
| New file |
| | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <inttypes.h> |
| | | |
| | | #include "pins_arduino.h" |
| | | #include "HardwareSerial.h" |
| | | |
| | | #ifndef RX1 |
| | | #define RX1 9 |
| | | #endif |
| | | |
| | | #ifndef TX1 |
| | | #define TX1 10 |
| | | #endif |
| | | |
| | | #ifndef RX2 |
| | | #define RX2 16 |
| | | #endif |
| | | |
| | | #ifndef TX2 |
| | | #define TX2 17 |
| | | #endif |
| | | |
| | | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) |
| | | HardwareSerial Serial(0); |
| | | HardwareSerial Serial1(1); |
| | | HardwareSerial Serial2(2); |
| | | #endif |
| | | |
| | | HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {} |
| | | |
| | | void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms) |
| | | { |
| | | if(0 > _uart_nr || _uart_nr > 2) { |
| | | log_e("Serial number is invalid, please use 0, 1 or 2"); |
| | | return; |
| | | } |
| | | if(_uart) { |
| | | end(); |
| | | } |
| | | if(_uart_nr == 0 && rxPin < 0 && txPin < 0) { |
| | | rxPin = 3; |
| | | txPin = 1; |
| | | } |
| | | if(_uart_nr == 1 && rxPin < 0 && txPin < 0) { |
| | | rxPin = RX1; |
| | | txPin = TX1; |
| | | } |
| | | if(_uart_nr == 2 && rxPin < 0 && txPin < 0) { |
| | | rxPin = RX2; |
| | | txPin = TX2; |
| | | } |
| | | |
| | | _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert); |
| | | |
| | | if(!baud) { |
| | | time_t startMillis = millis(); |
| | | unsigned long detectedBaudRate = 0; |
| | | while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) { |
| | | yield(); |
| | | } |
| | | |
| | | end(); |
| | | |
| | | if(detectedBaudRate) { |
| | | delay(100); // Give some time... |
| | | _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert); |
| | | } 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; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void HardwareSerial::updateBaudRate(unsigned long baud) |
| | | { |
| | | uartSetBaudRate(_uart, baud); |
| | | } |
| | | |
| | | void HardwareSerial::end() |
| | | { |
| | | if(uartGetDebug() == _uart_nr) { |
| | | uartSetDebug(0); |
| | | } |
| | | uartEnd(_uart); |
| | | _uart = 0; |
| | | } |
| | | |
| | | size_t HardwareSerial::setRxBufferSize(size_t new_size) { |
| | | return uartResizeRxBuffer(_uart, new_size); |
| | | } |
| | | |
| | | void HardwareSerial::setDebugOutput(bool en) |
| | | { |
| | | if(_uart == 0) { |
| | | return; |
| | | } |
| | | if(en) { |
| | | uartSetDebug(_uart); |
| | | } else { |
| | | if(uartGetDebug() == _uart_nr) { |
| | | uartSetDebug(0); |
| | | } |
| | | } |
| | | } |
| | | |
| | | int HardwareSerial::available(void) |
| | | { |
| | | return uartAvailable(_uart); |
| | | } |
| | | int HardwareSerial::availableForWrite(void) |
| | | { |
| | | return uartAvailableForWrite(_uart); |
| | | } |
| | | |
| | | int HardwareSerial::peek(void) |
| | | { |
| | | if (available()) { |
| | | return uartPeek(_uart); |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | int HardwareSerial::read(void) |
| | | { |
| | | if(available()) { |
| | | return uartRead(_uart); |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | void HardwareSerial::flush() |
| | | { |
| | | uartFlush(_uart); |
| | | } |
| | | |
| | | size_t HardwareSerial::write(uint8_t c) |
| | | { |
| | | uartWrite(_uart, c); |
| | | return 1; |
| | | } |
| | | |
| | | size_t HardwareSerial::write(const uint8_t *buffer, size_t size) |
| | | { |
| | | uartWriteBuf(_uart, buffer, size); |
| | | return size; |
| | | } |
| | | uint32_t HardwareSerial::baudRate() |
| | | |
| | | { |
| | | return uartGetBaudRate(_uart); |
| | | } |
| | | HardwareSerial::operator bool() const |
| | | { |
| | | return true; |
| | | } |
| New file |
| | |
| | | /* |
| | | HardwareSerial.h - Hardware serial library for Wiring |
| | | Copyright (c) 2006 Nicholas Zambetti. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Modified 28 September 2010 by Mark Sproul |
| | | Modified 14 August 2012 by Alarus |
| | | Modified 3 December 2013 by Matthijs Kooijman |
| | | Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support) |
| | | Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266) |
| | | Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266) |
| | | Modified 13 October 2018 by Jeroen Döll (add baudrate detection) |
| | | Baudrate detection example usage (detection on Serial1): |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | delay(100); |
| | | Serial.println(); |
| | | |
| | | Serial1.begin(0, SERIAL_8N1, -1, -1, true, 11000UL); // Passing 0 for baudrate to detect it, the last parameter is a timeout in ms |
| | | |
| | | unsigned long detectedBaudRate = Serial1.baudRate(); |
| | | if(detectedBaudRate) { |
| | | Serial.printf("Detected baudrate is %lu\n", detectedBaudRate); |
| | | } else { |
| | | Serial.println("No baudrate detected, Serial1 will not work!"); |
| | | } |
| | | } |
| | | |
| | | Pay attention: the baudrate returned by baudRate() may be rounded, eg 115200 returns 115201 |
| | | */ |
| | | |
| | | #ifndef HardwareSerial_h |
| | | #define HardwareSerial_h |
| | | |
| | | #include <inttypes.h> |
| | | |
| | | #include "Stream.h" |
| | | #include "esp32-hal.h" |
| | | |
| | | class HardwareSerial: public Stream |
| | | { |
| | | public: |
| | | HardwareSerial(int uart_nr); |
| | | |
| | | void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL); |
| | | void end(); |
| | | void updateBaudRate(unsigned long baud); |
| | | int available(void); |
| | | int availableForWrite(void); |
| | | int peek(void); |
| | | int read(void); |
| | | void flush(void); |
| | | size_t write(uint8_t); |
| | | size_t write(const uint8_t *buffer, size_t 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); |
| | | } |
| | | uint32_t baudRate(); |
| | | operator bool() const; |
| | | |
| | | size_t setRxBufferSize(size_t); |
| | | void setDebugOutput(bool); |
| | | |
| | | protected: |
| | | int _uart_nr; |
| | | uart_t* _uart; |
| | | }; |
| | | |
| | | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) |
| | | extern HardwareSerial Serial; |
| | | extern HardwareSerial Serial1; |
| | | extern HardwareSerial Serial2; |
| | | #endif |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | IPAddress.cpp - Base class that provides IPAddress |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #include <Arduino.h> |
| | | #include <IPAddress.h> |
| | | #include <Print.h> |
| | | |
| | | IPAddress::IPAddress() |
| | | { |
| | | _address.dword = 0; |
| | | } |
| | | |
| | | IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) |
| | | { |
| | | _address.bytes[0] = first_octet; |
| | | _address.bytes[1] = second_octet; |
| | | _address.bytes[2] = third_octet; |
| | | _address.bytes[3] = fourth_octet; |
| | | } |
| | | |
| | | IPAddress::IPAddress(uint32_t address) |
| | | { |
| | | _address.dword = address; |
| | | } |
| | | |
| | | IPAddress::IPAddress(const uint8_t *address) |
| | | { |
| | | memcpy(_address.bytes, address, sizeof(_address.bytes)); |
| | | } |
| | | |
| | | IPAddress& IPAddress::operator=(const uint8_t *address) |
| | | { |
| | | memcpy(_address.bytes, address, sizeof(_address.bytes)); |
| | | return *this; |
| | | } |
| | | |
| | | IPAddress& IPAddress::operator=(uint32_t address) |
| | | { |
| | | _address.dword = address; |
| | | return *this; |
| | | } |
| | | |
| | | bool IPAddress::operator==(const uint8_t* addr) const |
| | | { |
| | | return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; |
| | | } |
| | | |
| | | size_t IPAddress::printTo(Print& p) const |
| | | { |
| | | size_t n = 0; |
| | | for(int i = 0; i < 3; i++) { |
| | | n += p.print(_address.bytes[i], DEC); |
| | | n += p.print('.'); |
| | | } |
| | | n += p.print(_address.bytes[3], DEC); |
| | | return n; |
| | | } |
| | | |
| | | String IPAddress::toString() const |
| | | { |
| | | char szRet[16]; |
| | | sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); |
| | | return String(szRet); |
| | | } |
| | | |
| | | bool IPAddress::fromString(const char *address) |
| | | { |
| | | // TODO: add support for "a", "a.b", "a.b.c" formats |
| | | |
| | | uint16_t acc = 0; // Accumulator |
| | | uint8_t dots = 0; |
| | | |
| | | while (*address) |
| | | { |
| | | char c = *address++; |
| | | if (c >= '0' && c <= '9') |
| | | { |
| | | acc = acc * 10 + (c - '0'); |
| | | if (acc > 255) { |
| | | // Value out of [0..255] range |
| | | return false; |
| | | } |
| | | } |
| | | else if (c == '.') |
| | | { |
| | | if (dots == 3) { |
| | | // Too much dots (there must be 3 dots) |
| | | return false; |
| | | } |
| | | _address.bytes[dots++] = acc; |
| | | acc = 0; |
| | | } |
| | | else |
| | | { |
| | | // Invalid char |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | if (dots != 3) { |
| | | // Too few dots (there must be 3 dots) |
| | | return false; |
| | | } |
| | | _address.bytes[3] = acc; |
| | | return true; |
| | | } |
| New file |
| | |
| | | /* |
| | | IPAddress.h - Base class that provides IPAddress |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef IPAddress_h |
| | | #define IPAddress_h |
| | | |
| | | #include <stdint.h> |
| | | #include <WString.h> |
| | | #include <Printable.h> |
| | | |
| | | // A class to make it easier to handle and pass around IP addresses |
| | | |
| | | class IPAddress: public Printable |
| | | { |
| | | private: |
| | | union { |
| | | uint8_t bytes[4]; // IPv4 address |
| | | uint32_t dword; |
| | | } _address; |
| | | |
| | | // Access the raw byte array containing the address. Because this returns a pointer |
| | | // to the internal structure rather than a copy of the address this function should only |
| | | // be used when you know that the usage of the returned uint8_t* will be transient and not |
| | | // stored. |
| | | uint8_t* raw_address() |
| | | { |
| | | return _address.bytes; |
| | | } |
| | | |
| | | public: |
| | | // Constructors |
| | | IPAddress(); |
| | | IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); |
| | | IPAddress(uint32_t address); |
| | | IPAddress(const uint8_t *address); |
| | | virtual ~IPAddress() {} |
| | | |
| | | bool fromString(const char *address); |
| | | bool fromString(const String &address) { return fromString(address.c_str()); } |
| | | |
| | | // Overloaded cast operator to allow IPAddress objects to be used where a pointer |
| | | // to a four-byte uint8_t array is expected |
| | | operator uint32_t() const |
| | | { |
| | | return _address.dword; |
| | | } |
| | | bool operator==(const IPAddress& addr) const |
| | | { |
| | | return _address.dword == addr._address.dword; |
| | | } |
| | | bool operator==(const uint8_t* addr) const; |
| | | |
| | | // Overloaded index operator to allow getting and setting individual octets of the address |
| | | uint8_t operator[](int index) const |
| | | { |
| | | return _address.bytes[index]; |
| | | } |
| | | uint8_t& operator[](int index) |
| | | { |
| | | return _address.bytes[index]; |
| | | } |
| | | |
| | | // Overloaded copy operators to allow initialisation of IPAddress objects from other types |
| | | IPAddress& operator=(const uint8_t *address); |
| | | IPAddress& operator=(uint32_t address); |
| | | |
| | | virtual size_t printTo(Print& p) const; |
| | | String toString() const; |
| | | |
| | | friend class EthernetClass; |
| | | friend class UDP; |
| | | friend class Client; |
| | | friend class Server; |
| | | friend class DhcpClass; |
| | | friend class DNSClient; |
| | | }; |
| | | |
| | | const IPAddress INADDR_NONE(0, 0, 0, 0); |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | IPv6Address.cpp - Base class that provides IPv6Address |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #include <Arduino.h> |
| | | #include <IPv6Address.h> |
| | | #include <Print.h> |
| | | |
| | | IPv6Address::IPv6Address() |
| | | { |
| | | memset(_address.bytes, 0, sizeof(_address.bytes)); |
| | | } |
| | | |
| | | IPv6Address::IPv6Address(const uint8_t *address) |
| | | { |
| | | memcpy(_address.bytes, address, sizeof(_address.bytes)); |
| | | } |
| | | |
| | | IPv6Address::IPv6Address(const uint32_t *address) |
| | | { |
| | | memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes)); |
| | | } |
| | | |
| | | IPv6Address& IPv6Address::operator=(const uint8_t *address) |
| | | { |
| | | memcpy(_address.bytes, address, sizeof(_address.bytes)); |
| | | return *this; |
| | | } |
| | | |
| | | bool IPv6Address::operator==(const uint8_t* addr) const |
| | | { |
| | | return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; |
| | | } |
| | | |
| | | size_t IPv6Address::printTo(Print& p) const |
| | | { |
| | | size_t n = 0; |
| | | for(int i = 0; i < 16; i+=2) { |
| | | if(i){ |
| | | n += p.print(':'); |
| | | } |
| | | n += p.printf("%02x", _address.bytes[i]); |
| | | n += p.printf("%02x", _address.bytes[i+1]); |
| | | |
| | | } |
| | | return n; |
| | | } |
| | | |
| | | String IPv6Address::toString() const |
| | | { |
| | | char szRet[40]; |
| | | sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", |
| | | _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3], |
| | | _address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7], |
| | | _address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11], |
| | | _address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]); |
| | | return String(szRet); |
| | | } |
| | | |
| | | bool IPv6Address::fromString(const char *address) |
| | | { |
| | | //format 0011:2233:4455:6677:8899:aabb:ccdd:eeff |
| | | if(strlen(address) != 39){ |
| | | return false; |
| | | } |
| | | char * pos = (char *)address; |
| | | size_t i = 0; |
| | | for(i = 0; i < 16; i+=2) { |
| | | if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){ |
| | | return false; |
| | | } |
| | | pos += 5; |
| | | } |
| | | return true; |
| | | } |
| New file |
| | |
| | | /* |
| | | IPv6Address.h - Base class that provides IPv6Address |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef IPv6Address_h |
| | | #define IPv6Address_h |
| | | |
| | | #include <stdint.h> |
| | | #include <WString.h> |
| | | #include <Printable.h> |
| | | |
| | | // A class to make it easier to handle and pass around IP addresses |
| | | |
| | | class IPv6Address: public Printable |
| | | { |
| | | private: |
| | | union { |
| | | uint8_t bytes[16]; // IPv4 address |
| | | uint32_t dword[4]; |
| | | } _address; |
| | | |
| | | // Access the raw byte array containing the address. Because this returns a pointer |
| | | // to the internal structure rather than a copy of the address this function should only |
| | | // be used when you know that the usage of the returned uint8_t* will be transient and not |
| | | // stored. |
| | | uint8_t* raw_address() |
| | | { |
| | | return _address.bytes; |
| | | } |
| | | |
| | | public: |
| | | // Constructors |
| | | IPv6Address(); |
| | | IPv6Address(const uint8_t *address); |
| | | IPv6Address(const uint32_t *address); |
| | | virtual ~IPv6Address() {} |
| | | |
| | | bool fromString(const char *address); |
| | | bool fromString(const String &address) { return fromString(address.c_str()); } |
| | | |
| | | operator const uint8_t*() const |
| | | { |
| | | return _address.bytes; |
| | | } |
| | | operator const uint32_t*() const |
| | | { |
| | | return _address.dword; |
| | | } |
| | | bool operator==(const IPv6Address& addr) const |
| | | { |
| | | return (_address.dword[0] == addr._address.dword[0]) |
| | | && (_address.dword[1] == addr._address.dword[1]) |
| | | && (_address.dword[2] == addr._address.dword[2]) |
| | | && (_address.dword[3] == addr._address.dword[3]); |
| | | } |
| | | bool operator==(const uint8_t* addr) const; |
| | | |
| | | // Overloaded index operator to allow getting and setting individual octets of the address |
| | | uint8_t operator[](int index) const |
| | | { |
| | | return _address.bytes[index]; |
| | | } |
| | | uint8_t& operator[](int index) |
| | | { |
| | | return _address.bytes[index]; |
| | | } |
| | | |
| | | // Overloaded copy operators to allow initialisation of IPv6Address objects from other types |
| | | IPv6Address& operator=(const uint8_t *address); |
| | | |
| | | virtual size_t printTo(Print& p) const; |
| | | String toString() const; |
| | | |
| | | friend class UDP; |
| | | friend class Client; |
| | | friend class Server; |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Copyright (c) 2015 Hristo Gochkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | #include <Arduino.h> |
| | | #include <MD5Builder.h> |
| | | |
| | | uint8_t hex_char_to_byte(uint8_t c) |
| | | { |
| | | return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : |
| | | (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : |
| | | (c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; |
| | | } |
| | | |
| | | void MD5Builder::begin(void) |
| | | { |
| | | memset(_buf, 0x00, 16); |
| | | MD5Init(&_ctx); |
| | | } |
| | | |
| | | void MD5Builder::add(uint8_t * data, uint16_t len) |
| | | { |
| | | MD5Update(&_ctx, data, len); |
| | | } |
| | | |
| | | void MD5Builder::addHexString(const char * data) |
| | | { |
| | | uint16_t i, len = strlen(data); |
| | | uint8_t * tmp = (uint8_t*)malloc(len/2); |
| | | if(tmp == NULL) { |
| | | return; |
| | | } |
| | | for(i=0; i<len; i+=2) { |
| | | uint8_t high = hex_char_to_byte(data[i]); |
| | | uint8_t low = hex_char_to_byte(data[i+1]); |
| | | tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F); |
| | | } |
| | | add(tmp, len/2); |
| | | free(tmp); |
| | | } |
| | | |
| | | bool MD5Builder::addStream(Stream & stream, const size_t maxLen) |
| | | { |
| | | const int buf_size = 512; |
| | | int maxLengthLeft = maxLen; |
| | | uint8_t * buf = (uint8_t*) malloc(buf_size); |
| | | |
| | | if(!buf) { |
| | | return false; |
| | | } |
| | | |
| | | int bytesAvailable = stream.available(); |
| | | while((bytesAvailable > 0) && (maxLengthLeft > 0)) { |
| | | |
| | | // determine number of bytes to read |
| | | int readBytes = bytesAvailable; |
| | | if(readBytes > maxLengthLeft) { |
| | | readBytes = maxLengthLeft ; // read only until max_len |
| | | } |
| | | if(readBytes > buf_size) { |
| | | readBytes = buf_size; // not read more the buffer can handle |
| | | } |
| | | |
| | | // read data and check if we got something |
| | | int numBytesRead = stream.readBytes(buf, readBytes); |
| | | if(numBytesRead< 1) { |
| | | return false; |
| | | } |
| | | |
| | | // Update MD5 with buffer payload |
| | | MD5Update(&_ctx, buf, numBytesRead); |
| | | |
| | | // update available number of bytes |
| | | maxLengthLeft -= numBytesRead; |
| | | bytesAvailable = stream.available(); |
| | | } |
| | | free(buf); |
| | | return true; |
| | | } |
| | | |
| | | void MD5Builder::calculate(void) |
| | | { |
| | | MD5Final(_buf, &_ctx); |
| | | } |
| | | |
| | | void MD5Builder::getBytes(uint8_t * output) |
| | | { |
| | | memcpy(output, _buf, 16); |
| | | } |
| | | |
| | | void MD5Builder::getChars(char * output) |
| | | { |
| | | for(uint8_t i = 0; i < 16; i++) { |
| | | sprintf(output + (i * 2), "%02x", _buf[i]); |
| | | } |
| | | } |
| | | |
| | | String MD5Builder::toString(void) |
| | | { |
| | | char out[33]; |
| | | getChars(out); |
| | | return String(out); |
| | | } |
| New file |
| | |
| | | /* |
| | | Copyright (c) 2015 Hristo Gochkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | #ifndef __ESP8266_MD5_BUILDER__ |
| | | #define __ESP8266_MD5_BUILDER__ |
| | | |
| | | #include <WString.h> |
| | | #include <Stream.h> |
| | | #include "rom/md5_hash.h" |
| | | |
| | | class MD5Builder |
| | | { |
| | | private: |
| | | struct MD5Context _ctx; |
| | | uint8_t _buf[16]; |
| | | public: |
| | | void begin(void); |
| | | void add(uint8_t * data, uint16_t len); |
| | | void add(const char * data) |
| | | { |
| | | add((uint8_t*)data, strlen(data)); |
| | | } |
| | | void add(char * data) |
| | | { |
| | | add((const char*)data); |
| | | } |
| | | void add(String data) |
| | | { |
| | | add(data.c_str()); |
| | | } |
| | | void addHexString(const char * data); |
| | | void addHexString(char * data) |
| | | { |
| | | addHexString((const char*)data); |
| | | } |
| | | void addHexString(String data) |
| | | { |
| | | addHexString(data.c_str()); |
| | | } |
| | | bool addStream(Stream & stream, const size_t maxLen); |
| | | void calculate(void); |
| | | void getBytes(uint8_t * output); |
| | | void getChars(char * output); |
| | | String toString(void); |
| | | }; |
| | | |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Print.cpp - Base class that provides print() and println() |
| | | Copyright (c) 2008 David A. Mellis. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Modified 23 November 2006 by David A. Mellis |
| | | Modified December 2014 by Ivan Grokhotkov |
| | | Modified May 2015 by Michael C. Miller - ESP31B progmem support |
| | | */ |
| | | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <math.h> |
| | | #include "Arduino.h" |
| | | |
| | | #include "Print.h" |
| | | extern "C" { |
| | | #include "time.h" |
| | | } |
| | | |
| | | // Public Methods ////////////////////////////////////////////////////////////// |
| | | |
| | | /* default implementation: may be overridden */ |
| | | size_t Print::write(const uint8_t *buffer, size_t size) |
| | | { |
| | | size_t n = 0; |
| | | while(size--) { |
| | | n += write(*buffer++); |
| | | } |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::printf(const char *format, ...) |
| | | { |
| | | char loc_buf[64]; |
| | | char * temp = loc_buf; |
| | | va_list arg; |
| | | va_list copy; |
| | | va_start(arg, format); |
| | | va_copy(copy, arg); |
| | | size_t len = vsnprintf(NULL, 0, format, arg); |
| | | va_end(copy); |
| | | if(len >= sizeof(loc_buf)){ |
| | | temp = new char[len+1]; |
| | | if(temp == NULL) { |
| | | return 0; |
| | | } |
| | | } |
| | | len = vsnprintf(temp, len+1, format, arg); |
| | | write((uint8_t*)temp, len); |
| | | va_end(arg); |
| | | if(len >= sizeof(loc_buf)){ |
| | | delete[] temp; |
| | | } |
| | | return len; |
| | | } |
| | | |
| | | size_t Print::print(const __FlashStringHelper *ifsh) |
| | | { |
| | | return print(reinterpret_cast<const char *>(ifsh)); |
| | | } |
| | | |
| | | size_t Print::print(const String &s) |
| | | { |
| | | return write(s.c_str(), s.length()); |
| | | } |
| | | |
| | | size_t Print::print(const char str[]) |
| | | { |
| | | return write(str); |
| | | } |
| | | |
| | | size_t Print::print(char c) |
| | | { |
| | | return write(c); |
| | | } |
| | | |
| | | size_t Print::print(unsigned char b, int base) |
| | | { |
| | | return print((unsigned long) b, base); |
| | | } |
| | | |
| | | size_t Print::print(int n, int base) |
| | | { |
| | | return print((long) n, base); |
| | | } |
| | | |
| | | size_t Print::print(unsigned int n, int base) |
| | | { |
| | | return print((unsigned long) n, base); |
| | | } |
| | | |
| | | size_t Print::print(long n, int base) |
| | | { |
| | | if(base == 0) { |
| | | return write(n); |
| | | } else if(base == 10) { |
| | | if(n < 0) { |
| | | int t = print('-'); |
| | | n = -n; |
| | | return printNumber(n, 10) + t; |
| | | } |
| | | return printNumber(n, 10); |
| | | } else { |
| | | return printNumber(n, base); |
| | | } |
| | | } |
| | | |
| | | size_t Print::print(unsigned long n, int base) |
| | | { |
| | | if(base == 0) { |
| | | return write(n); |
| | | } else { |
| | | return printNumber(n, base); |
| | | } |
| | | } |
| | | |
| | | size_t Print::print(double n, int digits) |
| | | { |
| | | return printFloat(n, digits); |
| | | } |
| | | |
| | | size_t Print::println(const __FlashStringHelper *ifsh) |
| | | { |
| | | size_t n = print(ifsh); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::print(const Printable& x) |
| | | { |
| | | return x.printTo(*this); |
| | | } |
| | | |
| | | size_t Print::print(struct tm * timeinfo, const char * format) |
| | | { |
| | | const char * f = format; |
| | | if(!f){ |
| | | f = "%c"; |
| | | } |
| | | char buf[64]; |
| | | size_t written = strftime(buf, 64, f, timeinfo); |
| | | print(buf); |
| | | return written; |
| | | } |
| | | |
| | | size_t Print::println(void) |
| | | { |
| | | return print("\r\n"); |
| | | } |
| | | |
| | | size_t Print::println(const String &s) |
| | | { |
| | | size_t n = print(s); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(const char c[]) |
| | | { |
| | | size_t n = print(c); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(char c) |
| | | { |
| | | size_t n = print(c); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(unsigned char b, int base) |
| | | { |
| | | size_t n = print(b, base); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(int num, int base) |
| | | { |
| | | size_t n = print(num, base); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(unsigned int num, int base) |
| | | { |
| | | size_t n = print(num, base); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(long num, int base) |
| | | { |
| | | size_t n = print(num, base); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(unsigned long num, int base) |
| | | { |
| | | size_t n = print(num, base); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(double num, int digits) |
| | | { |
| | | size_t n = print(num, digits); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(const Printable& x) |
| | | { |
| | | size_t n = print(x); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | size_t Print::println(struct tm * timeinfo, const char * format) |
| | | { |
| | | size_t n = print(timeinfo, format); |
| | | n += println(); |
| | | return n; |
| | | } |
| | | |
| | | // Private Methods ///////////////////////////////////////////////////////////// |
| | | |
| | | size_t Print::printNumber(unsigned long n, uint8_t base) |
| | | { |
| | | char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. |
| | | char *str = &buf[sizeof(buf) - 1]; |
| | | |
| | | *str = '\0'; |
| | | |
| | | // prevent crash if called with base == 1 |
| | | if(base < 2) { |
| | | base = 10; |
| | | } |
| | | |
| | | do { |
| | | unsigned long m = n; |
| | | n /= base; |
| | | char c = m - base * n; |
| | | *--str = c < 10 ? c + '0' : c + 'A' - 10; |
| | | } while(n); |
| | | |
| | | return write(str); |
| | | } |
| | | |
| | | size_t Print::printFloat(double number, uint8_t digits) |
| | | { |
| | | size_t n = 0; |
| | | |
| | | if(isnan(number)) { |
| | | return print("nan"); |
| | | } |
| | | if(isinf(number)) { |
| | | return print("inf"); |
| | | } |
| | | if(number > 4294967040.0) { |
| | | return print("ovf"); // constant determined empirically |
| | | } |
| | | if(number < -4294967040.0) { |
| | | return print("ovf"); // constant determined empirically |
| | | } |
| | | |
| | | // Handle negative numbers |
| | | if(number < 0.0) { |
| | | n += print('-'); |
| | | number = -number; |
| | | } |
| | | |
| | | // Round correctly so that print(1.999, 2) prints as "2.00" |
| | | double rounding = 0.5; |
| | | for(uint8_t i = 0; i < digits; ++i) { |
| | | rounding /= 10.0; |
| | | } |
| | | |
| | | number += rounding; |
| | | |
| | | // Extract the integer part of the number and print it |
| | | unsigned long int_part = (unsigned long) number; |
| | | double remainder = number - (double) int_part; |
| | | n += print(int_part); |
| | | |
| | | // Print the decimal point, but only if there are digits beyond |
| | | if(digits > 0) { |
| | | n += print("."); |
| | | } |
| | | |
| | | // Extract digits from the remainder one at a time |
| | | while(digits-- > 0) { |
| | | remainder *= 10.0; |
| | | int toPrint = int(remainder); |
| | | n += print(toPrint); |
| | | remainder -= toPrint; |
| | | } |
| | | |
| | | return n; |
| | | } |
| New file |
| | |
| | | /* |
| | | Print.h - Base class that provides print() and println() |
| | | Copyright (c) 2008 David A. Mellis. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef Print_h |
| | | #define Print_h |
| | | |
| | | #include <stdint.h> |
| | | #include <stddef.h> |
| | | |
| | | #include "WString.h" |
| | | #include "Printable.h" |
| | | |
| | | #define DEC 10 |
| | | #define HEX 16 |
| | | #define OCT 8 |
| | | #define BIN 2 |
| | | |
| | | class Print |
| | | { |
| | | private: |
| | | int write_error; |
| | | size_t printNumber(unsigned long, uint8_t); |
| | | size_t printFloat(double, uint8_t); |
| | | protected: |
| | | void setWriteError(int err = 1) |
| | | { |
| | | write_error = err; |
| | | } |
| | | public: |
| | | Print() : |
| | | write_error(0) |
| | | { |
| | | } |
| | | virtual ~Print() {} |
| | | int getWriteError() |
| | | { |
| | | return write_error; |
| | | } |
| | | void clearWriteError() |
| | | { |
| | | setWriteError(0); |
| | | } |
| | | |
| | | virtual size_t write(uint8_t) = 0; |
| | | size_t write(const char *str) |
| | | { |
| | | if(str == NULL) { |
| | | return 0; |
| | | } |
| | | return write((const uint8_t *) str, strlen(str)); |
| | | } |
| | | virtual size_t write(const uint8_t *buffer, size_t size); |
| | | size_t write(const char *buffer, size_t size) |
| | | { |
| | | return write((const uint8_t *) buffer, size); |
| | | } |
| | | |
| | | size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); |
| | | size_t print(const __FlashStringHelper *); |
| | | size_t print(const String &); |
| | | size_t print(const char[]); |
| | | size_t print(char); |
| | | size_t print(unsigned char, int = DEC); |
| | | size_t print(int, int = DEC); |
| | | size_t print(unsigned int, int = DEC); |
| | | size_t print(long, int = DEC); |
| | | size_t print(unsigned long, int = DEC); |
| | | size_t print(double, int = 2); |
| | | size_t print(const Printable&); |
| | | size_t print(struct tm * timeinfo, const char * format = NULL); |
| | | |
| | | size_t println(const __FlashStringHelper *); |
| | | size_t println(const String &s); |
| | | size_t println(const char[]); |
| | | size_t println(char); |
| | | size_t println(unsigned char, int = DEC); |
| | | size_t println(int, int = DEC); |
| | | size_t println(unsigned int, int = DEC); |
| | | size_t println(long, int = DEC); |
| | | size_t println(unsigned long, int = DEC); |
| | | size_t println(double, int = 2); |
| | | size_t println(const Printable&); |
| | | size_t println(struct tm * timeinfo, const char * format = NULL); |
| | | size_t println(void); |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Printable.h - Interface class that allows printing of complex types |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef Printable_h |
| | | #define Printable_h |
| | | |
| | | #include <stdlib.h> |
| | | |
| | | class Print; |
| | | |
| | | /** The Printable class provides a way for new classes to allow themselves to be printed. |
| | | By deriving from Printable and implementing the printTo method, it will then be possible |
| | | for users to print out instances of this class by passing them into the usual |
| | | Print::print and Print::println methods. |
| | | */ |
| | | |
| | | class Printable |
| | | { |
| | | public: |
| | | virtual ~Printable() {} |
| | | virtual size_t printTo(Print& p) const = 0; |
| | | }; |
| | | |
| | | #endif |
| | | |
| New file |
| | |
| | | /* |
| | | Server.h - Base class that provides Server |
| | | Copyright (c) 2011 Adrian McEwen. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef server_h |
| | | #define server_h |
| | | |
| | | #include "Print.h" |
| | | |
| | | class Server: public Print |
| | | { |
| | | public: |
| | | virtual void begin(uint16_t port=0) =0; |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Stream.cpp - adds parsing methods to Stream class |
| | | Copyright (c) 2008 David A. Mellis. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Created July 2011 |
| | | parsing functions based on TextFinder library by Michael Margolis |
| | | */ |
| | | |
| | | #include "Arduino.h" |
| | | #include "Stream.h" |
| | | #include "esp32-hal.h" |
| | | |
| | | #define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait |
| | | #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field |
| | | |
| | | // private method to read stream with timeout |
| | | int Stream::timedRead() |
| | | { |
| | | int c; |
| | | _startMillis = millis(); |
| | | do { |
| | | c = read(); |
| | | if(c >= 0) { |
| | | return c; |
| | | } |
| | | } while(millis() - _startMillis < _timeout); |
| | | return -1; // -1 indicates timeout |
| | | } |
| | | |
| | | // private method to peek stream with timeout |
| | | int Stream::timedPeek() |
| | | { |
| | | int c; |
| | | _startMillis = millis(); |
| | | do { |
| | | c = peek(); |
| | | if(c >= 0) { |
| | | return c; |
| | | } |
| | | } while(millis() - _startMillis < _timeout); |
| | | return -1; // -1 indicates timeout |
| | | } |
| | | |
| | | // returns peek of the next digit in the stream or -1 if timeout |
| | | // discards non-numeric characters |
| | | int Stream::peekNextDigit() |
| | | { |
| | | int c; |
| | | while(1) { |
| | | c = timedPeek(); |
| | | if(c < 0) { |
| | | return c; // timeout |
| | | } |
| | | if(c == '-') { |
| | | return c; |
| | | } |
| | | if(c >= '0' && c <= '9') { |
| | | return c; |
| | | } |
| | | read(); // discard non-numeric |
| | | } |
| | | } |
| | | |
| | | // Public Methods |
| | | ////////////////////////////////////////////////////////////// |
| | | |
| | | void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait |
| | | { |
| | | _timeout = timeout; |
| | | } |
| | | unsigned long Stream::getTimeout(void) { |
| | | return _timeout; |
| | | } |
| | | |
| | | // find returns true if the target string is found |
| | | bool Stream::find(const char *target) |
| | | { |
| | | return findUntil(target, (char*) ""); |
| | | } |
| | | |
| | | // reads data from the stream until the target string of given length is found |
| | | // returns true if target string is found, false if timed out |
| | | bool Stream::find(const char *target, size_t length) |
| | | { |
| | | return findUntil(target, length, NULL, 0); |
| | | } |
| | | |
| | | // as find but search ends if the terminator string is found |
| | | bool Stream::findUntil(const char *target, const char *terminator) |
| | | { |
| | | return findUntil(target, strlen(target), terminator, strlen(terminator)); |
| | | } |
| | | |
| | | // reads data from the stream until the target string of the given length is found |
| | | // search terminated if the terminator string is found |
| | | // returns true if target string is found, false if terminated or timed out |
| | | bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) |
| | | { |
| | | size_t index = 0; // maximum target string length is 64k bytes! |
| | | size_t termIndex = 0; |
| | | int c; |
| | | |
| | | if(*target == 0) { |
| | | return true; // return true if target is a null string |
| | | } |
| | | while((c = timedRead()) > 0) { |
| | | |
| | | if(c != target[index]) { |
| | | index = 0; // reset index if any char does not match |
| | | } |
| | | |
| | | if(c == target[index]) { |
| | | //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); |
| | | if(++index >= targetLen) { // return true if all chars in the target match |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | if(termLen > 0 && c == terminator[termIndex]) { |
| | | if(++termIndex >= termLen) { |
| | | return false; // return false if terminate string found before target string |
| | | } |
| | | } else { |
| | | termIndex = 0; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // returns the first valid (long) integer value from the current position. |
| | | // initial characters that are not digits (or the minus sign) are skipped |
| | | // function is terminated by the first character that is not a digit. |
| | | long Stream::parseInt() |
| | | { |
| | | return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) |
| | | } |
| | | |
| | | // as above but a given skipChar is ignored |
| | | // this allows format characters (typically commas) in values to be ignored |
| | | long Stream::parseInt(char skipChar) |
| | | { |
| | | boolean isNegative = false; |
| | | long value = 0; |
| | | int c; |
| | | |
| | | c = peekNextDigit(); |
| | | // ignore non numeric leading characters |
| | | if(c < 0) { |
| | | return 0; // zero returned if timeout |
| | | } |
| | | |
| | | do { |
| | | if(c == skipChar) { |
| | | } // ignore this charactor |
| | | else if(c == '-') { |
| | | isNegative = true; |
| | | } else if(c >= '0' && c <= '9') { // is c a digit? |
| | | value = value * 10 + c - '0'; |
| | | } |
| | | read(); // consume the character we got with peek |
| | | c = timedPeek(); |
| | | } while((c >= '0' && c <= '9') || c == skipChar); |
| | | |
| | | if(isNegative) { |
| | | value = -value; |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | // as parseInt but returns a floating point value |
| | | float Stream::parseFloat() |
| | | { |
| | | return parseFloat(NO_SKIP_CHAR); |
| | | } |
| | | |
| | | // as above but the given skipChar is ignored |
| | | // this allows format characters (typically commas) in values to be ignored |
| | | float Stream::parseFloat(char skipChar) |
| | | { |
| | | boolean isNegative = false; |
| | | boolean isFraction = false; |
| | | long value = 0; |
| | | int c; |
| | | float fraction = 1.0; |
| | | |
| | | c = peekNextDigit(); |
| | | // ignore non numeric leading characters |
| | | if(c < 0) { |
| | | return 0; // zero returned if timeout |
| | | } |
| | | |
| | | do { |
| | | if(c == skipChar) { |
| | | } // ignore |
| | | else if(c == '-') { |
| | | isNegative = true; |
| | | } else if(c == '.') { |
| | | isFraction = true; |
| | | } else if(c >= '0' && c <= '9') { // is c a digit? |
| | | value = value * 10 + c - '0'; |
| | | if(isFraction) { |
| | | fraction *= 0.1; |
| | | } |
| | | } |
| | | read(); // consume the character we got with peek |
| | | c = timedPeek(); |
| | | } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); |
| | | |
| | | if(isNegative) { |
| | | value = -value; |
| | | } |
| | | if(isFraction) { |
| | | return value * fraction; |
| | | } else { |
| | | return value; |
| | | } |
| | | } |
| | | |
| | | // read characters from stream into buffer |
| | | // terminates if length characters have been read, or timeout (see setTimeout) |
| | | // returns the number of characters placed in the buffer |
| | | // the buffer is NOT null terminated. |
| | | // |
| | | size_t Stream::readBytes(char *buffer, size_t length) |
| | | { |
| | | size_t count = 0; |
| | | while(count < length) { |
| | | int c = timedRead(); |
| | | if(c < 0) { |
| | | break; |
| | | } |
| | | *buffer++ = (char) c; |
| | | count++; |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | // as readBytes with terminator character |
| | | // terminates if length characters have been read, timeout, or if the terminator character detected |
| | | // returns the number of characters placed in the buffer (0 means no valid data found) |
| | | |
| | | size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) |
| | | { |
| | | if(length < 1) { |
| | | return 0; |
| | | } |
| | | size_t index = 0; |
| | | while(index < length) { |
| | | int c = timedRead(); |
| | | if(c < 0 || c == terminator) { |
| | | break; |
| | | } |
| | | *buffer++ = (char) c; |
| | | index++; |
| | | } |
| | | return index; // return number of characters, not including null terminator |
| | | } |
| | | |
| | | String Stream::readString() |
| | | { |
| | | String ret; |
| | | int c = timedRead(); |
| | | while(c >= 0) { |
| | | ret += (char) c; |
| | | c = timedRead(); |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | String Stream::readStringUntil(char terminator) |
| | | { |
| | | String ret; |
| | | int c = timedRead(); |
| | | while(c >= 0 && c != terminator) { |
| | | ret += (char) c; |
| | | c = timedRead(); |
| | | } |
| | | return ret; |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | Stream.h - base class for character-based streams. |
| | | Copyright (c) 2010 David A. Mellis. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | parsing functions based on TextFinder library by Michael Margolis |
| | | */ |
| | | |
| | | #ifndef Stream_h |
| | | #define Stream_h |
| | | |
| | | #include <inttypes.h> |
| | | #include "Print.h" |
| | | |
| | | // compatability macros for testing |
| | | /* |
| | | #define getInt() parseInt() |
| | | #define getInt(skipChar) parseInt(skipchar) |
| | | #define getFloat() parseFloat() |
| | | #define getFloat(skipChar) parseFloat(skipChar) |
| | | #define getString( pre_string, post_string, buffer, length) |
| | | readBytesBetween( pre_string, terminator, buffer, length) |
| | | */ |
| | | |
| | | class Stream: public Print |
| | | { |
| | | protected: |
| | | unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read |
| | | unsigned long _startMillis; // used for timeout measurement |
| | | int timedRead(); // private method to read stream with timeout |
| | | int timedPeek(); // private method to peek stream with timeout |
| | | int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout |
| | | |
| | | public: |
| | | virtual int available() = 0; |
| | | virtual int read() = 0; |
| | | virtual int peek() = 0; |
| | | virtual void flush() = 0; |
| | | |
| | | Stream():_startMillis(0) |
| | | { |
| | | _timeout = 1000; |
| | | } |
| | | virtual ~Stream() {} |
| | | |
| | | // parsing methods |
| | | |
| | | void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second |
| | | unsigned long getTimeout(void); |
| | | bool find(const char *target); // reads data from the stream until the target string is found |
| | | bool find(uint8_t *target) |
| | | { |
| | | return find((char *) target); |
| | | } |
| | | // returns true if target string is found, false if timed out (see setTimeout) |
| | | |
| | | bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found |
| | | bool find(const uint8_t *target, size_t length) |
| | | { |
| | | return find((char *) target, length); |
| | | } |
| | | // returns true if target string is found, false if timed out |
| | | |
| | | bool find(char target) |
| | | { |
| | | return find (&target, 1); |
| | | } |
| | | |
| | | bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found |
| | | bool findUntil(const uint8_t *target, const char *terminator) |
| | | { |
| | | return findUntil((char *) target, terminator); |
| | | } |
| | | |
| | | bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found |
| | | bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) |
| | | { |
| | | return findUntil((char *) target, targetLen, terminate, termLen); |
| | | } |
| | | |
| | | long parseInt(); // returns the first valid (long) integer value from the current position. |
| | | // initial characters that are not digits (or the minus sign) are skipped |
| | | // integer is terminated by the first character that is not a digit. |
| | | |
| | | float parseFloat(); // float version of parseInt |
| | | |
| | | virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer |
| | | virtual size_t readBytes(uint8_t *buffer, size_t length) |
| | | { |
| | | return readBytes((char *) buffer, length); |
| | | } |
| | | // terminates if length characters have been read or timeout (see setTimeout) |
| | | // returns the number of characters placed in the buffer (0 means no valid data found) |
| | | |
| | | size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character |
| | | size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) |
| | | { |
| | | return readBytesUntil(terminator, (char *) buffer, length); |
| | | } |
| | | // terminates if length characters have been read, timeout, or if the terminator character detected |
| | | // returns the number of characters placed in the buffer (0 means no valid data found) |
| | | |
| | | // Arduino String functions to be added here |
| | | virtual String readString(); |
| | | String readStringUntil(char terminator); |
| | | |
| | | protected: |
| | | long parseInt(char skipChar); // as above but the given skipChar is ignored |
| | | // as above but the given skipChar is ignored |
| | | // this allows format characters (typically commas) in values to be ignored |
| | | |
| | | float parseFloat(char skipChar); // as above but the given skipChar is ignored |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /** |
| | | StreamString.cpp |
| | | |
| | | Copyright (c) 2015 Markus Sattler. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | */ |
| | | |
| | | #include <Arduino.h> |
| | | #include "StreamString.h" |
| | | |
| | | size_t StreamString::write(const uint8_t *data, size_t size) { |
| | | if(size && data) { |
| | | const unsigned int newlen = length() + size; |
| | | if(reserve(newlen + 1)) { |
| | | memcpy((void *) (wbuffer() + len()), (const void *) data, size); |
| | | setLen(newlen); |
| | | *(wbuffer() + newlen) = 0x00; // add null for string end |
| | | return size; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | size_t StreamString::write(uint8_t data) { |
| | | return concat((char) data); |
| | | } |
| | | |
| | | int StreamString::available() { |
| | | return length(); |
| | | } |
| | | |
| | | int StreamString::read() { |
| | | if(length()) { |
| | | char c = charAt(0); |
| | | remove(0, 1); |
| | | return c; |
| | | |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | int StreamString::peek() { |
| | | if(length()) { |
| | | char c = charAt(0); |
| | | return c; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | void StreamString::flush() { |
| | | } |
| | | |
| New file |
| | |
| | | /** |
| | | StreamString.h |
| | | |
| | | Copyright (c) 2015 Markus Sattler. All rights reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | */ |
| | | |
| | | #ifndef STREAMSTRING_H_ |
| | | #define STREAMSTRING_H_ |
| | | |
| | | |
| | | class StreamString: public Stream, public String |
| | | { |
| | | public: |
| | | size_t write(const uint8_t *buffer, size_t size) override; |
| | | size_t write(uint8_t data) override; |
| | | |
| | | int available() override; |
| | | int read() override; |
| | | int peek() override; |
| | | void flush() override; |
| | | }; |
| | | |
| | | |
| | | #endif /* STREAMSTRING_H_ */ |
| New file |
| | |
| | | /* |
| | | * Udp.cpp: Library to send/receive UDP packets. |
| | | * |
| | | * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) |
| | | * 1) UDP does not guarantee the order in which assembled UDP packets are received. This |
| | | * might not happen often in practice, but in larger network topologies, a UDP |
| | | * packet can be received out of sequence. |
| | | * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being |
| | | * aware of it. Again, this may not be a concern in practice on small local networks. |
| | | * For more information, see http://www.cafeaulait.org/course/week12/35.html |
| | | * |
| | | * MIT License: |
| | | * Copyright (c) 2008 Bjoern Hartmann |
| | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| | | * of this software and associated documentation files (the "Software"), to deal |
| | | * in the Software without restriction, including without limitation the rights |
| | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| | | * copies of the Software, and to permit persons to whom the Software is |
| | | * furnished to do so, subject to the following conditions: |
| | | * |
| | | * The above copyright notice and this permission notice shall be included in |
| | | * all copies or substantial portions of the Software. |
| | | * |
| | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| | | * THE SOFTWARE. |
| | | * |
| | | * bjoern@cs.stanford.edu 12/30/2008 |
| | | */ |
| | | |
| | | #ifndef udp_h |
| | | #define udp_h |
| | | |
| | | #include <Stream.h> |
| | | #include <IPAddress.h> |
| | | |
| | | class UDP: public Stream |
| | | { |
| | | |
| | | public: |
| | | virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use |
| | | virtual void stop() =0; // Finish with the UDP socket |
| | | |
| | | // Sending UDP packets |
| | | |
| | | // Start building up a packet to send to the remote host specific in ip and port |
| | | // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port |
| | | virtual int beginPacket(IPAddress ip, uint16_t port) =0; |
| | | // Start building up a packet to send to the remote host specific in host and port |
| | | // Returns 1 if successful, 0 if there was a problem resolving the hostname or port |
| | | virtual int beginPacket(const char *host, uint16_t port) =0; |
| | | // Finish off this packet and send it |
| | | // Returns 1 if the packet was sent successfully, 0 if there was an error |
| | | virtual int endPacket() =0; |
| | | // Write a single byte into the packet |
| | | virtual size_t write(uint8_t) =0; |
| | | // Write size bytes from buffer into the packet |
| | | virtual size_t write(const uint8_t *buffer, size_t size) =0; |
| | | |
| | | // Start processing the next available incoming packet |
| | | // Returns the size of the packet in bytes, or 0 if no packets are available |
| | | virtual int parsePacket() =0; |
| | | // Number of bytes remaining in the current packet |
| | | virtual int available() =0; |
| | | // Read a single byte from the current packet |
| | | virtual int read() =0; |
| | | // Read up to len bytes from the current packet and place them into buffer |
| | | // Returns the number of bytes read, or 0 if none are available |
| | | virtual int read(unsigned char* buffer, size_t len) =0; |
| | | // Read up to len characters from the current packet and place them into buffer |
| | | // Returns the number of characters read, or 0 if none are available |
| | | virtual int read(char* buffer, size_t len) =0; |
| | | // Return the next byte from the current packet without moving on to the next byte |
| | | virtual int peek() =0; |
| | | virtual void flush() =0; // Finish reading the current packet |
| | | |
| | | // Return the IP address of the host who sent the current incoming packet |
| | | virtual IPAddress remoteIP() =0; |
| | | // Return the port of the host who sent the current incoming packet |
| | | virtual uint16_t remotePort() =0; |
| | | protected: |
| | | uint8_t* rawIPAddress(IPAddress& addr) |
| | | { |
| | | return addr.raw_address(); |
| | | } |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | WCharacter.h - Character utility functions for Wiring & Arduino |
| | | Copyright (c) 2010 Hernando Barragan. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef Character_h |
| | | #define Character_h |
| | | |
| | | #include <ctype.h> |
| | | #define isascii(__c) ((unsigned)(__c)<=0177) |
| | | #define toascii(__c) ((__c)&0177) |
| | | |
| | | // WCharacter.h prototypes |
| | | inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); |
| | | inline boolean isAlpha(int c) __attribute__((always_inline)); |
| | | inline boolean isAscii(int c) __attribute__((always_inline)); |
| | | inline boolean isWhitespace(int c) __attribute__((always_inline)); |
| | | inline boolean isControl(int c) __attribute__((always_inline)); |
| | | inline boolean isDigit(int c) __attribute__((always_inline)); |
| | | inline boolean isGraph(int c) __attribute__((always_inline)); |
| | | inline boolean isLowerCase(int c) __attribute__((always_inline)); |
| | | inline boolean isPrintable(int c) __attribute__((always_inline)); |
| | | inline boolean isPunct(int c) __attribute__((always_inline)); |
| | | inline boolean isSpace(int c) __attribute__((always_inline)); |
| | | inline boolean isUpperCase(int c) __attribute__((always_inline)); |
| | | inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); |
| | | inline int toAscii(int c) __attribute__((always_inline)); |
| | | inline int toLowerCase(int c) __attribute__((always_inline)); |
| | | inline int toUpperCase(int c) __attribute__((always_inline)); |
| | | |
| | | // Checks for an alphanumeric character. |
| | | // It is equivalent to (isalpha(c) || isdigit(c)). |
| | | inline boolean isAlphaNumeric(int c) |
| | | { |
| | | return (isalnum(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for an alphabetic character. |
| | | // It is equivalent to (isupper(c) || islower(c)). |
| | | inline boolean isAlpha(int c) |
| | | { |
| | | return (isalpha(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks whether c is a 7-bit unsigned char value |
| | | // that fits into the ASCII character set. |
| | | inline boolean isAscii(int c) |
| | | { |
| | | return ( isascii (c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for a blank character, that is, a space or a tab. |
| | | inline boolean isWhitespace(int c) |
| | | { |
| | | return (isblank(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for a control character. |
| | | inline boolean isControl(int c) |
| | | { |
| | | return (iscntrl(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for a digit (0 through 9). |
| | | inline boolean isDigit(int c) |
| | | { |
| | | return (isdigit(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for any printable character except space. |
| | | inline boolean isGraph(int c) |
| | | { |
| | | return (isgraph(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for a lower-case character. |
| | | inline boolean isLowerCase(int c) |
| | | { |
| | | return (islower(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for any printable character including space. |
| | | inline boolean isPrintable(int c) |
| | | { |
| | | return (isprint(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for any printable character which is not a space |
| | | // or an alphanumeric character. |
| | | inline boolean isPunct(int c) |
| | | { |
| | | return (ispunct(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for white-space characters. For the avr-libc library, |
| | | // these are: space, formfeed ('\f'), newline ('\n'), carriage |
| | | // return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). |
| | | inline boolean isSpace(int c) |
| | | { |
| | | return (isspace(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for an uppercase letter. |
| | | inline boolean isUpperCase(int c) |
| | | { |
| | | return (isupper(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 |
| | | // 8 9 a b c d e f A B C D E F. |
| | | inline boolean isHexadecimalDigit(int c) |
| | | { |
| | | return (isxdigit(c) == 0 ? false : true); |
| | | } |
| | | |
| | | // Converts c to a 7-bit unsigned char value that fits into the |
| | | // ASCII character set, by clearing the high-order bits. |
| | | inline int toAscii(int c) |
| | | { |
| | | return toascii(c); |
| | | } |
| | | |
| | | // Warning: |
| | | // Many people will be unhappy if you use this function. |
| | | // This function will convert accented letters into random |
| | | // characters. |
| | | |
| | | // Converts the letter c to lower case, if possible. |
| | | inline int toLowerCase(int c) |
| | | { |
| | | return tolower(c); |
| | | } |
| | | |
| | | // Converts the letter c to upper case, if possible. |
| | | inline int toUpperCase(int c) |
| | | { |
| | | return toupper(c); |
| | | } |
| | | |
| | | #endif |
| New file |
| | |
| | | /* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ |
| | | |
| | | /* |
| | | Part of the Wiring project - http://wiring.org.co |
| | | Copyright (c) 2004-06 Hernando Barragan |
| | | Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General |
| | | Public License along with this library; if not, write to the |
| | | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
| | | Boston, MA 02111-1307 USA |
| | | |
| | | $Id$ |
| | | */ |
| | | |
| | | extern "C" { |
| | | #include <stdlib.h> |
| | | #include "esp_system.h" |
| | | } |
| | | |
| | | void randomSeed(unsigned long seed) |
| | | { |
| | | if(seed != 0) { |
| | | srand(seed); |
| | | } |
| | | } |
| | | |
| | | long random(long howbig) |
| | | { |
| | | uint32_t x = esp_random(); |
| | | uint64_t m = uint64_t(x) * uint64_t(howbig); |
| | | uint32_t l = uint32_t(m); |
| | | if (l < howbig) { |
| | | uint32_t t = -howbig; |
| | | if (t >= howbig) { |
| | | t -= howbig; |
| | | if (t >= howbig) |
| | | t %= howbig; |
| | | } |
| | | while (l < t) { |
| | | x = esp_random(); |
| | | m = uint64_t(x) * uint64_t(howbig); |
| | | l = uint32_t(m); |
| | | } |
| | | } |
| | | return m >> 32; |
| | | } |
| | | |
| | | long random(long howsmall, long howbig) |
| | | { |
| | | if(howsmall >= howbig) { |
| | | return howsmall; |
| | | } |
| | | long diff = howbig - howsmall; |
| | | return random(diff) + howsmall; |
| | | } |
| | | |
| | | long map(long x, long in_min, long in_max, long out_min, long out_max) { |
| | | long divisor = (in_max - in_min); |
| | | if(divisor == 0){ |
| | | return -1; //AVR returns -1, SAM returns 0 |
| | | } |
| | | return (x - in_min) * (out_max - out_min) / divisor + out_min; |
| | | } |
| | | |
| | | unsigned int makeWord(unsigned int w) |
| | | { |
| | | return w; |
| | | } |
| | | |
| | | unsigned int makeWord(unsigned char h, unsigned char l) |
| | | { |
| | | return (h << 8) | l; |
| | | } |
| New file |
| | |
| | | /* |
| | | WString.cpp - String library for Wiring & Arduino |
| | | ...mostly rewritten by Paul Stoffregen... |
| | | Copyright (c) 2009-10 Hernando Barragan. All rights reserved. |
| | | Copyright 2011, Paul Stoffregen, paul@pjrc.com |
| | | Modified by Ivan Grokhotkov, 2014 - esp8266 support |
| | | Modified by Michael C. Miller, 2015 - esp8266 progmem support |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #include <Arduino.h> |
| | | #include "WString.h" |
| | | #include "stdlib_noniso.h" |
| | | |
| | | /*********************************************/ |
| | | /* Constructors */ |
| | | /*********************************************/ |
| | | |
| | | String::String(const char *cstr) { |
| | | init(); |
| | | if(cstr) |
| | | copy(cstr, strlen(cstr)); |
| | | } |
| | | |
| | | String::String(const String &value) { |
| | | init(); |
| | | *this = value; |
| | | } |
| | | |
| | | String::String(const __FlashStringHelper *pstr) { |
| | | init(); |
| | | *this = pstr; // see operator = |
| | | } |
| | | |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | String::String(String &&rval) { |
| | | init(); |
| | | move(rval); |
| | | } |
| | | |
| | | String::String(StringSumHelper &&rval) { |
| | | init(); |
| | | move(rval); |
| | | } |
| | | #endif |
| | | |
| | | String::String(char c) { |
| | | init(); |
| | | char buf[2]; |
| | | buf[0] = c; |
| | | buf[1] = 0; |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(unsigned char value, unsigned char base) { |
| | | init(); |
| | | char buf[1 + 8 * sizeof(unsigned char)]; |
| | | utoa(value, buf, base); |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(int value, unsigned char base) { |
| | | init(); |
| | | char buf[2 + 8 * sizeof(int)]; |
| | | if (base == 10) { |
| | | sprintf(buf, "%d", value); |
| | | } else { |
| | | itoa(value, buf, base); |
| | | } |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(unsigned int value, unsigned char base) { |
| | | init(); |
| | | char buf[1 + 8 * sizeof(unsigned int)]; |
| | | utoa(value, buf, base); |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(long value, unsigned char base) { |
| | | init(); |
| | | char buf[2 + 8 * sizeof(long)]; |
| | | if (base==10) { |
| | | sprintf(buf, "%ld", value); |
| | | } else { |
| | | ltoa(value, buf, base); |
| | | } |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(unsigned long value, unsigned char base) { |
| | | init(); |
| | | char buf[1 + 8 * sizeof(unsigned long)]; |
| | | ultoa(value, buf, base); |
| | | *this = buf; |
| | | } |
| | | |
| | | String::String(float value, unsigned char decimalPlaces) { |
| | | init(); |
| | | char buf[33]; |
| | | *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); |
| | | } |
| | | |
| | | String::String(double value, unsigned char decimalPlaces) { |
| | | init(); |
| | | char buf[33]; |
| | | *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); |
| | | } |
| | | |
| | | String::~String() { |
| | | invalidate(); |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Memory Management */ |
| | | // /*********************************************/ |
| | | |
| | | inline void String::init(void) { |
| | | setSSO(false); |
| | | setCapacity(0); |
| | | setLen(0); |
| | | setBuffer(nullptr); |
| | | } |
| | | |
| | | void String::invalidate(void) { |
| | | if(!sso() && wbuffer()) |
| | | free(wbuffer()); |
| | | init(); |
| | | } |
| | | |
| | | unsigned char String::reserve(unsigned int size) { |
| | | if(buffer() && capacity() >= size) |
| | | return 1; |
| | | if(changeBuffer(size)) { |
| | | if(len() == 0) |
| | | wbuffer()[0] = 0; |
| | | return 1; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | unsigned char String::changeBuffer(unsigned int maxStrLen) { |
| | | // Can we use SSO here to avoid allocation? |
| | | if (maxStrLen < sizeof(sso_buf)) { |
| | | if (sso() || !buffer()) { |
| | | // Already using SSO, nothing to do |
| | | setSSO(true); |
| | | return 1; |
| | | } else { // if bufptr && !sso() |
| | | // Using bufptr, need to shrink into sso_buff |
| | | char temp[sizeof(sso_buf)]; |
| | | memcpy(temp, buffer(), maxStrLen); |
| | | free(wbuffer()); |
| | | setSSO(true); |
| | | memcpy(wbuffer(), temp, maxStrLen); |
| | | return 1; |
| | | } |
| | | } |
| | | // Fallthrough to normal allocator |
| | | size_t newSize = (maxStrLen + 16) & (~0xf); |
| | | // Make sure we can fit newsize in the buffer |
| | | if (newSize > CAPACITY_MAX) { |
| | | return false; |
| | | } |
| | | uint16_t oldLen = len(); |
| | | char *newbuffer = (char *) realloc(sso() ? nullptr : wbuffer(), newSize); |
| | | if(newbuffer) { |
| | | size_t oldSize = capacity() + 1; // include NULL. |
| | | if (sso()) { |
| | | // Copy the SSO buffer into allocated space |
| | | memcpy(newbuffer, sso_buf, sizeof(sso_buf)); |
| | | } |
| | | if (newSize > oldSize) |
| | | { |
| | | memset(newbuffer + oldSize, 0, newSize - oldSize); |
| | | } |
| | | setSSO(false); |
| | | setCapacity(newSize - 1); |
| | | setLen(oldLen); // Needed in case of SSO where len() never existed |
| | | setBuffer(newbuffer); |
| | | return 1; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Copy and Move */ |
| | | // /*********************************************/ |
| | | |
| | | String & String::copy(const char *cstr, unsigned int length) { |
| | | if(!reserve(length)) { |
| | | invalidate(); |
| | | return *this; |
| | | } |
| | | setLen(length); |
| | | strcpy(wbuffer(), cstr); |
| | | return *this; |
| | | } |
| | | |
| | | String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { |
| | | if (!reserve(length)) { |
| | | invalidate(); |
| | | return *this; |
| | | } |
| | | setLen(length); |
| | | strcpy_P(wbuffer(), (PGM_P)pstr); |
| | | return *this; |
| | | } |
| | | |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | void String::move(String &rhs) { |
| | | if(buffer()) { |
| | | if(capacity() >= rhs.len()) { |
| | | strcpy(wbuffer(), rhs.buffer()); |
| | | setLen(rhs.len()); |
| | | rhs.invalidate(); |
| | | return; |
| | | } else { |
| | | if (!sso()) { |
| | | free(wbuffer()); |
| | | setBuffer(nullptr); |
| | | } |
| | | } |
| | | } |
| | | if (rhs.sso()) { |
| | | setSSO(true); |
| | | memmove(sso_buf, rhs.sso_buf, sizeof(sso_buf)); |
| | | } else { |
| | | setSSO(false); |
| | | setBuffer(rhs.wbuffer()); |
| | | } |
| | | setCapacity(rhs.capacity()); |
| | | setLen(rhs.len()); |
| | | rhs.setSSO(false); |
| | | rhs.setCapacity(0); |
| | | rhs.setLen(0); |
| | | rhs.setBuffer(nullptr); |
| | | } |
| | | #endif |
| | | |
| | | String & String::operator =(const String &rhs) { |
| | | if(this == &rhs) |
| | | return *this; |
| | | |
| | | if(rhs.buffer()) |
| | | copy(rhs.buffer(), rhs.len()); |
| | | else |
| | | invalidate(); |
| | | |
| | | return *this; |
| | | } |
| | | |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | String & String::operator =(String &&rval) { |
| | | if(this != &rval) |
| | | move(rval); |
| | | return *this; |
| | | } |
| | | |
| | | String & String::operator =(StringSumHelper &&rval) { |
| | | if(this != &rval) |
| | | move(rval); |
| | | return *this; |
| | | } |
| | | #endif |
| | | |
| | | String & String::operator =(const char *cstr) { |
| | | if(cstr) |
| | | copy(cstr, strlen(cstr)); |
| | | else |
| | | invalidate(); |
| | | |
| | | return *this; |
| | | } |
| | | |
| | | String & String::operator = (const __FlashStringHelper *pstr) |
| | | { |
| | | if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); |
| | | else invalidate(); |
| | | |
| | | return *this; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* concat */ |
| | | // /*********************************************/ |
| | | |
| | | unsigned char String::concat(const String &s) { |
| | | // Special case if we're concatting ourself (s += s;) since we may end up |
| | | // realloc'ing the buffer and moving s.buffer in the method called |
| | | if (&s == this) { |
| | | unsigned int newlen = 2 * len(); |
| | | if (!s.buffer()) |
| | | return 0; |
| | | if (s.len() == 0) |
| | | return 1; |
| | | if (!reserve(newlen)) |
| | | return 0; |
| | | memcpy(wbuffer() + len(), buffer(), len()); |
| | | setLen(newlen); |
| | | wbuffer()[len()] = 0; |
| | | return 1; |
| | | } else { |
| | | return concat(s.buffer(), s.len()); |
| | | } |
| | | } |
| | | |
| | | unsigned char String::concat(const char *cstr, unsigned int length) { |
| | | unsigned int newlen = len() + length; |
| | | if(!cstr) |
| | | return 0; |
| | | if(length == 0) |
| | | return 1; |
| | | if(!reserve(newlen)) |
| | | return 0; |
| | | strcpy(wbuffer() + len(), cstr); |
| | | setLen(newlen); |
| | | return 1; |
| | | } |
| | | |
| | | unsigned char String::concat(const char *cstr) { |
| | | if(!cstr) |
| | | return 0; |
| | | return concat(cstr, strlen(cstr)); |
| | | } |
| | | |
| | | unsigned char String::concat(char c) { |
| | | char buf[2]; |
| | | buf[0] = c; |
| | | buf[1] = 0; |
| | | return concat(buf, 1); |
| | | } |
| | | |
| | | unsigned char String::concat(unsigned char num) { |
| | | char buf[1 + 3 * sizeof(unsigned char)]; |
| | | sprintf(buf, "%d", num); |
| | | return concat(buf, strlen(buf)); |
| | | } |
| | | |
| | | unsigned char String::concat(int num) { |
| | | char buf[2 + 3 * sizeof(int)]; |
| | | sprintf(buf, "%d", num); |
| | | return concat(buf, strlen(buf)); |
| | | } |
| | | |
| | | unsigned char String::concat(unsigned int num) { |
| | | char buf[1 + 3 * sizeof(unsigned int)]; |
| | | utoa(num, buf, 10); |
| | | return concat(buf, strlen(buf)); |
| | | } |
| | | |
| | | unsigned char String::concat(long num) { |
| | | char buf[2 + 3 * sizeof(long)]; |
| | | sprintf(buf, "%ld", num); |
| | | return concat(buf, strlen(buf)); |
| | | } |
| | | |
| | | unsigned char String::concat(unsigned long num) { |
| | | char buf[1 + 3 * sizeof(unsigned long)]; |
| | | ultoa(num, buf, 10); |
| | | return concat(buf, strlen(buf)); |
| | | } |
| | | |
| | | unsigned char String::concat(float num) { |
| | | char buf[20]; |
| | | char* string = dtostrf(num, 4, 2, buf); |
| | | return concat(string, strlen(string)); |
| | | } |
| | | |
| | | unsigned char String::concat(double num) { |
| | | char buf[20]; |
| | | char* string = dtostrf(num, 4, 2, buf); |
| | | return concat(string, strlen(string)); |
| | | } |
| | | |
| | | unsigned char String::concat(const __FlashStringHelper * str) { |
| | | if (!str) return 0; |
| | | int length = strlen_P((PGM_P)str); |
| | | if (length == 0) return 1; |
| | | unsigned int newlen = len() + length; |
| | | if (!reserve(newlen)) return 0; |
| | | strcpy_P(wbuffer() + len(), (PGM_P)str); |
| | | setLen(newlen); |
| | | return 1; |
| | | } |
| | | |
| | | /*********************************************/ |
| | | /* Concatenate */ |
| | | /*********************************************/ |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(rhs.buffer(), rhs.len())) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!cstr || !a.concat(cstr, strlen(cstr))) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, char c) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(c)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, int num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, long num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, float num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator +(const StringSumHelper &lhs, double num) { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if(!a.concat(num)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) |
| | | { |
| | | StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
| | | if (!a.concat(rhs)) |
| | | a.invalidate(); |
| | | return a; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Comparison */ |
| | | // /*********************************************/ |
| | | |
| | | int String::compareTo(const String &s) const { |
| | | if(!buffer() || !s.buffer()) { |
| | | if(s.buffer() && s.len() > 0) |
| | | return 0 - *(unsigned char *) s.buffer(); |
| | | if(buffer() && len() > 0) |
| | | return *(unsigned char *) buffer(); |
| | | return 0; |
| | | } |
| | | return strcmp(buffer(), s.buffer()); |
| | | } |
| | | |
| | | unsigned char String::equals(const String &s2) const { |
| | | return (len() == s2.len() && compareTo(s2) == 0); |
| | | } |
| | | |
| | | unsigned char String::equals(const char *cstr) const { |
| | | if(len() == 0) |
| | | return (cstr == NULL || *cstr == 0); |
| | | if(cstr == NULL) |
| | | return buffer()[0] == 0; |
| | | return strcmp(buffer(), cstr) == 0; |
| | | } |
| | | |
| | | unsigned char String::operator<(const String &rhs) const { |
| | | return compareTo(rhs) < 0; |
| | | } |
| | | |
| | | unsigned char String::operator>(const String &rhs) const { |
| | | return compareTo(rhs) > 0; |
| | | } |
| | | |
| | | unsigned char String::operator<=(const String &rhs) const { |
| | | return compareTo(rhs) <= 0; |
| | | } |
| | | |
| | | unsigned char String::operator>=(const String &rhs) const { |
| | | return compareTo(rhs) >= 0; |
| | | } |
| | | |
| | | unsigned char String::equalsIgnoreCase(const String &s2) const { |
| | | if(this == &s2) |
| | | return 1; |
| | | if(len() != s2.len()) |
| | | return 0; |
| | | if(len() == 0) |
| | | return 1; |
| | | const char *p1 = buffer(); |
| | | const char *p2 = s2.buffer(); |
| | | while(*p1) { |
| | | if(tolower(*p1++) != tolower(*p2++)) |
| | | return 0; |
| | | } |
| | | return 1; |
| | | } |
| | | |
| | | unsigned char String::equalsConstantTime(const String &s2) const { |
| | | // To avoid possible time-based attacks present function |
| | | // compares given strings in a constant time. |
| | | if(len() != s2.len()) |
| | | return 0; |
| | | //at this point lengths are the same |
| | | if(len() == 0) |
| | | return 1; |
| | | //at this point lenghts are the same and non-zero |
| | | const char *p1 = buffer(); |
| | | const char *p2 = s2.buffer(); |
| | | unsigned int equalchars = 0; |
| | | unsigned int diffchars = 0; |
| | | while(*p1) { |
| | | if(*p1 == *p2) |
| | | ++equalchars; |
| | | else |
| | | ++diffchars; |
| | | ++p1; |
| | | ++p2; |
| | | } |
| | | //the following should force a constant time eval of the condition without a compiler "logical shortcut" |
| | | unsigned char equalcond = (equalchars == len()); |
| | | unsigned char diffcond = (diffchars == 0); |
| | | return (equalcond & diffcond); //bitwise AND |
| | | } |
| | | |
| | | unsigned char String::startsWith(const String &s2) const { |
| | | if(len() < s2.len()) |
| | | return 0; |
| | | return startsWith(s2, 0); |
| | | } |
| | | |
| | | unsigned char String::startsWith(const String &s2, unsigned int offset) const { |
| | | if(offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer()) |
| | | return 0; |
| | | return strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0; |
| | | } |
| | | |
| | | unsigned char String::endsWith(const String &s2) const { |
| | | if(len() < s2.len() || !buffer() || !s2.buffer()) |
| | | return 0; |
| | | return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Character Access */ |
| | | // /*********************************************/ |
| | | |
| | | char String::charAt(unsigned int loc) const { |
| | | return operator[](loc); |
| | | } |
| | | |
| | | void String::setCharAt(unsigned int loc, char c) { |
| | | if(loc < len()) |
| | | wbuffer()[loc] = c; |
| | | } |
| | | |
| | | char & String::operator[](unsigned int index) { |
| | | static char dummy_writable_char; |
| | | if(index >= len() || !buffer()) { |
| | | dummy_writable_char = 0; |
| | | return dummy_writable_char; |
| | | } |
| | | return wbuffer()[index]; |
| | | } |
| | | |
| | | char String::operator[](unsigned int index) const { |
| | | if(index >= len() || !buffer()) |
| | | return 0; |
| | | return buffer()[index]; |
| | | } |
| | | |
| | | void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const { |
| | | if(!bufsize || !buf) |
| | | return; |
| | | if(index >= len()) { |
| | | buf[0] = 0; |
| | | return; |
| | | } |
| | | unsigned int n = bufsize - 1; |
| | | if(n > len() - index) |
| | | n = len() - index; |
| | | strncpy((char *) buf, buffer() + index, n); |
| | | buf[n] = 0; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Search */ |
| | | // /*********************************************/ |
| | | |
| | | int String::indexOf(char c) const { |
| | | return indexOf(c, 0); |
| | | } |
| | | |
| | | int String::indexOf(char ch, unsigned int fromIndex) const { |
| | | if(fromIndex >= len()) |
| | | return -1; |
| | | const char* temp = strchr(buffer() + fromIndex, ch); |
| | | if(temp == NULL) |
| | | return -1; |
| | | return temp - buffer(); |
| | | } |
| | | |
| | | int String::indexOf(const String &s2) const { |
| | | return indexOf(s2, 0); |
| | | } |
| | | |
| | | int String::indexOf(const String &s2, unsigned int fromIndex) const { |
| | | if(fromIndex >= len()) |
| | | return -1; |
| | | const char *found = strstr(buffer() + fromIndex, s2.buffer()); |
| | | if(found == NULL) |
| | | return -1; |
| | | return found - buffer(); |
| | | } |
| | | |
| | | int String::lastIndexOf(char theChar) const { |
| | | return lastIndexOf(theChar, len() - 1); |
| | | } |
| | | |
| | | int String::lastIndexOf(char ch, unsigned int fromIndex) const { |
| | | if(fromIndex >= len()) |
| | | return -1; |
| | | char tempchar = buffer()[fromIndex + 1]; |
| | | wbuffer()[fromIndex + 1] = '\0'; |
| | | char* temp = strrchr(wbuffer(), ch); |
| | | wbuffer()[fromIndex + 1] = tempchar; |
| | | if(temp == NULL) |
| | | return -1; |
| | | return temp - buffer(); |
| | | } |
| | | |
| | | int String::lastIndexOf(const String &s2) const { |
| | | return lastIndexOf(s2, len() - s2.len()); |
| | | } |
| | | |
| | | int String::lastIndexOf(const String &s2, unsigned int fromIndex) const { |
| | | if(s2.len() == 0 || len() == 0 || s2.len() > len()) |
| | | return -1; |
| | | if(fromIndex >= len()) |
| | | fromIndex = len() - 1; |
| | | int found = -1; |
| | | for(char *p = wbuffer(); p <= wbuffer() + fromIndex; p++) { |
| | | p = strstr(p, s2.buffer()); |
| | | if(!p) |
| | | break; |
| | | if((unsigned int) (p - wbuffer()) <= fromIndex) |
| | | found = p - buffer(); |
| | | } |
| | | return found; |
| | | } |
| | | |
| | | String String::substring(unsigned int left, unsigned int right) const { |
| | | if(left > right) { |
| | | unsigned int temp = right; |
| | | right = left; |
| | | left = temp; |
| | | } |
| | | String out; |
| | | if(left >= len()) |
| | | 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 |
| | | return out; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Modification */ |
| | | // /*********************************************/ |
| | | |
| | | void String::replace(char find, char replace) { |
| | | if(!buffer()) |
| | | return; |
| | | for(char *p = wbuffer(); *p; p++) { |
| | | if(*p == find) |
| | | *p = replace; |
| | | } |
| | | } |
| | | |
| | | void String::replace(const String& find, const String& replace) { |
| | | if(len() == 0 || find.len() == 0) |
| | | return; |
| | | int diff = replace.len() - find.len(); |
| | | char *readFrom = wbuffer(); |
| | | char *foundAt; |
| | | if(diff == 0) { |
| | | while((foundAt = strstr(readFrom, find.buffer())) != NULL) { |
| | | memmove(foundAt, replace.buffer(), replace.len()); |
| | | readFrom = foundAt + replace.len(); |
| | | } |
| | | } else if(diff < 0) { |
| | | char *writeTo = wbuffer(); |
| | | while((foundAt = strstr(readFrom, find.buffer())) != NULL) { |
| | | unsigned int n = foundAt - readFrom; |
| | | memmove(writeTo, readFrom, n); |
| | | writeTo += n; |
| | | memmove(writeTo, replace.buffer(), replace.len()); |
| | | writeTo += replace.len(); |
| | | readFrom = foundAt + find.len(); |
| | | setLen(len() + diff); |
| | | } |
| | | memmove(writeTo, readFrom, strlen(readFrom)+1); |
| | | } else { |
| | | unsigned int size = len(); // compute size needed for result |
| | | while((foundAt = strstr(readFrom, find.buffer())) != NULL) { |
| | | readFrom = foundAt + find.len(); |
| | | size += diff; |
| | | } |
| | | if(size == len()) |
| | | return; |
| | | if(size > capacity() && !changeBuffer(size)) |
| | | return; // XXX: tell user! |
| | | int index = len() - 1; |
| | | while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) { |
| | | readFrom = wbuffer() + index + find.len(); |
| | | memmove(readFrom + diff, readFrom, len() - (readFrom - buffer())); |
| | | int newLen = len() + diff; |
| | | memmove(wbuffer() + index, replace.buffer(), replace.len()); |
| | | setLen(newLen); |
| | | wbuffer()[newLen] = 0; |
| | | index--; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void String::remove(unsigned int index) { |
| | | // Pass the biggest integer as the count. The remove method |
| | | // below will take care of truncating it at the end of the |
| | | // string. |
| | | remove(index, (unsigned int) -1); |
| | | } |
| | | |
| | | void String::remove(unsigned int index, unsigned int count) { |
| | | if(index >= len()) { |
| | | return; |
| | | } |
| | | if(count <= 0) { |
| | | return; |
| | | } |
| | | if(count > len() - index) { |
| | | count = len() - index; |
| | | } |
| | | char *writeTo = wbuffer() + index; |
| | | unsigned int newlen = len() - count; |
| | | setLen(newlen); |
| | | memmove(writeTo, wbuffer() + index + count, newlen - index); |
| | | wbuffer()[newlen] = 0; |
| | | } |
| | | |
| | | void String::toLowerCase(void) { |
| | | if(!buffer()) |
| | | return; |
| | | for(char *p = wbuffer(); *p; p++) { |
| | | *p = tolower(*p); |
| | | } |
| | | } |
| | | |
| | | void String::toUpperCase(void) { |
| | | if(!buffer()) |
| | | return; |
| | | for(char *p = wbuffer(); *p; p++) { |
| | | *p = toupper(*p); |
| | | } |
| | | } |
| | | |
| | | void String::trim(void) { |
| | | if(!buffer() || len() == 0) |
| | | return; |
| | | char *begin = wbuffer(); |
| | | while(isspace(*begin)) |
| | | begin++; |
| | | char *end = wbuffer() + len() - 1; |
| | | while(isspace(*end) && end >= begin) |
| | | end--; |
| | | unsigned int newlen = end + 1 - begin; |
| | | setLen(newlen); |
| | | if(begin > buffer()) |
| | | memmove(wbuffer(), begin, newlen); |
| | | wbuffer()[newlen] = 0; |
| | | } |
| | | |
| | | // /*********************************************/ |
| | | // /* Parsing / Conversion */ |
| | | // /*********************************************/ |
| | | |
| | | long String::toInt(void) const { |
| | | if (buffer()) |
| | | return atol(buffer()); |
| | | return 0; |
| | | } |
| | | |
| | | float String::toFloat(void) const { |
| | | if (buffer()) |
| | | return atof(buffer()); |
| | | return 0; |
| | | } |
| | | |
| | | double String::toDouble(void) const |
| | | { |
| | | if (buffer()) |
| | | return atof(buffer()); |
| | | return 0.0; |
| | | } |
| | | |
| | | // global empty string to allow returning const String& with nothing |
| | | |
| | | const String emptyString; |
| New file |
| | |
| | | /* |
| | | WString.h - String library for Wiring & Arduino |
| | | ...mostly rewritten by Paul Stoffregen... |
| | | Copyright (c) 2009-10 Hernando Barragan. All right reserved. |
| | | Copyright 2011, Paul Stoffregen, paul@pjrc.com |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef String_class_h |
| | | #define String_class_h |
| | | #ifdef __cplusplus |
| | | |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <ctype.h> |
| | | #include <pgmspace.h> |
| | | |
| | | // An inherited class for holding the result of a concatenation. These |
| | | // result objects are assumed to be writable by subsequent concatenations. |
| | | class StringSumHelper; |
| | | |
| | | // an abstract class used as a means to proide a unique pointer type |
| | | // but really has no body |
| | | class __FlashStringHelper; |
| | | #define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal))) |
| | | |
| | | // The string class |
| | | class String { |
| | | // use a function pointer to allow for "if (s)" without the |
| | | // complications of an operator bool(). for more information, see: |
| | | // http://www.artima.com/cppsource/safebool.html |
| | | typedef void (String::*StringIfHelperType)() const; |
| | | void StringIfHelper() const { |
| | | } |
| | | |
| | | public: |
| | | // constructors |
| | | // creates a copy of the initial value. |
| | | // if the initial value is null or invalid, or if memory allocation |
| | | // fails, the string will be marked as invalid (i.e. "if (s)" will |
| | | // be false). |
| | | String(const char *cstr = ""); |
| | | String(const String &str); |
| | | String(const __FlashStringHelper *str); |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | String(String &&rval); |
| | | String(StringSumHelper &&rval); |
| | | #endif |
| | | explicit String(char c); |
| | | explicit String(unsigned char, unsigned char base = 10); |
| | | explicit String(int, unsigned char base = 10); |
| | | explicit String(unsigned int, unsigned char base = 10); |
| | | explicit String(long, unsigned char base = 10); |
| | | explicit String(unsigned long, unsigned char base = 10); |
| | | explicit String(float, unsigned char decimalPlaces = 2); |
| | | explicit String(double, unsigned char decimalPlaces = 2); |
| | | ~String(void); |
| | | |
| | | // memory management |
| | | // return true on success, false on failure (in which case, the string |
| | | // is left unchanged). reserve(0), if successful, will validate an |
| | | // invalid string (i.e., "if (s)" will be true afterwards) |
| | | unsigned char reserve(unsigned int size); |
| | | inline unsigned int length(void) const { |
| | | if(buffer()) { |
| | | return len(); |
| | | } else { |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | // creates a copy of the assigned value. if the value is null or |
| | | // invalid, or if the memory allocation fails, the string will be |
| | | // marked as invalid ("if (s)" will be false). |
| | | String & operator =(const String &rhs); |
| | | String & operator =(const char *cstr); |
| | | String & operator = (const __FlashStringHelper *str); |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | String & operator =(String &&rval); |
| | | String & operator =(StringSumHelper &&rval); |
| | | #endif |
| | | |
| | | // concatenate (works w/ built-in types) |
| | | |
| | | // returns true on success, false on failure (in which case, the string |
| | | // is left unchanged). if the argument is null or invalid, the |
| | | // concatenation is considered unsucessful. |
| | | unsigned char concat(const String &str); |
| | | unsigned char concat(const char *cstr); |
| | | unsigned char concat(char c); |
| | | unsigned char concat(unsigned char c); |
| | | unsigned char concat(int num); |
| | | unsigned char concat(unsigned int num); |
| | | unsigned char concat(long num); |
| | | unsigned char concat(unsigned long num); |
| | | unsigned char concat(float num); |
| | | unsigned char concat(double num); |
| | | unsigned char concat(const __FlashStringHelper * str); |
| | | |
| | | // if there's not enough memory for the concatenated value, the string |
| | | // will be left unchanged (but this isn't signalled in any way) |
| | | String & operator +=(const String &rhs) { |
| | | concat(rhs); |
| | | return (*this); |
| | | } |
| | | String & operator +=(const char *cstr) { |
| | | concat(cstr); |
| | | return (*this); |
| | | } |
| | | String & operator +=(char c) { |
| | | concat(c); |
| | | return (*this); |
| | | } |
| | | String & operator +=(unsigned char num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(int num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(unsigned int num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(long num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(unsigned long num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(float num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator +=(double num) { |
| | | concat(num); |
| | | return (*this); |
| | | } |
| | | String & operator += (const __FlashStringHelper *str){ |
| | | concat(str); |
| | | return (*this); |
| | | } |
| | | |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, char c); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, int num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, long num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, float num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, double num); |
| | | friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs); |
| | | |
| | | // comparison (only works w/ Strings and "strings") |
| | | operator StringIfHelperType() const { |
| | | return buffer() ? &String::StringIfHelper : 0; |
| | | } |
| | | int compareTo(const String &s) const; |
| | | unsigned char equals(const String &s) const; |
| | | unsigned char equals(const char *cstr) const; |
| | | unsigned char operator ==(const String &rhs) const { |
| | | return equals(rhs); |
| | | } |
| | | unsigned char operator ==(const char *cstr) const { |
| | | return equals(cstr); |
| | | } |
| | | unsigned char operator !=(const String &rhs) const { |
| | | return !equals(rhs); |
| | | } |
| | | unsigned char operator !=(const char *cstr) const { |
| | | return !equals(cstr); |
| | | } |
| | | unsigned char operator <(const String &rhs) const; |
| | | unsigned char operator >(const String &rhs) const; |
| | | unsigned char operator <=(const String &rhs) const; |
| | | unsigned char operator >=(const String &rhs) const; |
| | | unsigned char equalsIgnoreCase(const String &s) const; |
| | | unsigned char equalsConstantTime(const String &s) const; |
| | | unsigned char startsWith(const String &prefix) const; |
| | | unsigned char startsWith(const String &prefix, unsigned int offset) const; |
| | | unsigned char endsWith(const String &suffix) const; |
| | | |
| | | // character acccess |
| | | char charAt(unsigned int index) const; |
| | | void setCharAt(unsigned int index, char c); |
| | | char operator [](unsigned int index) const; |
| | | char& operator [](unsigned int index); |
| | | void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const; |
| | | void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const { |
| | | getBytes((unsigned char *) buf, bufsize, index); |
| | | } |
| | | const char* c_str() const { return buffer(); } |
| | | char* begin() { return wbuffer(); } |
| | | char* end() { return wbuffer() + length(); } |
| | | const char* begin() const { return c_str(); } |
| | | const char* end() const { return c_str() + length(); } |
| | | |
| | | // search |
| | | int indexOf(char ch) const; |
| | | int indexOf(char ch, unsigned int fromIndex) const; |
| | | int indexOf(const String &str) const; |
| | | int indexOf(const String &str, unsigned int fromIndex) const; |
| | | int lastIndexOf(char ch) const; |
| | | int lastIndexOf(char ch, unsigned int fromIndex) const; |
| | | int lastIndexOf(const String &str) const; |
| | | int lastIndexOf(const String &str, unsigned int fromIndex) const; |
| | | String substring(unsigned int beginIndex) const { |
| | | return substring(beginIndex, len()); |
| | | } |
| | | ; |
| | | String substring(unsigned int beginIndex, unsigned int endIndex) const; |
| | | |
| | | // modification |
| | | void replace(char find, char replace); |
| | | void replace(const String& find, const String& replace); |
| | | void remove(unsigned int index); |
| | | void remove(unsigned int index, unsigned int count); |
| | | void toLowerCase(void); |
| | | void toUpperCase(void); |
| | | void trim(void); |
| | | |
| | | // parsing/conversion |
| | | long toInt(void) const; |
| | | float toFloat(void) const; |
| | | double toDouble(void) const; |
| | | |
| | | protected: |
| | | // Contains the string info when we're not in SSO mode |
| | | struct _ptr { |
| | | char * buff; |
| | | uint16_t cap; |
| | | uint16_t len; |
| | | }; |
| | | |
| | | // SSO is handled by checking the last byte of sso_buff. |
| | | // When not in SSO mode, that byte is set to 0xff, while when in SSO mode it is always 0x00 (so it can serve as the string terminator as well as a flag) |
| | | // This allows strings up up to 12 (11 + \0 termination) without any extra space. |
| | | enum { SSOSIZE = sizeof(struct _ptr) + 4 }; // Characters to allocate space for SSO, must be 12 or more |
| | | enum { CAPACITY_MAX = 65535 }; // If size of capacity changed, be sure to update this enum |
| | | union { |
| | | struct _ptr ptr; |
| | | char sso_buf[SSOSIZE]; |
| | | }; |
| | | // Accessor functions |
| | | inline bool sso() const { return sso_buf[SSOSIZE - 1] == 0; } |
| | | inline unsigned int len() const { return sso() ? strlen(sso_buf) : ptr.len; } |
| | | inline unsigned int capacity() const { return sso() ? SSOSIZE - 1 : ptr.cap; } |
| | | inline void setSSO(bool sso) { sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff; } |
| | | inline void setLen(int len) { if (!sso()) ptr.len = len; } |
| | | inline void setCapacity(int cap) { if (!sso()) ptr.cap = cap; } |
| | | inline void setBuffer(char *buff) { if (!sso()) ptr.buff = buff; } |
| | | // Buffer accessor functions |
| | | inline const char *buffer() const { return (const char *)(sso() ? sso_buf : ptr.buff); } |
| | | inline char *wbuffer() const { return sso() ? const_cast<char *>(sso_buf) : ptr.buff; } // Writable version of buffer |
| | | |
| | | protected: |
| | | 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); |
| | | String & copy(const __FlashStringHelper *pstr, unsigned int length); |
| | | #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
| | | void move(String &rhs); |
| | | #endif |
| | | }; |
| | | |
| | | class StringSumHelper: public String { |
| | | public: |
| | | StringSumHelper(const String &s) : |
| | | String(s) { |
| | | } |
| | | StringSumHelper(const char *p) : |
| | | String(p) { |
| | | } |
| | | StringSumHelper(char c) : |
| | | String(c) { |
| | | } |
| | | StringSumHelper(unsigned char num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(int num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(unsigned int num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(long num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(unsigned long num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(float num) : |
| | | String(num) { |
| | | } |
| | | StringSumHelper(double num) : |
| | | String(num) { |
| | | } |
| | | }; |
| | | |
| | | extern const String emptyString; |
| | | |
| | | #endif // __cplusplus |
| | | #endif // String_class_h |
| New file |
| | |
| | | #include "lwip/apps/sntp.h" |
| New file |
| | |
| | | /** |
| | | * base64.cpp |
| | | * |
| | | * Created on: 09.12.2015 |
| | | * |
| | | * Copyright (c) 2015 Markus Sattler. All rights reserved. |
| | | * This file is part of the ESP31B core for Arduino. |
| | | * |
| | | * This library is free software; you can redistribute it and/or |
| | | * modify it under the terms of the GNU Lesser General Public |
| | | * License as published by the Free Software Foundation; either |
| | | * version 2.1 of the License, or (at your option) any later version. |
| | | * |
| | | * This library is distributed in the hope that it will be useful, |
| | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | * |
| | | */ |
| | | |
| | | #include "Arduino.h" |
| | | extern "C" { |
| | | #include "libb64/cdecode.h" |
| | | #include "libb64/cencode.h" |
| | | } |
| | | #include "base64.h" |
| | | |
| | | /** |
| | | * convert input data to base64 |
| | | * @param data uint8_t * |
| | | * @param length size_t |
| | | * @return String |
| | | */ |
| | | String base64::encode(uint8_t * data, size_t length) |
| | | { |
| | | size_t size = base64_encode_expected_len(length) + 1; |
| | | char * buffer = (char *) malloc(size); |
| | | if(buffer) { |
| | | base64_encodestate _state; |
| | | base64_init_encodestate(&_state); |
| | | int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); |
| | | len = base64_encode_blockend((buffer + len), &_state); |
| | | |
| | | String base64 = String(buffer); |
| | | free(buffer); |
| | | return base64; |
| | | } |
| | | return String("-FAIL-"); |
| | | } |
| | | |
| | | /** |
| | | * convert input data to base64 |
| | | * @param text String |
| | | * @return String |
| | | */ |
| | | String base64::encode(String text) |
| | | { |
| | | return base64::encode((uint8_t *) text.c_str(), text.length()); |
| | | } |
| | | |
| New file |
| | |
| | | #ifndef CORE_BASE64_H_ |
| | | #define CORE_BASE64_H_ |
| | | |
| | | class base64 |
| | | { |
| | | public: |
| | | static String encode(uint8_t * data, size_t length); |
| | | static String encode(String text); |
| | | private: |
| | | }; |
| | | |
| | | |
| | | #endif /* CORE_BASE64_H_ */ |
| New file |
| | |
| | | /* |
| | | binary.h - Definitions for binary constants |
| | | Copyright (c) 2006 David A. Mellis. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef Binary_h |
| | | #define Binary_h |
| | | |
| | | #define B0 0 |
| | | #define B00 0 |
| | | #define B000 0 |
| | | #define B0000 0 |
| | | #define B00000 0 |
| | | #define B000000 0 |
| | | #define B0000000 0 |
| | | #define B00000000 0 |
| | | #define B1 1 |
| | | #define B01 1 |
| | | #define B001 1 |
| | | #define B0001 1 |
| | | #define B00001 1 |
| | | #define B000001 1 |
| | | #define B0000001 1 |
| | | #define B00000001 1 |
| | | #define B10 2 |
| | | #define B010 2 |
| | | #define B0010 2 |
| | | #define B00010 2 |
| | | #define B000010 2 |
| | | #define B0000010 2 |
| | | #define B00000010 2 |
| | | #define B11 3 |
| | | #define B011 3 |
| | | #define B0011 3 |
| | | #define B00011 3 |
| | | #define B000011 3 |
| | | #define B0000011 3 |
| | | #define B00000011 3 |
| | | #define B100 4 |
| | | #define B0100 4 |
| | | #define B00100 4 |
| | | #define B000100 4 |
| | | #define B0000100 4 |
| | | #define B00000100 4 |
| | | #define B101 5 |
| | | #define B0101 5 |
| | | #define B00101 5 |
| | | #define B000101 5 |
| | | #define B0000101 5 |
| | | #define B00000101 5 |
| | | #define B110 6 |
| | | #define B0110 6 |
| | | #define B00110 6 |
| | | #define B000110 6 |
| | | #define B0000110 6 |
| | | #define B00000110 6 |
| | | #define B111 7 |
| | | #define B0111 7 |
| | | #define B00111 7 |
| | | #define B000111 7 |
| | | #define B0000111 7 |
| | | #define B00000111 7 |
| | | #define B1000 8 |
| | | #define B01000 8 |
| | | #define B001000 8 |
| | | #define B0001000 8 |
| | | #define B00001000 8 |
| | | #define B1001 9 |
| | | #define B01001 9 |
| | | #define B001001 9 |
| | | #define B0001001 9 |
| | | #define B00001001 9 |
| | | #define B1010 10 |
| | | #define B01010 10 |
| | | #define B001010 10 |
| | | #define B0001010 10 |
| | | #define B00001010 10 |
| | | #define B1011 11 |
| | | #define B01011 11 |
| | | #define B001011 11 |
| | | #define B0001011 11 |
| | | #define B00001011 11 |
| | | #define B1100 12 |
| | | #define B01100 12 |
| | | #define B001100 12 |
| | | #define B0001100 12 |
| | | #define B00001100 12 |
| | | #define B1101 13 |
| | | #define B01101 13 |
| | | #define B001101 13 |
| | | #define B0001101 13 |
| | | #define B00001101 13 |
| | | #define B1110 14 |
| | | #define B01110 14 |
| | | #define B001110 14 |
| | | #define B0001110 14 |
| | | #define B00001110 14 |
| | | #define B1111 15 |
| | | #define B01111 15 |
| | | #define B001111 15 |
| | | #define B0001111 15 |
| | | #define B00001111 15 |
| | | #define B10000 16 |
| | | #define B010000 16 |
| | | #define B0010000 16 |
| | | #define B00010000 16 |
| | | #define B10001 17 |
| | | #define B010001 17 |
| | | #define B0010001 17 |
| | | #define B00010001 17 |
| | | #define B10010 18 |
| | | #define B010010 18 |
| | | #define B0010010 18 |
| | | #define B00010010 18 |
| | | #define B10011 19 |
| | | #define B010011 19 |
| | | #define B0010011 19 |
| | | #define B00010011 19 |
| | | #define B10100 20 |
| | | #define B010100 20 |
| | | #define B0010100 20 |
| | | #define B00010100 20 |
| | | #define B10101 21 |
| | | #define B010101 21 |
| | | #define B0010101 21 |
| | | #define B00010101 21 |
| | | #define B10110 22 |
| | | #define B010110 22 |
| | | #define B0010110 22 |
| | | #define B00010110 22 |
| | | #define B10111 23 |
| | | #define B010111 23 |
| | | #define B0010111 23 |
| | | #define B00010111 23 |
| | | #define B11000 24 |
| | | #define B011000 24 |
| | | #define B0011000 24 |
| | | #define B00011000 24 |
| | | #define B11001 25 |
| | | #define B011001 25 |
| | | #define B0011001 25 |
| | | #define B00011001 25 |
| | | #define B11010 26 |
| | | #define B011010 26 |
| | | #define B0011010 26 |
| | | #define B00011010 26 |
| | | #define B11011 27 |
| | | #define B011011 27 |
| | | #define B0011011 27 |
| | | #define B00011011 27 |
| | | #define B11100 28 |
| | | #define B011100 28 |
| | | #define B0011100 28 |
| | | #define B00011100 28 |
| | | #define B11101 29 |
| | | #define B011101 29 |
| | | #define B0011101 29 |
| | | #define B00011101 29 |
| | | #define B11110 30 |
| | | #define B011110 30 |
| | | #define B0011110 30 |
| | | #define B00011110 30 |
| | | #define B11111 31 |
| | | #define B011111 31 |
| | | #define B0011111 31 |
| | | #define B00011111 31 |
| | | #define B100000 32 |
| | | #define B0100000 32 |
| | | #define B00100000 32 |
| | | #define B100001 33 |
| | | #define B0100001 33 |
| | | #define B00100001 33 |
| | | #define B100010 34 |
| | | #define B0100010 34 |
| | | #define B00100010 34 |
| | | #define B100011 35 |
| | | #define B0100011 35 |
| | | #define B00100011 35 |
| | | #define B100100 36 |
| | | #define B0100100 36 |
| | | #define B00100100 36 |
| | | #define B100101 37 |
| | | #define B0100101 37 |
| | | #define B00100101 37 |
| | | #define B100110 38 |
| | | #define B0100110 38 |
| | | #define B00100110 38 |
| | | #define B100111 39 |
| | | #define B0100111 39 |
| | | #define B00100111 39 |
| | | #define B101000 40 |
| | | #define B0101000 40 |
| | | #define B00101000 40 |
| | | #define B101001 41 |
| | | #define B0101001 41 |
| | | #define B00101001 41 |
| | | #define B101010 42 |
| | | #define B0101010 42 |
| | | #define B00101010 42 |
| | | #define B101011 43 |
| | | #define B0101011 43 |
| | | #define B00101011 43 |
| | | #define B101100 44 |
| | | #define B0101100 44 |
| | | #define B00101100 44 |
| | | #define B101101 45 |
| | | #define B0101101 45 |
| | | #define B00101101 45 |
| | | #define B101110 46 |
| | | #define B0101110 46 |
| | | #define B00101110 46 |
| | | #define B101111 47 |
| | | #define B0101111 47 |
| | | #define B00101111 47 |
| | | #define B110000 48 |
| | | #define B0110000 48 |
| | | #define B00110000 48 |
| | | #define B110001 49 |
| | | #define B0110001 49 |
| | | #define B00110001 49 |
| | | #define B110010 50 |
| | | #define B0110010 50 |
| | | #define B00110010 50 |
| | | #define B110011 51 |
| | | #define B0110011 51 |
| | | #define B00110011 51 |
| | | #define B110100 52 |
| | | #define B0110100 52 |
| | | #define B00110100 52 |
| | | #define B110101 53 |
| | | #define B0110101 53 |
| | | #define B00110101 53 |
| | | #define B110110 54 |
| | | #define B0110110 54 |
| | | #define B00110110 54 |
| | | #define B110111 55 |
| | | #define B0110111 55 |
| | | #define B00110111 55 |
| | | #define B111000 56 |
| | | #define B0111000 56 |
| | | #define B00111000 56 |
| | | #define B111001 57 |
| | | #define B0111001 57 |
| | | #define B00111001 57 |
| | | #define B111010 58 |
| | | #define B0111010 58 |
| | | #define B00111010 58 |
| | | #define B111011 59 |
| | | #define B0111011 59 |
| | | #define B00111011 59 |
| | | #define B111100 60 |
| | | #define B0111100 60 |
| | | #define B00111100 60 |
| | | #define B111101 61 |
| | | #define B0111101 61 |
| | | #define B00111101 61 |
| | | #define B111110 62 |
| | | #define B0111110 62 |
| | | #define B00111110 62 |
| | | #define B111111 63 |
| | | #define B0111111 63 |
| | | #define B00111111 63 |
| | | #define B1000000 64 |
| | | #define B01000000 64 |
| | | #define B1000001 65 |
| | | #define B01000001 65 |
| | | #define B1000010 66 |
| | | #define B01000010 66 |
| | | #define B1000011 67 |
| | | #define B01000011 67 |
| | | #define B1000100 68 |
| | | #define B01000100 68 |
| | | #define B1000101 69 |
| | | #define B01000101 69 |
| | | #define B1000110 70 |
| | | #define B01000110 70 |
| | | #define B1000111 71 |
| | | #define B01000111 71 |
| | | #define B1001000 72 |
| | | #define B01001000 72 |
| | | #define B1001001 73 |
| | | #define B01001001 73 |
| | | #define B1001010 74 |
| | | #define B01001010 74 |
| | | #define B1001011 75 |
| | | #define B01001011 75 |
| | | #define B1001100 76 |
| | | #define B01001100 76 |
| | | #define B1001101 77 |
| | | #define B01001101 77 |
| | | #define B1001110 78 |
| | | #define B01001110 78 |
| | | #define B1001111 79 |
| | | #define B01001111 79 |
| | | #define B1010000 80 |
| | | #define B01010000 80 |
| | | #define B1010001 81 |
| | | #define B01010001 81 |
| | | #define B1010010 82 |
| | | #define B01010010 82 |
| | | #define B1010011 83 |
| | | #define B01010011 83 |
| | | #define B1010100 84 |
| | | #define B01010100 84 |
| | | #define B1010101 85 |
| | | #define B01010101 85 |
| | | #define B1010110 86 |
| | | #define B01010110 86 |
| | | #define B1010111 87 |
| | | #define B01010111 87 |
| | | #define B1011000 88 |
| | | #define B01011000 88 |
| | | #define B1011001 89 |
| | | #define B01011001 89 |
| | | #define B1011010 90 |
| | | #define B01011010 90 |
| | | #define B1011011 91 |
| | | #define B01011011 91 |
| | | #define B1011100 92 |
| | | #define B01011100 92 |
| | | #define B1011101 93 |
| | | #define B01011101 93 |
| | | #define B1011110 94 |
| | | #define B01011110 94 |
| | | #define B1011111 95 |
| | | #define B01011111 95 |
| | | #define B1100000 96 |
| | | #define B01100000 96 |
| | | #define B1100001 97 |
| | | #define B01100001 97 |
| | | #define B1100010 98 |
| | | #define B01100010 98 |
| | | #define B1100011 99 |
| | | #define B01100011 99 |
| | | #define B1100100 100 |
| | | #define B01100100 100 |
| | | #define B1100101 101 |
| | | #define B01100101 101 |
| | | #define B1100110 102 |
| | | #define B01100110 102 |
| | | #define B1100111 103 |
| | | #define B01100111 103 |
| | | #define B1101000 104 |
| | | #define B01101000 104 |
| | | #define B1101001 105 |
| | | #define B01101001 105 |
| | | #define B1101010 106 |
| | | #define B01101010 106 |
| | | #define B1101011 107 |
| | | #define B01101011 107 |
| | | #define B1101100 108 |
| | | #define B01101100 108 |
| | | #define B1101101 109 |
| | | #define B01101101 109 |
| | | #define B1101110 110 |
| | | #define B01101110 110 |
| | | #define B1101111 111 |
| | | #define B01101111 111 |
| | | #define B1110000 112 |
| | | #define B01110000 112 |
| | | #define B1110001 113 |
| | | #define B01110001 113 |
| | | #define B1110010 114 |
| | | #define B01110010 114 |
| | | #define B1110011 115 |
| | | #define B01110011 115 |
| | | #define B1110100 116 |
| | | #define B01110100 116 |
| | | #define B1110101 117 |
| | | #define B01110101 117 |
| | | #define B1110110 118 |
| | | #define B01110110 118 |
| | | #define B1110111 119 |
| | | #define B01110111 119 |
| | | #define B1111000 120 |
| | | #define B01111000 120 |
| | | #define B1111001 121 |
| | | #define B01111001 121 |
| | | #define B1111010 122 |
| | | #define B01111010 122 |
| | | #define B1111011 123 |
| | | #define B01111011 123 |
| | | #define B1111100 124 |
| | | #define B01111100 124 |
| | | #define B1111101 125 |
| | | #define B01111101 125 |
| | | #define B1111110 126 |
| | | #define B01111110 126 |
| | | #define B1111111 127 |
| | | #define B01111111 127 |
| | | #define B10000000 128 |
| | | #define B10000001 129 |
| | | #define B10000010 130 |
| | | #define B10000011 131 |
| | | #define B10000100 132 |
| | | #define B10000101 133 |
| | | #define B10000110 134 |
| | | #define B10000111 135 |
| | | #define B10001000 136 |
| | | #define B10001001 137 |
| | | #define B10001010 138 |
| | | #define B10001011 139 |
| | | #define B10001100 140 |
| | | #define B10001101 141 |
| | | #define B10001110 142 |
| | | #define B10001111 143 |
| | | #define B10010000 144 |
| | | #define B10010001 145 |
| | | #define B10010010 146 |
| | | #define B10010011 147 |
| | | #define B10010100 148 |
| | | #define B10010101 149 |
| | | #define B10010110 150 |
| | | #define B10010111 151 |
| | | #define B10011000 152 |
| | | #define B10011001 153 |
| | | #define B10011010 154 |
| | | #define B10011011 155 |
| | | #define B10011100 156 |
| | | #define B10011101 157 |
| | | #define B10011110 158 |
| | | #define B10011111 159 |
| | | #define B10100000 160 |
| | | #define B10100001 161 |
| | | #define B10100010 162 |
| | | #define B10100011 163 |
| | | #define B10100100 164 |
| | | #define B10100101 165 |
| | | #define B10100110 166 |
| | | #define B10100111 167 |
| | | #define B10101000 168 |
| | | #define B10101001 169 |
| | | #define B10101010 170 |
| | | #define B10101011 171 |
| | | #define B10101100 172 |
| | | #define B10101101 173 |
| | | #define B10101110 174 |
| | | #define B10101111 175 |
| | | #define B10110000 176 |
| | | #define B10110001 177 |
| | | #define B10110010 178 |
| | | #define B10110011 179 |
| | | #define B10110100 180 |
| | | #define B10110101 181 |
| | | #define B10110110 182 |
| | | #define B10110111 183 |
| | | #define B10111000 184 |
| | | #define B10111001 185 |
| | | #define B10111010 186 |
| | | #define B10111011 187 |
| | | #define B10111100 188 |
| | | #define B10111101 189 |
| | | #define B10111110 190 |
| | | #define B10111111 191 |
| | | #define B11000000 192 |
| | | #define B11000001 193 |
| | | #define B11000010 194 |
| | | #define B11000011 195 |
| | | #define B11000100 196 |
| | | #define B11000101 197 |
| | | #define B11000110 198 |
| | | #define B11000111 199 |
| | | #define B11001000 200 |
| | | #define B11001001 201 |
| | | #define B11001010 202 |
| | | #define B11001011 203 |
| | | #define B11001100 204 |
| | | #define B11001101 205 |
| | | #define B11001110 206 |
| | | #define B11001111 207 |
| | | #define B11010000 208 |
| | | #define B11010001 209 |
| | | #define B11010010 210 |
| | | #define B11010011 211 |
| | | #define B11010100 212 |
| | | #define B11010101 213 |
| | | #define B11010110 214 |
| | | #define B11010111 215 |
| | | #define B11011000 216 |
| | | #define B11011001 217 |
| | | #define B11011010 218 |
| | | #define B11011011 219 |
| | | #define B11011100 220 |
| | | #define B11011101 221 |
| | | #define B11011110 222 |
| | | #define B11011111 223 |
| | | #define B11100000 224 |
| | | #define B11100001 225 |
| | | #define B11100010 226 |
| | | #define B11100011 227 |
| | | #define B11100100 228 |
| | | #define B11100101 229 |
| | | #define B11100110 230 |
| | | #define B11100111 231 |
| | | #define B11101000 232 |
| | | #define B11101001 233 |
| | | #define B11101010 234 |
| | | #define B11101011 235 |
| | | #define B11101100 236 |
| | | #define B11101101 237 |
| | | #define B11101110 238 |
| | | #define B11101111 239 |
| | | #define B11110000 240 |
| | | #define B11110001 241 |
| | | #define B11110010 242 |
| | | #define B11110011 243 |
| | | #define B11110100 244 |
| | | #define B11110101 245 |
| | | #define B11110110 246 |
| | | #define B11110111 247 |
| | | #define B11111000 248 |
| | | #define B11111001 249 |
| | | #define B11111010 250 |
| | | #define B11111011 251 |
| | | #define B11111100 252 |
| | | #define B11111101 253 |
| | | #define B11111110 254 |
| | | #define B11111111 255 |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | cbuf.cpp - Circular buffer implementation |
| | | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #include "cbuf.h" |
| | | |
| | | cbuf::cbuf(size_t size) : |
| | | next(NULL), _size(size+1), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin) |
| | | { |
| | | } |
| | | |
| | | cbuf::~cbuf() |
| | | { |
| | | delete[] _buf; |
| | | } |
| | | |
| | | size_t cbuf::resizeAdd(size_t addSize) |
| | | { |
| | | return resize(_size + addSize); |
| | | } |
| | | |
| | | size_t cbuf::resize(size_t newSize) |
| | | { |
| | | |
| | | size_t bytes_available = available(); |
| | | newSize += 1; |
| | | // not lose any data |
| | | // if data can be lost use remove or flush before resize |
| | | if((newSize < bytes_available) || (newSize == _size)) { |
| | | return _size; |
| | | } |
| | | |
| | | char *newbuf = new char[newSize]; |
| | | char *oldbuf = _buf; |
| | | |
| | | if(!newbuf) { |
| | | return _size; |
| | | } |
| | | |
| | | if(_buf) { |
| | | read(newbuf, bytes_available); |
| | | memset((newbuf + bytes_available), 0x00, (newSize - bytes_available)); |
| | | } |
| | | |
| | | _begin = newbuf; |
| | | _end = newbuf + bytes_available; |
| | | _bufend = newbuf + newSize; |
| | | _size = newSize; |
| | | |
| | | _buf = newbuf; |
| | | delete[] oldbuf; |
| | | |
| | | return _size; |
| | | } |
| | | |
| | | size_t cbuf::available() const |
| | | { |
| | | if(_end >= _begin) { |
| | | return _end - _begin; |
| | | } |
| | | return _size - (_begin - _end); |
| | | } |
| | | |
| | | size_t cbuf::size() |
| | | { |
| | | return _size; |
| | | } |
| | | |
| | | size_t cbuf::room() const |
| | | { |
| | | if(_end >= _begin) { |
| | | return _size - (_end - _begin) - 1; |
| | | } |
| | | return _begin - _end - 1; |
| | | } |
| | | |
| | | int cbuf::peek() |
| | | { |
| | | if(empty()) { |
| | | return -1; |
| | | } |
| | | |
| | | return static_cast<int>(*_begin); |
| | | } |
| | | |
| | | size_t cbuf::peek(char *dst, size_t size) |
| | | { |
| | | size_t bytes_available = available(); |
| | | size_t size_to_read = (size < bytes_available) ? size : bytes_available; |
| | | size_t size_read = size_to_read; |
| | | char * begin = _begin; |
| | | if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { |
| | | size_t top_size = _bufend - _begin; |
| | | memcpy(dst, _begin, top_size); |
| | | begin = _buf; |
| | | size_to_read -= top_size; |
| | | dst += top_size; |
| | | } |
| | | memcpy(dst, begin, size_to_read); |
| | | return size_read; |
| | | } |
| | | |
| | | int cbuf::read() |
| | | { |
| | | if(empty()) { |
| | | return -1; |
| | | } |
| | | |
| | | char result = *_begin; |
| | | _begin = wrap_if_bufend(_begin + 1); |
| | | return static_cast<int>(result); |
| | | } |
| | | |
| | | size_t cbuf::read(char* dst, size_t size) |
| | | { |
| | | size_t bytes_available = available(); |
| | | size_t size_to_read = (size < bytes_available) ? size : bytes_available; |
| | | size_t size_read = size_to_read; |
| | | if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { |
| | | size_t top_size = _bufend - _begin; |
| | | memcpy(dst, _begin, top_size); |
| | | _begin = _buf; |
| | | size_to_read -= top_size; |
| | | dst += top_size; |
| | | } |
| | | memcpy(dst, _begin, size_to_read); |
| | | _begin = wrap_if_bufend(_begin + size_to_read); |
| | | return size_read; |
| | | } |
| | | |
| | | size_t cbuf::write(char c) |
| | | { |
| | | if(full()) { |
| | | return 0; |
| | | } |
| | | |
| | | *_end = c; |
| | | _end = wrap_if_bufend(_end + 1); |
| | | return 1; |
| | | } |
| | | |
| | | size_t cbuf::write(const char* src, size_t size) |
| | | { |
| | | size_t bytes_available = room(); |
| | | size_t size_to_write = (size < bytes_available) ? size : bytes_available; |
| | | size_t size_written = size_to_write; |
| | | if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) { |
| | | size_t top_size = _bufend - _end; |
| | | memcpy(_end, src, top_size); |
| | | _end = _buf; |
| | | size_to_write -= top_size; |
| | | src += top_size; |
| | | } |
| | | memcpy(_end, src, size_to_write); |
| | | _end = wrap_if_bufend(_end + size_to_write); |
| | | return size_written; |
| | | } |
| | | |
| | | void cbuf::flush() |
| | | { |
| | | _begin = _buf; |
| | | _end = _buf; |
| | | } |
| | | |
| | | size_t cbuf::remove(size_t size) |
| | | { |
| | | size_t bytes_available = available(); |
| | | if(size >= bytes_available) { |
| | | flush(); |
| | | return 0; |
| | | } |
| | | size_t size_to_remove = (size < bytes_available) ? size : bytes_available; |
| | | if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) { |
| | | size_t top_size = _bufend - _begin; |
| | | _begin = _buf; |
| | | size_to_remove -= top_size; |
| | | } |
| | | _begin = wrap_if_bufend(_begin + size_to_remove); |
| | | return available(); |
| | | } |
| New file |
| | |
| | | /* |
| | | cbuf.h - Circular buffer implementation |
| | | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef __cbuf_h |
| | | #define __cbuf_h |
| | | |
| | | #include <stddef.h> |
| | | #include <stdint.h> |
| | | #include <string.h> |
| | | |
| | | class cbuf |
| | | { |
| | | public: |
| | | cbuf(size_t size); |
| | | ~cbuf(); |
| | | |
| | | size_t resizeAdd(size_t addSize); |
| | | size_t resize(size_t newSize); |
| | | size_t available() const; |
| | | size_t size(); |
| | | |
| | | size_t room() const; |
| | | |
| | | inline bool empty() const |
| | | { |
| | | return _begin == _end; |
| | | } |
| | | |
| | | inline bool full() const |
| | | { |
| | | return wrap_if_bufend(_end + 1) == _begin; |
| | | } |
| | | |
| | | int peek(); |
| | | size_t peek(char *dst, size_t size); |
| | | |
| | | int read(); |
| | | size_t read(char* dst, size_t size); |
| | | |
| | | size_t write(char c); |
| | | size_t write(const char* src, size_t size); |
| | | |
| | | void flush(); |
| | | size_t remove(size_t size); |
| | | |
| | | cbuf *next; |
| | | |
| | | private: |
| | | inline char* wrap_if_bufend(char* ptr) const |
| | | { |
| | | return (ptr == _bufend) ? _buf : ptr; |
| | | } |
| | | |
| | | size_t _size; |
| | | char* _buf; |
| | | const char* _bufend; |
| | | char* _begin; |
| | | char* _end; |
| | | |
| | | }; |
| | | |
| | | #endif//__cbuf_h |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-adc.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "soc/rtc_io_reg.h" |
| | | #include "soc/rtc_cntl_reg.h" |
| | | #include "soc/sens_reg.h" |
| | | |
| | | static uint8_t __analogAttenuation = 3;//11db |
| | | static uint8_t __analogWidth = 3;//12 bits |
| | | static uint8_t __analogCycles = 8; |
| | | static uint8_t __analogSamples = 0;//1 sample |
| | | static uint8_t __analogClockDiv = 1; |
| | | |
| | | // Width of returned answer () |
| | | static uint8_t __analogReturnedWidth = 12; |
| | | |
| | | void __analogSetWidth(uint8_t bits){ |
| | | if(bits < 9){ |
| | | bits = 9; |
| | | } else if(bits > 12){ |
| | | bits = 12; |
| | | } |
| | | __analogReturnedWidth = bits; |
| | | __analogWidth = bits - 9; |
| | | SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, __analogWidth, SENS_SAR1_BIT_WIDTH_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, __analogWidth, SENS_SAR1_SAMPLE_BIT_S); |
| | | |
| | | SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, __analogWidth, SENS_SAR2_BIT_WIDTH_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, __analogWidth, SENS_SAR2_SAMPLE_BIT_S); |
| | | } |
| | | |
| | | void __analogSetCycles(uint8_t cycles){ |
| | | __analogCycles = cycles; |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_CYCLE, __analogCycles, SENS_SAR1_SAMPLE_CYCLE_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_CYCLE, __analogCycles, SENS_SAR2_SAMPLE_CYCLE_S); |
| | | } |
| | | |
| | | void __analogSetSamples(uint8_t samples){ |
| | | if(!samples){ |
| | | return; |
| | | } |
| | | __analogSamples = samples - 1; |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_NUM, __analogSamples, SENS_SAR1_SAMPLE_NUM_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_NUM, __analogSamples, SENS_SAR2_SAMPLE_NUM_S); |
| | | } |
| | | |
| | | void __analogSetClockDiv(uint8_t clockDiv){ |
| | | if(!clockDiv){ |
| | | return; |
| | | } |
| | | __analogClockDiv = clockDiv; |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_CLK_DIV, __analogClockDiv, SENS_SAR1_CLK_DIV_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_CLK_DIV, __analogClockDiv, SENS_SAR2_CLK_DIV_S); |
| | | } |
| | | |
| | | void __analogSetAttenuation(adc_attenuation_t attenuation) |
| | | { |
| | | __analogAttenuation = attenuation & 3; |
| | | uint32_t att_data = 0; |
| | | int i = 10; |
| | | while(i--){ |
| | | att_data |= __analogAttenuation << (i * 2); |
| | | } |
| | | WRITE_PERI_REG(SENS_SAR_ATTEN1_REG, att_data & 0xFFFF);//ADC1 has 8 channels |
| | | WRITE_PERI_REG(SENS_SAR_ATTEN2_REG, att_data); |
| | | } |
| | | |
| | | void IRAM_ATTR __analogInit(){ |
| | | static bool initialized = false; |
| | | if(initialized){ |
| | | return; |
| | | } |
| | | |
| | | __analogSetAttenuation(__analogAttenuation); |
| | | __analogSetCycles(__analogCycles); |
| | | __analogSetSamples(__analogSamples + 1);//in samples |
| | | __analogSetClockDiv(__analogClockDiv); |
| | | __analogSetWidth(__analogWidth + 9);//in bits |
| | | |
| | | SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV); |
| | | SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); |
| | | |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE_M); //SAR ADC1 controller (in RTC) is started by SW |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M); //SAR ADC1 pad enable bitmap is controlled by SW |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE_M); //SAR ADC2 controller (in RTC) is started by SW |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); //SAR ADC2 pad enable bitmap is controlled by SW |
| | | |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M); //force XPD_SAR=0, use XPD_FSM |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S); //force XPD_AMP=0 |
| | | |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_CTRL_REG, 0xfff << SENS_AMP_RST_FB_FSM_S); //clear FSM |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S); |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S); |
| | | while (GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S) != 0); //wait det_fsm== |
| | | |
| | | initialized = true; |
| | | } |
| | | |
| | | void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) |
| | | { |
| | | int8_t channel = digitalPinToAnalogChannel(pin); |
| | | if(channel < 0 || attenuation > 3){ |
| | | return ; |
| | | } |
| | | __analogInit(); |
| | | if(channel > 7){ |
| | | SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, 3, attenuation, ((channel - 10) * 2)); |
| | | } else { |
| | | SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, 3, attenuation, (channel * 2)); |
| | | } |
| | | } |
| | | |
| | | bool IRAM_ATTR __adcAttachPin(uint8_t pin){ |
| | | |
| | | int8_t channel = digitalPinToAnalogChannel(pin); |
| | | if(channel < 0){ |
| | | return false;//not adc pin |
| | | } |
| | | |
| | | int8_t pad = digitalPinToTouchChannel(pin); |
| | | if(pad >= 0){ |
| | | uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG); |
| | | if(touch & (1 << pad)){ |
| | | touch &= ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) |
| | | | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)) |
| | | | (1 << (pad + SENS_TOUCH_PAD_WORKEN_S))); |
| | | WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch); |
| | | } |
| | | } else if(pin == 25){ |
| | | CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1 |
| | | } else if(pin == 26){ |
| | | CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2 |
| | | } |
| | | |
| | | pinMode(pin, ANALOG); |
| | | |
| | | __analogInit(); |
| | | return true; |
| | | } |
| | | |
| | | bool IRAM_ATTR __adcStart(uint8_t pin){ |
| | | |
| | | int8_t channel = digitalPinToAnalogChannel(pin); |
| | | if(channel < 0){ |
| | | return false;//not adc pin |
| | | } |
| | | |
| | | if(channel > 9){ |
| | | channel -= 10; |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, (1 << channel), SENS_SAR2_EN_PAD_S); |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M); |
| | | } else { |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, (1 << channel), SENS_SAR1_EN_PAD_S); |
| | | SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | bool IRAM_ATTR __adcBusy(uint8_t pin){ |
| | | |
| | | int8_t channel = digitalPinToAnalogChannel(pin); |
| | | if(channel < 0){ |
| | | return false;//not adc pin |
| | | } |
| | | |
| | | if(channel > 7){ |
| | | return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0); |
| | | } |
| | | return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0); |
| | | } |
| | | |
| | | uint16_t IRAM_ATTR __adcEnd(uint8_t pin) |
| | | { |
| | | |
| | | uint16_t value = 0; |
| | | int8_t channel = digitalPinToAnalogChannel(pin); |
| | | if(channel < 0){ |
| | | return 0;//not adc pin |
| | | } |
| | | if(channel > 7){ |
| | | while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0); //wait for conversion |
| | | value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S); |
| | | } else { |
| | | while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0); //wait for conversion |
| | | value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S); |
| | | } |
| | | |
| | | // Shift result if necessary |
| | | uint8_t from = __analogWidth + 9; |
| | | if (from == __analogReturnedWidth) { |
| | | return value; |
| | | } |
| | | if (from > __analogReturnedWidth) { |
| | | return value >> (from - __analogReturnedWidth); |
| | | } |
| | | return value << (__analogReturnedWidth - from); |
| | | } |
| | | |
| | | uint16_t IRAM_ATTR __analogRead(uint8_t pin) |
| | | { |
| | | if(!__adcAttachPin(pin) || !__adcStart(pin)){ |
| | | return 0; |
| | | } |
| | | return __adcEnd(pin); |
| | | } |
| | | |
| | | void __analogReadResolution(uint8_t bits) |
| | | { |
| | | if(!bits || bits > 16){ |
| | | return; |
| | | } |
| | | __analogSetWidth(bits); // hadware from 9 to 12 |
| | | __analogReturnedWidth = bits; // software from 1 to 16 |
| | | } |
| | | |
| | | int __hallRead() //hall sensor without LNA |
| | | { |
| | | int Sens_Vp0; |
| | | int Sens_Vn0; |
| | | int Sens_Vp1; |
| | | int Sens_Vn1; |
| | | |
| | | pinMode(36, ANALOG); |
| | | pinMode(39, ANALOG); |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE_M); // hall sens force enable |
| | | SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_XPD_HALL); // xpd hall |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE_M); // phase force |
| | | CLEAR_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); // hall phase |
| | | Sens_Vp0 = __analogRead(36); |
| | | Sens_Vn0 = __analogRead(39); |
| | | SET_PERI_REG_MASK(RTC_IO_HALL_SENS_REG, RTC_IO_HALL_PHASE); |
| | | Sens_Vp1 = __analogRead(36); |
| | | Sens_Vn1 = __analogRead(39); |
| | | SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 0, SENS_FORCE_XPD_SAR_S); |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_XPD_HALL_FORCE); |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE); |
| | | return (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0); |
| | | } |
| | | |
| | | extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead"))); |
| | | extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution"))); |
| | | extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth"))); |
| | | extern void analogSetCycles(uint8_t cycles) __attribute__ ((weak, alias("__analogSetCycles"))); |
| | | extern void analogSetSamples(uint8_t samples) __attribute__ ((weak, alias("__analogSetSamples"))); |
| | | extern void analogSetClockDiv(uint8_t clockDiv) __attribute__ ((weak, alias("__analogSetClockDiv"))); |
| | | extern void analogSetAttenuation(adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetAttenuation"))); |
| | | extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetPinAttenuation"))); |
| | | extern int hallRead() __attribute__ ((weak, alias("__hallRead"))); |
| | | |
| | | extern bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin"))); |
| | | extern bool adcStart(uint8_t pin) __attribute__ ((weak, alias("__adcStart"))); |
| | | extern bool adcBusy(uint8_t pin) __attribute__ ((weak, alias("__adcBusy"))); |
| | | extern uint16_t adcEnd(uint8_t pin) __attribute__ ((weak, alias("__adcEnd"))); |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef MAIN_ESP32_HAL_ADC_H_ |
| | | #define MAIN_ESP32_HAL_ADC_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | |
| | | typedef enum { |
| | | ADC_0db, |
| | | ADC_2_5db, |
| | | ADC_6db, |
| | | ADC_11db |
| | | } adc_attenuation_t; |
| | | |
| | | /* |
| | | * Get ADC value for pin |
| | | * */ |
| | | uint16_t analogRead(uint8_t pin); |
| | | |
| | | /* |
| | | * Set the resolution of analogRead return values. Default is 12 bits (range from 0 to 4096). |
| | | * If between 9 and 12, it will equal the set hardware resolution, else value will be shifted. |
| | | * Range is 1 - 16 |
| | | * |
| | | * Note: compatibility with Arduino SAM |
| | | */ |
| | | void analogReadResolution(uint8_t bits); |
| | | |
| | | /* |
| | | * Sets the sample bits and read resolution |
| | | * Default is 12bit (0 - 4095) |
| | | * Range is 9 - 12 |
| | | * */ |
| | | void analogSetWidth(uint8_t bits); |
| | | |
| | | /* |
| | | * Set number of cycles per sample |
| | | * Default is 8 and seems to do well |
| | | * Range is 1 - 255 |
| | | * */ |
| | | void analogSetCycles(uint8_t cycles); |
| | | |
| | | /* |
| | | * Set number of samples in the range. |
| | | * Default is 1 |
| | | * Range is 1 - 255 |
| | | * This setting splits the range into |
| | | * "samples" pieces, which could look |
| | | * like the sensitivity has been multiplied |
| | | * that many times |
| | | * */ |
| | | void analogSetSamples(uint8_t samples); |
| | | |
| | | /* |
| | | * Set the divider for the ADC clock. |
| | | * Default is 1 |
| | | * Range is 1 - 255 |
| | | * */ |
| | | void analogSetClockDiv(uint8_t clockDiv); |
| | | |
| | | /* |
| | | * Set the attenuation for all channels |
| | | * Default is 11db |
| | | * */ |
| | | void analogSetAttenuation(adc_attenuation_t attenuation); |
| | | |
| | | /* |
| | | * Set the attenuation for particular pin |
| | | * Default is 11db |
| | | * */ |
| | | void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation); |
| | | |
| | | /* |
| | | * Get value for HALL sensor (without LNA) |
| | | * connected to pins 36(SVP) and 39(SVN) |
| | | * */ |
| | | int hallRead(); |
| | | |
| | | /* |
| | | * Non-Blocking API (almost) |
| | | * |
| | | * Note: ADC conversion can run only for single pin at a time. |
| | | * That means that if you want to run ADC on two pins on the same bus, |
| | | * you need to run them one after another. Probably the best use would be |
| | | * to start conversion on both buses in parallel. |
| | | * */ |
| | | |
| | | /* |
| | | * Attach pin to ADC (will also clear any other analog mode that could be on) |
| | | * */ |
| | | bool adcAttachPin(uint8_t pin); |
| | | |
| | | /* |
| | | * Start ADC conversion on attached pin's bus |
| | | * */ |
| | | bool adcStart(uint8_t pin); |
| | | |
| | | /* |
| | | * Check if conversion on the pin's ADC bus is currently running |
| | | * */ |
| | | bool adcBusy(uint8_t pin); |
| | | |
| | | /* |
| | | * Get the result of the conversion (will wait if it have not finished) |
| | | * */ |
| | | uint16_t adcEnd(uint8_t pin); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_ADC_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-bt.h" |
| | | |
| | | #ifdef CONFIG_BT_ENABLED |
| | | |
| | | bool btInUse(){ return true; } |
| | | |
| | | #ifdef CONFIG_BLUEDROID_ENABLED |
| | | #include "esp_bt.h" |
| | | |
| | | #ifdef CONFIG_CLASSIC_BT_ENABLED |
| | | #define BT_MODE ESP_BT_MODE_BTDM |
| | | #else |
| | | #define BT_MODE ESP_BT_MODE_BLE |
| | | #endif |
| | | |
| | | bool btStarted(){ |
| | | return (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED); |
| | | } |
| | | |
| | | bool btStart(){ |
| | | esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){ |
| | | return true; |
| | | } |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){ |
| | | esp_bt_controller_init(&cfg); |
| | | while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){} |
| | | } |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){ |
| | | if (esp_bt_controller_enable(BT_MODE)) { |
| | | log_e("BT Enable failed"); |
| | | return false; |
| | | } |
| | | } |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){ |
| | | return true; |
| | | } |
| | | log_e("BT Start failed"); |
| | | return false; |
| | | } |
| | | |
| | | bool btStop(){ |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE){ |
| | | return true; |
| | | } |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED){ |
| | | if (esp_bt_controller_disable()) { |
| | | log_e("BT Disable failed"); |
| | | return false; |
| | | } |
| | | while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED); |
| | | } |
| | | if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){ |
| | | return true; |
| | | } |
| | | log_e("BT Stop failed"); |
| | | return false; |
| | | } |
| | | |
| | | #else |
| | | bool btStarted() |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | bool btStart() |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | bool btStop() |
| | | { |
| | | return false; |
| | | } |
| | | #endif |
| | | #endif |
| | | |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_ESP32_HAL_BT_H_ |
| | | #define _ESP32_ESP32_HAL_BT_H_ |
| | | |
| | | #include "esp32-hal.h" |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | bool btStarted(); |
| | | bool btStart(); |
| | | bool btStop(); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_ESP32_HAL_BT_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "sdkconfig.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/semphr.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/xtensa_timer.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_log.h" |
| | | #include "soc/rtc.h" |
| | | #include "soc/rtc_cntl_reg.h" |
| | | #include "rom/rtc.h" |
| | | #include "soc/apb_ctrl_reg.h" |
| | | #include "esp32-hal.h" |
| | | #include "esp32-hal-cpu.h" |
| | | |
| | | typedef struct apb_change_cb_s { |
| | | struct apb_change_cb_s * next; |
| | | void * arg; |
| | | apb_change_cb_t cb; |
| | | } apb_change_t; |
| | | |
| | | const uint32_t MHZ = 1000000; |
| | | |
| | | static apb_change_t * apb_change_callbacks = NULL; |
| | | static xSemaphoreHandle apb_change_lock = NULL; |
| | | |
| | | static void initApbChangeCallback(){ |
| | | static volatile bool initialized = false; |
| | | if(!initialized){ |
| | | initialized = true; |
| | | apb_change_lock = xSemaphoreCreateMutex(); |
| | | if(!apb_change_lock){ |
| | | initialized = false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void triggerApbChangeCallback(apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
| | | initApbChangeCallback(); |
| | | xSemaphoreTake(apb_change_lock, portMAX_DELAY); |
| | | apb_change_t * r = apb_change_callbacks; |
| | | while(r != NULL){ |
| | | r->cb(r->arg, ev_type, old_apb, new_apb); |
| | | r=r->next; |
| | | } |
| | | xSemaphoreGive(apb_change_lock); |
| | | } |
| | | |
| | | bool addApbChangeCallback(void * arg, apb_change_cb_t cb){ |
| | | initApbChangeCallback(); |
| | | apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t)); |
| | | if(!c){ |
| | | log_e("Callback Object Malloc Failed"); |
| | | return false; |
| | | } |
| | | c->next = NULL; |
| | | c->arg = arg; |
| | | c->cb = cb; |
| | | xSemaphoreTake(apb_change_lock, portMAX_DELAY); |
| | | if(apb_change_callbacks == NULL){ |
| | | apb_change_callbacks = c; |
| | | } else { |
| | | apb_change_t * r = apb_change_callbacks; |
| | | if(r->cb != cb || r->arg != arg){ |
| | | while(r->next){ |
| | | r = r->next; |
| | | if(r->cb == cb && r->arg == arg){ |
| | | free(c); |
| | | goto unlock_and_exit; |
| | | } |
| | | } |
| | | r->next = c; |
| | | } |
| | | } |
| | | unlock_and_exit: |
| | | xSemaphoreGive(apb_change_lock); |
| | | return true; |
| | | } |
| | | |
| | | bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){ |
| | | initApbChangeCallback(); |
| | | xSemaphoreTake(apb_change_lock, portMAX_DELAY); |
| | | apb_change_t * r = apb_change_callbacks; |
| | | if(r == NULL){ |
| | | xSemaphoreGive(apb_change_lock); |
| | | return false; |
| | | } |
| | | if(r->cb == cb && r->arg == arg){ |
| | | apb_change_callbacks = r->next; |
| | | free(r); |
| | | } else { |
| | | while(r->next && (r->next->cb != cb || r->next->arg != arg)){ |
| | | r = r->next; |
| | | } |
| | | if(r->next == NULL || r->next->cb != cb || r->next->arg != arg){ |
| | | xSemaphoreGive(apb_change_lock); |
| | | return false; |
| | | } |
| | | apb_change_t * c = r->next; |
| | | r->next = c->next; |
| | | free(c); |
| | | } |
| | | xSemaphoreGive(apb_change_lock); |
| | | return true; |
| | | } |
| | | |
| | | static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){ |
| | | if(conf->freq_mhz >= 80){ |
| | | return 80 * MHZ; |
| | | } |
| | | return (conf->source_freq_mhz * MHZ) / conf->div; |
| | | } |
| | | |
| | | void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF |
| | | |
| | | bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){ |
| | | rtc_cpu_freq_config_t conf, cconf; |
| | | uint32_t capb, apb; |
| | | //Get XTAL Frequency and calculate min CPU MHz |
| | | rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get(); |
| | | if(xtal > RTC_XTAL_FREQ_AUTO){ |
| | | if(xtal < RTC_XTAL_FREQ_40M) { |
| | | if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){ |
| | | log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2); |
| | | return false; |
| | | } |
| | | } else if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2) && cpu_freq_mhz != (xtal/4)){ |
| | | log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4); |
| | | return false; |
| | | } |
| | | } |
| | | if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){ |
| | | if(xtal >= RTC_XTAL_FREQ_40M){ |
| | | log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4); |
| | | } else { |
| | | log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2); |
| | | } |
| | | return false; |
| | | } |
| | | //Get current CPU clock configuration |
| | | rtc_clk_cpu_freq_get_config(&cconf); |
| | | //return if frequency has not changed |
| | | if(cconf.freq_mhz == cpu_freq_mhz){ |
| | | return true; |
| | | } |
| | | //Get configuration for the new CPU frequency |
| | | if(!rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &conf)){ |
| | | log_e("CPU clock could not be set to %u MHz", cpu_freq_mhz); |
| | | return false; |
| | | } |
| | | //Current APB |
| | | capb = calculateApb(&cconf); |
| | | //New APB |
| | | apb = calculateApb(&conf); |
| | | log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_APLL)?"APLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"8M")), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb); |
| | | //Call peripheral functions before the APB change |
| | | if(apb_change_callbacks){ |
| | | triggerApbChangeCallback(APB_BEFORE_CHANGE, capb, apb); |
| | | } |
| | | //Make the frequency change |
| | | rtc_clk_cpu_freq_set_config_fast(&conf); |
| | | if(capb != apb){ |
| | | //Update REF_TICK (uncomment if REF_TICK is different than 1MHz) |
| | | //if(conf.freq_mhz < 80){ |
| | | // ESP_REG(APB_CTRL_XTAL_TICK_CONF_REG) = conf.freq_mhz / (REF_CLK_FREQ / MHZ) - 1; |
| | | //} |
| | | //Update APB Freq REG |
| | | rtc_clk_apb_freq_update(apb); |
| | | //Update esp_timer divisor |
| | | esp_timer_impl_update_apb_freq(apb / MHZ); |
| | | } |
| | | //Update FreeRTOS Tick Divisor |
| | | uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb); |
| | | _xt_tick_divisor = fcpu / XT_TICK_PER_SEC; |
| | | //Call peripheral functions after the APB change |
| | | if(apb_change_callbacks){ |
| | | triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | uint32_t getCpuFrequencyMhz(){ |
| | | rtc_cpu_freq_config_t conf; |
| | | rtc_clk_cpu_freq_get_config(&conf); |
| | | return conf.freq_mhz; |
| | | } |
| | | |
| | | uint32_t getXtalFrequencyMhz(){ |
| | | return rtc_clk_xtal_freq_get(); |
| | | } |
| | | |
| | | uint32_t getApbFrequency(){ |
| | | rtc_cpu_freq_config_t conf; |
| | | rtc_clk_cpu_freq_get_config(&conf); |
| | | return calculateApb(&conf); |
| | | } |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_HAL_CPU_H_ |
| | | #define _ESP32_HAL_CPU_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | #include <stdlib.h> |
| | | |
| | | typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t; |
| | | |
| | | typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb); |
| | | |
| | | bool addApbChangeCallback(void * arg, apb_change_cb_t cb); |
| | | bool removeApbChangeCallback(void * arg, apb_change_cb_t cb); |
| | | |
| | | //function takes the following frequencies as valid values: |
| | | // 240, 160, 80 <<< For all XTAL types |
| | | // 40, 20, 10 <<< For 40MHz XTAL |
| | | // 26, 13 <<< For 26MHz XTAL |
| | | // 24, 12 <<< For 24MHz XTAL |
| | | bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz); |
| | | |
| | | uint32_t getCpuFrequencyMhz(); // In MHz |
| | | uint32_t getXtalFrequencyMhz(); // In MHz |
| | | uint32_t getApbFrequency(); // In Hz |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_HAL_CPU_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-dac.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "soc/rtc_io_reg.h" |
| | | #include "soc/rtc_cntl_reg.h" |
| | | #include "soc/sens_reg.h" |
| | | |
| | | void IRAM_ATTR __dacWrite(uint8_t pin, uint8_t value) |
| | | { |
| | | if(pin < 25 || pin > 26){ |
| | | return;//not dac pin |
| | | } |
| | | pinMode(pin, ANALOG); |
| | | uint8_t channel = pin - 25; |
| | | |
| | | |
| | | //Disable Tone |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN); |
| | | |
| | | if (channel) { |
| | | //Disable Channel Tone |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M); |
| | | //Set the Dac value |
| | | SET_PERI_REG_BITS(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC, value, RTC_IO_PDAC2_DAC_S); //dac_output |
| | | //Channel output enable |
| | | SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE); |
| | | } else { |
| | | //Disable Channel Tone |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M); |
| | | //Set the Dac value |
| | | SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, value, RTC_IO_PDAC1_DAC_S); //dac_output |
| | | //Channel output enable |
| | | SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE); |
| | | } |
| | | } |
| | | |
| | | extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite"))); |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef MAIN_ESP32_HAL_DAC_H_ |
| | | #define MAIN_ESP32_HAL_DAC_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "driver/gpio.h" |
| | | |
| | | void dacWrite(uint8_t pin, uint8_t value); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_DAC_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-gpio.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "rom/gpio.h" |
| | | #include "soc/gpio_reg.h" |
| | | #include "soc/io_mux_reg.h" |
| | | #include "soc/gpio_struct.h" |
| | | #include "soc/rtc_io_reg.h" |
| | | |
| | | const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26}; |
| | | |
| | | const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[GPIO_PIN_COUNT]={ |
| | | {0x44, 11, 11, 1}, |
| | | {0x88, -1, -1, -1}, |
| | | {0x40, 12, 12, 2}, |
| | | {0x84, -1, -1, -1}, |
| | | {0x48, 10, 10, 0}, |
| | | {0x6c, -1, -1, -1}, |
| | | {0x60, -1, -1, -1}, |
| | | {0x64, -1, -1, -1}, |
| | | {0x68, -1, -1, -1}, |
| | | {0x54, -1, -1, -1}, |
| | | {0x58, -1, -1, -1}, |
| | | {0x5c, -1, -1, -1}, |
| | | {0x34, 15, 15, 5}, |
| | | {0x38, 14, 14, 4}, |
| | | {0x30, 16, 16, 6}, |
| | | {0x3c, 13, 13, 3}, |
| | | {0x4c, -1, -1, -1}, |
| | | {0x50, -1, -1, -1}, |
| | | {0x70, -1, -1, -1}, |
| | | {0x74, -1, -1, -1}, |
| | | {0x78, -1, -1, -1}, |
| | | {0x7c, -1, -1, -1}, |
| | | {0x80, -1, -1, -1}, |
| | | {0x8c, -1, -1, -1}, |
| | | {0, -1, -1, -1}, |
| | | {0x24, 6, 18, -1}, //DAC1 |
| | | {0x28, 7, 19, -1}, //DAC2 |
| | | {0x2c, 17, 17, 7}, |
| | | {0, -1, -1, -1}, |
| | | {0, -1, -1, -1}, |
| | | {0, -1, -1, -1}, |
| | | {0, -1, -1, -1}, |
| | | {0x1c, 9, 4, 9}, |
| | | {0x20, 8, 5, 8}, |
| | | {0x14, 4, 6, -1}, |
| | | {0x18, 5, 7, -1}, |
| | | {0x04, 0, 0, -1}, |
| | | {0x08, 1, 1, -1}, |
| | | {0x0c, 2, 2, -1}, |
| | | {0x10, 3, 3, -1} |
| | | }; |
| | | |
| | | typedef void (*voidFuncPtr)(void); |
| | | typedef void (*voidFuncPtrArg)(void*); |
| | | typedef struct { |
| | | voidFuncPtr fn; |
| | | void* arg; |
| | | bool functional; |
| | | } InterruptHandle_t; |
| | | static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,}; |
| | | |
| | | #include "driver/rtc_io.h" |
| | | |
| | | extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode) |
| | | { |
| | | |
| | | if(!digitalPinIsValid(pin)) { |
| | | return; |
| | | } |
| | | |
| | | uint32_t rtc_reg = rtc_gpio_desc[pin].reg; |
| | | if(mode == ANALOG) { |
| | | if(!rtc_reg) { |
| | | return;//not rtc pin |
| | | } |
| | | //lock rtc |
| | | uint32_t reg_val = ESP_REG(rtc_reg); |
| | | if(reg_val & rtc_gpio_desc[pin].mux){ |
| | | return;//already in adc mode |
| | | } |
| | | reg_val &= ~( |
| | | (RTC_IO_TOUCH_PAD1_FUN_SEL_V << rtc_gpio_desc[pin].func) |
| | | |rtc_gpio_desc[pin].ie |
| | | |rtc_gpio_desc[pin].pullup |
| | | |rtc_gpio_desc[pin].pulldown); |
| | | ESP_REG(RTC_GPIO_ENABLE_W1TC_REG) = (1 << (rtc_gpio_desc[pin].rtc_num + RTC_GPIO_ENABLE_W1TC_S)); |
| | | ESP_REG(rtc_reg) = reg_val | rtc_gpio_desc[pin].mux; |
| | | //unlock rtc |
| | | ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)2 << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE; |
| | | return; |
| | | } |
| | | |
| | | //RTC pins PULL settings |
| | | if(rtc_reg) { |
| | | //lock rtc |
| | | ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); |
| | | if(mode & PULLUP) { |
| | | ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown); |
| | | } else if(mode & PULLDOWN) { |
| | | ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup); |
| | | } else { |
| | | ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); |
| | | } |
| | | //unlock rtc |
| | | } |
| | | |
| | | uint32_t pinFunction = 0, pinControl = 0; |
| | | |
| | | //lock gpio |
| | | if(mode & INPUT) { |
| | | if(pin < 32) { |
| | | GPIO.enable_w1tc = ((uint32_t)1 << pin); |
| | | } else { |
| | | GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32)); |
| | | } |
| | | } else if(mode & OUTPUT) { |
| | | if(pin > 33){ |
| | | //unlock gpio |
| | | return;//pins above 33 can be only inputs |
| | | } else if(pin < 32) { |
| | | GPIO.enable_w1ts = ((uint32_t)1 << pin); |
| | | } else { |
| | | GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32)); |
| | | } |
| | | } |
| | | |
| | | if(mode & PULLUP) { |
| | | pinFunction |= FUN_PU; |
| | | } else if(mode & PULLDOWN) { |
| | | pinFunction |= FUN_PD; |
| | | } |
| | | |
| | | pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers? |
| | | pinFunction |= FUN_IE;//input enable but required for output as well? |
| | | |
| | | if(mode & (INPUT | OUTPUT)) { |
| | | pinFunction |= ((uint32_t)2 << MCU_SEL_S); |
| | | } else if(mode == SPECIAL) { |
| | | pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S); |
| | | } else { |
| | | pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S); |
| | | } |
| | | |
| | | ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = pinFunction; |
| | | |
| | | if(mode & OPEN_DRAIN) { |
| | | pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S); |
| | | } |
| | | |
| | | GPIO.pin[pin].val = pinControl; |
| | | //unlock gpio |
| | | } |
| | | |
| | | extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) |
| | | { |
| | | if(val) { |
| | | if(pin < 32) { |
| | | GPIO.out_w1ts = ((uint32_t)1 << pin); |
| | | } else if(pin < 34) { |
| | | GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32)); |
| | | } |
| | | } else { |
| | | if(pin < 32) { |
| | | GPIO.out_w1tc = ((uint32_t)1 << pin); |
| | | } else if(pin < 34) { |
| | | GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | extern int IRAM_ATTR __digitalRead(uint8_t pin) |
| | | { |
| | | if(pin < 32) { |
| | | return (GPIO.in >> pin) & 0x1; |
| | | } else if(pin < 40) { |
| | | return (GPIO.in1.val >> (pin - 32)) & 0x1; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static intr_handle_t gpio_intr_handle = NULL; |
| | | |
| | | static void IRAM_ATTR __onPinInterrupt() |
| | | { |
| | | uint32_t gpio_intr_status_l=0; |
| | | uint32_t gpio_intr_status_h=0; |
| | | |
| | | gpio_intr_status_l = GPIO.status; |
| | | gpio_intr_status_h = GPIO.status1.val; |
| | | GPIO.status_w1tc = gpio_intr_status_l;//Clear intr for gpio0-gpio31 |
| | | GPIO.status1_w1tc.val = gpio_intr_status_h;//Clear intr for gpio32-39 |
| | | |
| | | uint8_t pin=0; |
| | | if(gpio_intr_status_l) { |
| | | do { |
| | | if(gpio_intr_status_l & ((uint32_t)1 << pin)) { |
| | | if(__pinInterruptHandlers[pin].fn) { |
| | | if(__pinInterruptHandlers[pin].arg){ |
| | | ((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg); |
| | | } else { |
| | | __pinInterruptHandlers[pin].fn(); |
| | | } |
| | | } |
| | | } |
| | | } while(++pin<32); |
| | | } |
| | | if(gpio_intr_status_h) { |
| | | pin=32; |
| | | do { |
| | | if(gpio_intr_status_h & ((uint32_t)1 << (pin - 32))) { |
| | | if(__pinInterruptHandlers[pin].fn) { |
| | | if(__pinInterruptHandlers[pin].arg){ |
| | | ((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg); |
| | | } else { |
| | | __pinInterruptHandlers[pin].fn(); |
| | | } |
| | | } |
| | | } |
| | | } while(++pin<GPIO_PIN_COUNT); |
| | | } |
| | | } |
| | | |
| | | extern void cleanupFunctional(void* arg); |
| | | |
| | | extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional) |
| | | { |
| | | static bool interrupt_initialized = false; |
| | | |
| | | if(!interrupt_initialized) { |
| | | interrupt_initialized = true; |
| | | esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle); |
| | | } |
| | | |
| | | // if new attach without detach remove old info |
| | | if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) |
| | | { |
| | | cleanupFunctional(__pinInterruptHandlers[pin].arg); |
| | | } |
| | | __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; |
| | | __pinInterruptHandlers[pin].arg = arg; |
| | | __pinInterruptHandlers[pin].functional = functional; |
| | | |
| | | esp_intr_disable(gpio_intr_handle); |
| | | if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU |
| | | GPIO.pin[pin].int_ena = 1; |
| | | } else { //PRO_CPU |
| | | GPIO.pin[pin].int_ena = 4; |
| | | } |
| | | GPIO.pin[pin].int_type = intr_type; |
| | | esp_intr_enable(gpio_intr_handle); |
| | | } |
| | | |
| | | extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type) |
| | | { |
| | | __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); |
| | | } |
| | | |
| | | extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) { |
| | | __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); |
| | | } |
| | | |
| | | extern void __detachInterrupt(uint8_t pin) |
| | | { |
| | | esp_intr_disable(gpio_intr_handle); |
| | | if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) |
| | | { |
| | | cleanupFunctional(__pinInterruptHandlers[pin].arg); |
| | | } |
| | | __pinInterruptHandlers[pin].fn = NULL; |
| | | __pinInterruptHandlers[pin].arg = NULL; |
| | | __pinInterruptHandlers[pin].functional = false; |
| | | |
| | | GPIO.pin[pin].int_ena = 0; |
| | | GPIO.pin[pin].int_type = 0; |
| | | esp_intr_enable(gpio_intr_handle); |
| | | } |
| | | |
| | | |
| | | extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); |
| | | extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); |
| | | extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"))); |
| | | extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); |
| | | extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); |
| | | extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); |
| | | |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef MAIN_ESP32_HAL_GPIO_H_ |
| | | #define MAIN_ESP32_HAL_GPIO_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | |
| | | #define LOW 0x0 |
| | | #define HIGH 0x1 |
| | | |
| | | //GPIO FUNCTIONS |
| | | #define INPUT 0x01 |
| | | #define OUTPUT 0x02 |
| | | #define PULLUP 0x04 |
| | | #define INPUT_PULLUP 0x05 |
| | | #define PULLDOWN 0x08 |
| | | #define INPUT_PULLDOWN 0x09 |
| | | #define OPEN_DRAIN 0x10 |
| | | #define OUTPUT_OPEN_DRAIN 0x12 |
| | | #define SPECIAL 0xF0 |
| | | #define FUNCTION_1 0x00 |
| | | #define FUNCTION_2 0x20 |
| | | #define FUNCTION_3 0x40 |
| | | #define FUNCTION_4 0x60 |
| | | #define FUNCTION_5 0x80 |
| | | #define FUNCTION_6 0xA0 |
| | | #define ANALOG 0xC0 |
| | | |
| | | //Interrupt Modes |
| | | #define DISABLED 0x00 |
| | | #define RISING 0x01 |
| | | #define FALLING 0x02 |
| | | #define CHANGE 0x03 |
| | | #define ONLOW 0x04 |
| | | #define ONHIGH 0x05 |
| | | #define ONLOW_WE 0x0C |
| | | #define ONHIGH_WE 0x0D |
| | | |
| | | typedef struct { |
| | | uint8_t reg; /*!< GPIO register offset from DR_REG_IO_MUX_BASE */ |
| | | int8_t rtc; /*!< RTC GPIO number (-1 if not RTC GPIO pin) */ |
| | | int8_t adc; /*!< ADC Channel number (-1 if not ADC pin) */ |
| | | int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */ |
| | | } esp32_gpioMux_t; |
| | | |
| | | extern const esp32_gpioMux_t esp32_gpioMux[40]; |
| | | extern const int8_t esp32_adc2gpio[20]; |
| | | |
| | | #define digitalPinIsValid(pin) ((pin) < 40 && esp32_gpioMux[(pin)].reg) |
| | | #define digitalPinCanOutput(pin) ((pin) < 34 && esp32_gpioMux[(pin)].reg) |
| | | #define digitalPinToRtcPin(pin) (((pin) < 40)?esp32_gpioMux[(pin)].rtc:-1) |
| | | #define digitalPinToAnalogChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].adc:-1) |
| | | #define digitalPinToTouchChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].touch:-1) |
| | | #define digitalPinToDacChannel(pin) (((pin) == 25)?0:((pin) == 26)?1:-1) |
| | | |
| | | void pinMode(uint8_t pin, uint8_t mode); |
| | | void digitalWrite(uint8_t pin, uint8_t val); |
| | | int digitalRead(uint8_t pin); |
| | | |
| | | void attachInterrupt(uint8_t pin, void (*)(void), int mode); |
| | | void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); |
| | | void detachInterrupt(uint8_t pin); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_GPIO_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-i2c.h" |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/semphr.h" |
| | | #include "freertos/event_groups.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "driver/periph_ctrl.h" |
| | | #include "soc/i2c_reg.h" |
| | | #include "soc/i2c_struct.h" |
| | | #include "soc/dport_reg.h" |
| | | #include "esp_attr.h" |
| | | #include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018 |
| | | //#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE) |
| | | //#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i))) |
| | | #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)) |
| | | |
| | | #define DR_REG_I2C_EXT_BASE_FIXED 0x60013000 |
| | | #define DR_REG_I2C1_EXT_BASE_FIXED 0x60027000 |
| | | |
| | | /* Stickbreaker ISR mode debug support |
| | | |
| | | ENABLE_I2C_DEBUG_BUFFER |
| | | Enable debug interrupt history buffer, fifoTx history buffer. |
| | | Setting this define will result in 2570 bytes of RAM being used whenever CORE_DEBUG_LEVEL |
| | | is higher than WARNING. Unless you are debugging a problem in the I2C subsystem, |
| | | I would recommend you leave it commented out. |
| | | */ |
| | | |
| | | //#define ENABLE_I2C_DEBUG_BUFFER |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | #define INTBUFFMAX 64 |
| | | #define FIFOMAX 512 |
| | | static uint32_t intBuff[INTBUFFMAX][3][2]; |
| | | static uint32_t intPos[2]= {0,0}; |
| | | static uint16_t fifoBuffer[FIFOMAX]; |
| | | static uint16_t fifoPos = 0; |
| | | #endif |
| | | |
| | | // start from tools/sdk/include/soc/soc/i2c_struct.h |
| | | |
| | | typedef union { |
| | | struct { |
| | | uint32_t byte_num: 8; /*Byte_num represent the number of data need to be send or data need to be received.*/ |
| | | uint32_t ack_en: 1; /*ack_check_en ack_exp and ack value are used to control the ack bit.*/ |
| | | uint32_t ack_exp: 1; /*ack_check_en ack_exp and ack value are used to control the ack bit.*/ |
| | | uint32_t ack_val: 1; /*ack_check_en ack_exp and ack value are used to control the ack bit.*/ |
| | | uint32_t op_code: 3; /*op_code is the command 0:RSTART 1:WRITE 2:READ 3:STOP . 4:END.*/ |
| | | uint32_t reserved14: 17; |
| | | uint32_t done: 1; /*When command0 is done in I2C Master mode this bit changes to high level.*/ |
| | | }; |
| | | uint32_t val; |
| | | } I2C_COMMAND_t; |
| | | |
| | | typedef union { |
| | | struct { |
| | | uint32_t rx_fifo_full_thrhd: 5; |
| | | uint32_t tx_fifo_empty_thrhd:5; //Config tx_fifo empty threhd value when using apb fifo access * / |
| | | uint32_t nonfifo_en: 1; //Set this bit to enble apb nonfifo access. * / |
| | | uint32_t fifo_addr_cfg_en: 1; //When this bit is set to 1 then the byte after address represent the offset address of I2C Slave's ram. * / |
| | | uint32_t rx_fifo_rst: 1; //Set this bit to reset rx fifo when using apb fifo access. * / |
| | | // chuck while this bit is 1, the RX fifo is held in REST, Toggle it * / |
| | | uint32_t tx_fifo_rst: 1; //Set this bit to reset tx fifo when using apb fifo access. * / |
| | | // chuck while this bit is 1, the TX fifo is held in REST, Toggle it * / |
| | | uint32_t nonfifo_rx_thres: 6; //when I2C receives more than nonfifo_rx_thres data it will produce rx_send_full_int_raw interrupt and update the current offset address of the receiving data.* / |
| | | uint32_t nonfifo_tx_thres: 6; //when I2C sends more than nonfifo_tx_thres data it will produce tx_send_empty_int_raw interrupt and update the current offset address of the sending data. * / |
| | | uint32_t reserved26: 6; |
| | | }; |
| | | uint32_t val; |
| | | } I2C_FIFO_CONF_t; |
| | | |
| | | typedef union { |
| | | struct { |
| | | uint32_t rx_fifo_start_addr: 5; /*This is the offset address of the last receiving data as described in nonfifo_rx_thres_register.*/ |
| | | uint32_t rx_fifo_end_addr: 5; /*This is the offset address of the first receiving data as described in nonfifo_rx_thres_register.*/ |
| | | uint32_t tx_fifo_start_addr: 5; /*This is the offset address of the first sending data as described in nonfifo_tx_thres register.*/ |
| | | uint32_t tx_fifo_end_addr: 5; /*This is the offset address of the last sending data as described in nonfifo_tx_thres register.*/ |
| | | uint32_t reserved20: 12; |
| | | }; |
| | | uint32_t val; |
| | | } I2C_FIFO_ST_t; |
| | | |
| | | // end from tools/sdk/include/soc/soc/i2c_struct.h |
| | | |
| | | // sync between dispatch(i2cProcQueue) and worker(i2c_isr_handler_default) |
| | | typedef enum { |
| | | //I2C_NONE=0, |
| | | I2C_STARTUP=1, |
| | | I2C_RUNNING, |
| | | I2C_DONE |
| | | } I2C_STAGE_t; |
| | | |
| | | typedef enum { |
| | | I2C_NONE=0, |
| | | I2C_MASTER, |
| | | I2C_SLAVE, |
| | | I2C_MASTERSLAVE |
| | | } I2C_MODE_t; |
| | | |
| | | // internal Error condition |
| | | typedef enum { |
| | | // I2C_NONE=0, |
| | | I2C_OK=1, |
| | | I2C_ERROR, |
| | | I2C_ADDR_NAK, |
| | | I2C_DATA_NAK, |
| | | I2C_ARBITRATION, |
| | | I2C_TIMEOUT |
| | | } I2C_ERROR_t; |
| | | |
| | | // i2c_event bits for EVENTGROUP bits |
| | | // needed to minimize change events, FreeRTOS Daemon overload, so ISR will only set values |
| | | // on Exit. Dispatcher will set bits for each dq before/after ISR completion |
| | | #define EVENT_ERROR_NAK (BIT(0)) |
| | | #define EVENT_ERROR (BIT(1)) |
| | | #define EVENT_ERROR_BUS_BUSY (BIT(2)) |
| | | #define EVENT_RUNNING (BIT(3)) |
| | | #define EVENT_DONE (BIT(4)) |
| | | #define EVENT_IN_END (BIT(5)) |
| | | #define EVENT_ERROR_PREV (BIT(6)) |
| | | #define EVENT_ERROR_TIMEOUT (BIT(7)) |
| | | #define EVENT_ERROR_ARBITRATION (BIT(8)) |
| | | #define EVENT_ERROR_DATA_NAK (BIT(9)) |
| | | #define EVENT_MASK 0x3F |
| | | |
| | | // control record for each dq entry |
| | | typedef union { |
| | | struct { |
| | | uint32_t addr: 16; // I2C address, if 10bit must have 0x7800 mask applied, else 8bit |
| | | uint32_t mode: 1; // transaction direction 0 write, 1 read |
| | | uint32_t stop: 1; // sendStop 0 no, 1 yes |
| | | uint32_t startCmdSent: 1; // START cmd has been added to command[] |
| | | uint32_t addrCmdSent: 1; // addr WRITE cmd has been added to command[] |
| | | uint32_t dataCmdSent: 1; // all necessary DATA(READ/WRITE) cmds added to command[] |
| | | uint32_t stopCmdSent: 1; // completed all necessary commands |
| | | uint32_t addrReq: 2; // number of addr bytes need to send address |
| | | uint32_t addrSent: 2; // number of addr bytes added to FIFO |
| | | uint32_t reserved_31: 6; |
| | | }; |
| | | uint32_t val; |
| | | } I2C_DATA_CTRL_t; |
| | | |
| | | // individual dq element |
| | | typedef struct { |
| | | uint8_t *data; // data pointer for read/write buffer |
| | | uint16_t length; // size of data buffer |
| | | uint16_t position; // current position for next char in buffer (<length) |
| | | uint16_t cmdBytesNeeded; // used to control number of I2C_COMMAND_t blocks added to queue |
| | | I2C_DATA_CTRL_t ctrl; |
| | | EventGroupHandle_t queueEvent; // optional user supplied for Async feedback EventBits |
| | | } I2C_DATA_QUEUE_t; |
| | | |
| | | struct i2c_struct_t { |
| | | i2c_dev_t * dev; |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | xSemaphoreHandle lock; |
| | | #endif |
| | | uint8_t num; |
| | | int8_t sda; |
| | | int8_t scl; |
| | | I2C_MODE_t mode; |
| | | I2C_STAGE_t stage; |
| | | I2C_ERROR_t error; |
| | | EventGroupHandle_t i2c_event; // a way to monitor ISR process |
| | | // maybe use it to trigger callback for OnRequest() |
| | | intr_handle_t intr_handle; /*!< I2C interrupt handle*/ |
| | | I2C_DATA_QUEUE_t * dq; |
| | | uint16_t queueCount; // number of dq entries in queue. |
| | | uint16_t queuePos; // current queue that still has or needs data (out/in) |
| | | int16_t errorByteCnt; // byte pos where error happened, -1 devId, 0..(length-1) data |
| | | uint16_t errorQueue; // errorByteCnt is in this queue,(for error locus) |
| | | uint32_t exitCode; |
| | | uint32_t debugFlags; |
| | | }; |
| | | |
| | | enum { |
| | | I2C_CMD_RSTART, |
| | | I2C_CMD_WRITE, |
| | | I2C_CMD_READ, |
| | | I2C_CMD_STOP, |
| | | I2C_CMD_END |
| | | }; |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | #define I2C_MUTEX_LOCK() |
| | | #define I2C_MUTEX_UNLOCK() |
| | | |
| | | static i2c_t _i2c_bus_array[2] = { |
| | | {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), 0, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0}, |
| | | {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0} |
| | | }; |
| | | #else |
| | | #define I2C_MUTEX_LOCK() do {} while (xSemaphoreTakeRecursive(i2c->lock, portMAX_DELAY) != pdPASS) |
| | | #define I2C_MUTEX_UNLOCK() xSemaphoreGiveRecursive(i2c->lock) |
| | | |
| | | static i2c_t _i2c_bus_array[2] = { |
| | | {(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0, -1, -1, I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0,0}, |
| | | {(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), NULL, 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0,0} |
| | | }; |
| | | #endif |
| | | |
| | | /* |
| | | * index - command index (0 to 15) |
| | | * op_code - is the command |
| | | * byte_num - This register is to store the amounts of data that is read and written. byte_num in RSTART, STOP, END is null. |
| | | * ack_val - Each data byte is terminated by an ACK bit used to set the bit level. |
| | | * ack_exp - This bit is to set an expected ACK value for the transmitter. |
| | | * ack_check - This bit is to decide whether the transmitter checks ACK bit. 1 means yes and 0 means no. |
| | | * */ |
| | | |
| | | |
| | | /* Stickbreaker ISR mode debug support |
| | | */ |
| | | static void IRAM_ATTR i2cDumpCmdQueue(i2c_t *i2c) |
| | | { |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR)&&(defined ENABLE_I2C_DEBUG_BUFFER) |
| | | static const char * const cmdName[] ={"RSTART","WRITE","READ","STOP","END"}; |
| | | uint8_t i=0; |
| | | while(i<16) { |
| | | I2C_COMMAND_t c; |
| | | c.val=i2c->dev->command[i].val; |
| | | log_e("[%2d]\t%c\t%s\tval[%d]\texp[%d]\ten[%d]\tbytes[%d]",i,(c.done?'Y':'N'), |
| | | cmdName[c.op_code], |
| | | c.ack_val, |
| | | c.ack_exp, |
| | | c.ack_en, |
| | | c.byte_num); |
| | | i++; |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | /* Stickbreaker ISR mode debug support |
| | | */ |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) |
| | | static void i2cDumpDqData(i2c_t * i2c) |
| | | { |
| | | #if defined (ENABLE_I2C_DEBUG_BUFFER) |
| | | uint16_t a=0; |
| | | char buff[140]; |
| | | I2C_DATA_QUEUE_t *tdq; |
| | | int digits=0,lenDigits=0; |
| | | a = i2c->queueCount; |
| | | while(a>0) { |
| | | digits++; |
| | | a /= 10; |
| | | } |
| | | while(a<i2c->queueCount) { // find maximum number of len decimal digits for formatting |
| | | if (i2c->dq[a].length > lenDigits ) lenDigits = i2c->dq[a].length; |
| | | a++; |
| | | } |
| | | a=0; |
| | | while(lenDigits>0){ |
| | | a++; |
| | | lenDigits /= 10; |
| | | } |
| | | lenDigits = a; |
| | | a = 0; |
| | | while(a<i2c->queueCount) { |
| | | tdq=&i2c->dq[a]; |
| | | char buf1[10],buf2[10]; |
| | | sprintf(buf1,"%0*d",lenDigits,tdq->length); |
| | | sprintf(buf2,"%0*d",lenDigits,tdq->position); |
| | | log_i("[%0*d] %sbit %x %c %s buf@=%p, len=%s, pos=%s, ctrl=%d%d%d%d%d",digits,a, |
| | | (tdq->ctrl.addr>0x100)?"10":"7", |
| | | (tdq->ctrl.addr>0x100)?(((tdq->ctrl.addr&0x600)>>1)|(tdq->ctrl.addr&0xff)):(tdq->ctrl.addr>>1), |
| | | (tdq->ctrl.mode)?'R':'W', |
| | | (tdq->ctrl.stop)?"STOP":"", |
| | | tdq->data, |
| | | buf1,buf2, |
| | | tdq->ctrl.startCmdSent,tdq->ctrl.addrCmdSent,tdq->ctrl.dataCmdSent,(tdq->ctrl.stop)?tdq->ctrl.stopCmdSent:0,tdq->ctrl.addrSent |
| | | ); |
| | | uint16_t offset = 0; |
| | | while(offset<tdq->length) { |
| | | memset(buff,' ',140); |
| | | buff[139]='\0'; |
| | | uint16_t i = 0,j; |
| | | j=sprintf(buff,"0x%04x: ",offset); |
| | | while((i<32)&&(offset < tdq->length)) { |
| | | char ch = tdq->data[offset]; |
| | | sprintf((char*)&buff[(i*3)+41],"%02x ",ch); |
| | | if((ch<32)||(ch>126)) { |
| | | ch='.'; |
| | | } |
| | | j+=sprintf((char*)&buff[j],"%c",ch); |
| | | buff[j]=' '; |
| | | i++; |
| | | offset++; |
| | | } |
| | | log_i("%s",buff); |
| | | } |
| | | a++; |
| | | } |
| | | #else |
| | | log_i("Debug Buffer not Enabled"); |
| | | #endif |
| | | } |
| | | #endif |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO |
| | | static void i2cDumpI2c(i2c_t * i2c) |
| | | { |
| | | log_e("i2c=%p",i2c); |
| | | log_i("dev=%p date=%p",i2c->dev,i2c->dev->date); |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | log_i("lock=%p",i2c->lock); |
| | | #endif |
| | | log_i("num=%d",i2c->num); |
| | | log_i("mode=%d",i2c->mode); |
| | | log_i("stage=%d",i2c->stage); |
| | | log_i("error=%d",i2c->error); |
| | | log_i("event=%p bits=%x",i2c->i2c_event,(i2c->i2c_event)?xEventGroupGetBits(i2c->i2c_event):0); |
| | | log_i("intr_handle=%p",i2c->intr_handle); |
| | | log_i("dq=%p",i2c->dq); |
| | | log_i("queueCount=%d",i2c->queueCount); |
| | | log_i("queuePos=%d",i2c->queuePos); |
| | | log_i("errorByteCnt=%d",i2c->errorByteCnt); |
| | | log_i("errorQueue=%d",i2c->errorQueue); |
| | | log_i("debugFlags=0x%08X",i2c->debugFlags); |
| | | if(i2c->dq) { |
| | | i2cDumpDqData(i2c); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) |
| | | static void i2cDumpInts(uint8_t num) |
| | | { |
| | | #if defined (ENABLE_I2C_DEBUG_BUFFER) |
| | | uint32_t b; |
| | | log_i("%u row\tcount\tINTR\tTX\tRX\tTick ",num); |
| | | for(uint32_t a=1; a<=INTBUFFMAX; a++) { |
| | | b=(a+intPos[num])%INTBUFFMAX; |
| | | if(intBuff[b][0][num]!=0) { |
| | | log_i("[%02d]\t0x%04x\t0x%04x\t0x%04x\t0x%04x\t0x%08x",b,((intBuff[b][0][num]>>16)&0xFFFF),(intBuff[b][0][num]&0xFFFF),((intBuff[b][1][num]>>16)&0xFFFF),(intBuff[b][1][num]&0xFFFF),intBuff[b][2][num]); |
| | | } |
| | | } |
| | | #else |
| | | log_i("Debug Buffer not Enabled"); |
| | | #endif |
| | | } |
| | | #endif |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER) |
| | | static void IRAM_ATTR i2cDumpStatus(i2c_t * i2c){ |
| | | typedef union { |
| | | struct { |
| | | uint32_t ack_rec: 1; /*This register stores the value of ACK bit.*/ |
| | | uint32_t slave_rw: 1; /*when in slave mode 1:master read slave 0: master write slave.*/ |
| | | uint32_t time_out: 1; /*when I2C takes more than time_out_reg clocks to receive a data then this register changes to high level.*/ |
| | | uint32_t arb_lost: 1; /*when I2C lost control of SDA line this register changes to high level.*/ |
| | | uint32_t bus_busy: 1; /*1:I2C bus is busy transferring data. 0:I2C bus is in idle state.*/ |
| | | uint32_t slave_addressed: 1; /*when configured as i2c slave and the address send by master is equal to slave's address then this bit will be high level.*/ |
| | | uint32_t byte_trans: 1; /*This register changes to high level when one byte is transferred.*/ |
| | | uint32_t reserved7: 1; |
| | | uint32_t rx_fifo_cnt: 6; /*This register represent the amount of data need to send.*/ |
| | | uint32_t reserved14: 4; |
| | | uint32_t tx_fifo_cnt: 6; /*This register stores the amount of received data in ram.*/ |
| | | uint32_t scl_main_state_last: 3; /*This register stores the value of state machine for i2c module. 3'h0: SCL_MAIN_IDLE 3'h1: SCL_ADDRESS_SHIFT 3'h2: SCL_ACK_ADDRESS 3'h3: SCL_RX_DATA 3'h4 SCL_TX_DATA 3'h5:SCL_SEND_ACK 3'h6:SCL_WAIT_ACK*/ |
| | | uint32_t reserved27: 1; |
| | | uint32_t scl_state_last: 3; /*This register stores the value of state machine to produce SCL. 3'h0: SCL_IDLE 3'h1:SCL_START 3'h2:SCL_LOW_EDGE 3'h3: SCL_LOW 3'h4:SCL_HIGH_EDGE 3'h5:SCL_HIGH 3'h6:SCL_STOP*/ |
| | | uint32_t reserved31: 1; |
| | | }; |
| | | uint32_t val; |
| | | } status_reg; |
| | | |
| | | status_reg sr; |
| | | sr.val= i2c->dev->status_reg.val; |
| | | |
| | | log_i("ack(%d) sl_rw(%d) to(%d) arb(%d) busy(%d) sl(%d) trans(%d) rx(%d) tx(%d) sclMain(%d) scl(%d)",sr.ack_rec,sr.slave_rw,sr.time_out,sr.arb_lost,sr.bus_busy,sr.slave_addressed,sr.byte_trans, sr.rx_fifo_cnt, sr.tx_fifo_cnt,sr.scl_main_state_last, sr.scl_state_last); |
| | | } |
| | | #endif |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER) |
| | | static void i2cDumpFifo(i2c_t * i2c){ |
| | | char buf[64]; |
| | | uint16_t k = 0; |
| | | uint16_t i = fifoPos+1; |
| | | i %=FIFOMAX; |
| | | while((fifoBuffer[i]==0)&&(i!=fifoPos)){ |
| | | i++; |
| | | i %=FIFOMAX; |
| | | } |
| | | if(i != fifoPos){// actual data |
| | | do{ |
| | | if(fifoBuffer[i] & 0x8000){ // address byte |
| | | if(fifoBuffer[i] & 0x100) { // read |
| | | if(fifoBuffer[i] & 0x1) { // valid read dev id |
| | | k+= sprintf(&buf[k],"READ 0x%02X",(fifoBuffer[i]&0xff)>>1); |
| | | } else { // invalid read dev id |
| | | k+= sprintf(&buf[k],"Bad READ 0x%02X",(fifoBuffer[i]&0xff)); |
| | | } |
| | | } else { // write |
| | | if(fifoBuffer[i] & 0x1) { // bad write dev id |
| | | k+= sprintf(&buf[k],"bad WRITE 0x%02X",(fifoBuffer[i]&0xff)); |
| | | } else { // good Write |
| | | k+= sprintf(&buf[k],"WRITE 0x%02X",(fifoBuffer[i]&0xff)>>1); |
| | | } |
| | | } |
| | | } else k += sprintf(&buf[k],"% 4X ",fifoBuffer[i]); |
| | | |
| | | i++; |
| | | i %= FIFOMAX; |
| | | bool outBuffer=false; |
| | | if( fifoBuffer[i] & 0x8000){ |
| | | outBuffer=true; |
| | | k=0; |
| | | } |
| | | if((outBuffer)||(k>50)||(i==fifoPos)) log_i("%s",buf); |
| | | outBuffer = false; |
| | | if(k>50) { |
| | | k=sprintf(buf,"-> "); |
| | | } |
| | | }while( i!= fifoPos); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char locus[]){ |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER) |
| | | if( trigger ){ |
| | | log_i("%s",locus); |
| | | if(trigger & 1) i2cDumpI2c(i2c); |
| | | if(trigger & 2) i2cDumpInts(i2c->num); |
| | | if(trigger & 4) i2cDumpCmdQueue(i2c); |
| | | if(trigger & 8) i2cDumpStatus(i2c); |
| | | if(trigger & 16) i2cDumpFifo(i2c); |
| | | } |
| | | #endif |
| | | } |
| | | // end of debug support routines |
| | | |
| | | /* Start of CPU Clock change Support |
| | | */ |
| | | |
| | | static void i2cApbChangeCallback(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
| | | i2c_t* i2c = (i2c_t*) arg; // recover data |
| | | if(i2c == NULL) { // point to peripheral control block does not exits |
| | | return; |
| | | } |
| | | uint32_t oldFreq=0; |
| | | switch(ev_type){ |
| | | case APB_BEFORE_CHANGE : |
| | | if(new_apb < 3000000) {// too slow |
| | | log_e("apb speed %d too slow",new_apb); |
| | | break; |
| | | } |
| | | I2C_MUTEX_LOCK(); // lock will spin until current transaction is completed |
| | | break; |
| | | case APB_AFTER_CHANGE : |
| | | oldFreq = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period); //read old apbCycles |
| | | if(oldFreq>0) { // was configured with value |
| | | oldFreq = old_apb / oldFreq; |
| | | i2cSetFrequency(i2c,oldFreq); |
| | | } |
| | | I2C_MUTEX_UNLOCK(); |
| | | break; |
| | | default : |
| | | log_e("unk ev %u",ev_type); |
| | | I2C_MUTEX_UNLOCK(); |
| | | } |
| | | return; |
| | | } |
| | | /* End of CPU Clock change Support |
| | | */ |
| | | static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check) |
| | | { |
| | | I2C_COMMAND_t cmd; |
| | | cmd.val=0; |
| | | cmd.ack_en = ack_check; |
| | | cmd.ack_exp = ack_exp; |
| | | cmd.ack_val = ack_val; |
| | | cmd.byte_num = byte_num; |
| | | cmd.op_code = op_code; |
| | | i2c->dev->command[index].val = cmd.val; |
| | | } |
| | | |
| | | |
| | | static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS) |
| | | { |
| | | /* this function is called on initial i2cProcQueue() or when a I2C_END_DETECT_INT occurs |
| | | */ |
| | | uint16_t cmdIdx = 0; |
| | | uint16_t qp = i2c->queuePos; // all queues before queuePos have been completely processed, |
| | | // so look start by checking the 'current queue' so see if it needs commands added to |
| | | // hardware peripheral command list. walk through each queue entry until all queues have been |
| | | // checked |
| | | bool done; |
| | | bool needMoreCmds = false; |
| | | bool ena_rx=false; // if we add a read op, better enable Rx_Fifo IRQ |
| | | bool ena_tx=false; // if we add a Write op, better enable TX_Fifo IRQ |
| | | |
| | | while(!needMoreCmds&&(qp < i2c->queueCount)) { // check if more possible cmds |
| | | if(i2c->dq[qp].ctrl.stopCmdSent) {// marks that all required cmds[] have been added to peripheral |
| | | qp++; |
| | | } else { |
| | | needMoreCmds=true; |
| | | } |
| | | } |
| | | //log_e("needMoreCmds=%d",needMoreCmds); |
| | | done=(!needMoreCmds)||(cmdIdx>14); |
| | | |
| | | while(!done) { // fill the command[] until either 0..14 filled or out of cmds and last cmd is STOP |
| | | //CMD START |
| | | I2C_DATA_QUEUE_t *tdq=&i2c->dq[qp]; // simpler coding |
| | | |
| | | if((!tdq->ctrl.startCmdSent) && (cmdIdx < 14)) { // has this dq element's START command been added? |
| | | // (cmdIdx<14) because a START op cannot directly precede an END op, else a time out cascade occurs |
| | | i2cSetCmd(i2c, cmdIdx++, I2C_CMD_RSTART, 0, false, false, false); |
| | | tdq->ctrl.startCmdSent=1; |
| | | } |
| | | |
| | | //CMD WRITE ADDRESS |
| | | if((!done)&&(tdq->ctrl.startCmdSent)) { // have to leave room for continue(END), and START must have been sent! |
| | | if(!tdq->ctrl.addrCmdSent) { |
| | | i2cSetCmd(i2c, cmdIdx++, I2C_CMD_WRITE, tdq->ctrl.addrReq, false, false, true); //load address in cmdlist, validate (low) ack |
| | | tdq->ctrl.addrCmdSent=1; |
| | | done =(cmdIdx>14); |
| | | ena_tx=true; // tx Data necessary |
| | | } |
| | | } |
| | | |
| | | /* Can I have another Sir? |
| | | ALL CMD queues must be terminated with either END or STOP. |
| | | |
| | | If END is used, when refilling the cmd[] next time, no entries from END to [15] can be used. |
| | | AND the cmd[] must be filled starting at [0] with commands. Either fill all 15 [0]..[14] and leave the |
| | | END in [15] or include a STOP in one of the positions [0]..[14]. Any entries after a STOP are IGNORED by the StateMachine. |
| | | The END operation does not complete until ctr->trans_start=1 has been issued. |
| | | |
| | | So, only refill from [0]..[14], leave [15] for a continuation(END) if necessary. |
| | | As a corollary, once END exists in [15], you do not need to overwrite it for the |
| | | next continuation. It is never modified. But, I update it every time because it might |
| | | actually be the first time! |
| | | |
| | | 23NOV17 START cannot proceed END. if START is in[14], END cannot be in [15]. |
| | | So, if END is moved to [14], [14] and [15] can no longer be used for anything other than END. |
| | | If a START is found in [14] then a prior READ or WRITE must be expanded so that there is no START element in [14]. |
| | | */ |
| | | |
| | | if((!done)&&(tdq->ctrl.addrCmdSent)) { //room in command[] for at least One data (read/Write) cmd |
| | | uint8_t blkSize=0; // max is 255 |
| | | while(( tdq->cmdBytesNeeded > tdq->ctrl.mode )&&(!done )) { // more bytes needed and room in cmd queue, leave room for END |
| | | blkSize = (tdq->cmdBytesNeeded > 255)?255:(tdq->cmdBytesNeeded - tdq->ctrl.mode); // Last read cmd needs different ACK setting, so leave 1 byte remainder on reads |
| | | tdq->cmdBytesNeeded -= blkSize; |
| | | if(tdq->ctrl.mode==1) { //read mode |
| | | i2cSetCmd(i2c, (cmdIdx)++, I2C_CMD_READ, blkSize,false,false,false); // read cmd, this can't be the last read. |
| | | ena_rx=true; // need to enable rxFifo IRQ |
| | | } else { // write |
| | | i2cSetCmd(i2c, cmdIdx++, I2C_CMD_WRITE, blkSize, false, false, true); // check for Nak |
| | | ena_tx=true; // need to enable txFifo IRQ |
| | | } |
| | | done = cmdIdx>14; //have to leave room for END |
| | | } |
| | | |
| | | if(!done) { // buffer is not filled completely |
| | | if((tdq->ctrl.mode==1)&&(tdq->cmdBytesNeeded==1)) { //special last read byte NAK |
| | | i2cSetCmd(i2c, (cmdIdx)++, I2C_CMD_READ, 1,true,false,false); |
| | | // send NAK to mark end of read |
| | | tdq->cmdBytesNeeded=0; |
| | | done = cmdIdx > 14; |
| | | ena_rx=true; |
| | | } |
| | | } |
| | | |
| | | tdq->ctrl.dataCmdSent=(tdq->cmdBytesNeeded==0); // enough command[] to send all data |
| | | |
| | | if((!done)&&(tdq->ctrl.dataCmdSent)) { // possibly add stop |
| | | if(!tdq->ctrl.stopCmdSent){ |
| | | if(tdq->ctrl.stop) { //send a stop |
| | | i2cSetCmd(i2c, (cmdIdx)++,I2C_CMD_STOP,0,false,false,false); |
| | | done = cmdIdx > 14; |
| | | } |
| | | tdq->ctrl.stopCmdSent = 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if((cmdIdx==14)&&(!tdq->ctrl.startCmdSent)) { |
| | | // START would have preceded END, causes SM TIMEOUT |
| | | // need to stretch out a prior WRITE or READ to two Command[] elements |
| | | done = false; // reuse it |
| | | uint16_t i = 13; // start working back until a READ/WRITE has >1 numBytes |
| | | cmdIdx =15; |
| | | while(!done) { |
| | | i2c->dev->command[i+1].val = i2c->dev->command[i].val; // push it down |
| | | if (((i2c->dev->command[i].op_code == 1)||(i2c->dev->command[i].op_code==2))) { |
| | | /* add a dummy read/write cmd[] with num_bytes set to zero,just a place holder in the cmd[]list |
| | | */ |
| | | i2c->dev->command[i].byte_num = 0; |
| | | done = true; |
| | | |
| | | } else { |
| | | if(i > 0) { |
| | | i--; |
| | | } else { // unable to stretch, fatal |
| | | log_e("invalid CMD[] layout Stretch Failed"); |
| | | i2cDumpCmdQueue(i2c); |
| | | done = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | if(cmdIdx==15) { //need continuation, even if STOP is in 14, it will not matter |
| | | // cmd buffer is almost full, Add END as a continuation feature |
| | | i2cSetCmd(i2c, (cmdIdx)++,I2C_CMD_END, 0,false,false,false); |
| | | i2c->dev->int_ena.end_detect=1; |
| | | i2c->dev->int_clr.end_detect=1; |
| | | done = true; |
| | | } |
| | | |
| | | if(!done) { |
| | | if(tdq->ctrl.stopCmdSent) { // this queue element has been completely added to command[] buffer |
| | | qp++; |
| | | if(qp < i2c->queueCount) { |
| | | tdq = &i2c->dq[qp]; |
| | | } else { |
| | | done = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | }// while(!done) |
| | | if(INTS) { // don't want to prematurely enable fifo ints until ISR is ready to handle them. |
| | | if(ena_rx) { |
| | | i2c->dev->int_ena.rx_fifo_full = 1; |
| | | } |
| | | if(ena_tx) { |
| | | i2c->dev->int_ena.tx_fifo_empty = 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void IRAM_ATTR fillTxFifo(i2c_t * i2c) |
| | | { |
| | | /* |
| | | 12/01/2017 The Fifo's are independent, 32 bytes of tx and 32 bytes of Rx. |
| | | overlap is not an issue, just keep them full/empty the status_reg.xx_fifo_cnt |
| | | tells the truth. And the INT's fire correctly |
| | | */ |
| | | uint16_t a=i2c->queuePos; // currently executing dq, |
| | | bool full=!(i2c->dev->status_reg.tx_fifo_cnt<31); |
| | | uint8_t cnt; |
| | | bool rxQueueEncountered = false; |
| | | while((a < i2c->queueCount) && !full) { |
| | | I2C_DATA_QUEUE_t *tdq = &i2c->dq[a]; |
| | | cnt=0; |
| | | // add to address to fifo ctrl.addr already has R/W bit positioned correctly |
| | | if(tdq->ctrl.addrSent < tdq->ctrl.addrReq) { // need to send address bytes |
| | | if(tdq->ctrl.addrReq==2) { //10bit |
| | | if(tdq->ctrl.addrSent==0) { //10bit highbyte needs sent |
| | | if(!full) { // room in fifo |
| | | i2c->dev->fifo_data.val = ((tdq->ctrl.addr>>8)&0xFF); |
| | | cnt++; |
| | | tdq->ctrl.addrSent=1; //10bit highbyte sent |
| | | } |
| | | } |
| | | full=!(i2c->dev->status_reg.tx_fifo_cnt<31); |
| | | |
| | | if(tdq->ctrl.addrSent==1) { //10bit Lowbyte needs sent |
| | | if(!full) { // room in fifo |
| | | i2c->dev->fifo_data.val = tdq->ctrl.addr&0xFF; |
| | | cnt++; |
| | | tdq->ctrl.addrSent=2; //10bit lowbyte sent |
| | | } |
| | | } |
| | | } else { // 7bit} |
| | | if(tdq->ctrl.addrSent==0) { // 7bit Lowbyte needs sent |
| | | if(!full) { // room in fifo |
| | | i2c->dev->fifo_data.val = tdq->ctrl.addr&0xFF; |
| | | cnt++; |
| | | tdq->ctrl.addrSent=1; // 7bit lowbyte sent |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | uint16_t a = 0x8000 | tdq->ctrl.addr | (tdq->ctrl.mode<<8); |
| | | fifoBuffer[fifoPos++] = a; |
| | | fifoPos %= FIFOMAX; |
| | | #endif |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // add write data to fifo |
| | | if(tdq->ctrl.mode==0) { // write |
| | | if(tdq->ctrl.addrSent == tdq->ctrl.addrReq) { //address has been sent, is Write Mode! |
| | | uint32_t moveCnt = 32 - i2c->dev->status_reg.tx_fifo_cnt; // how much room in txFifo? |
| | | while(( moveCnt>0)&&(tdq->position < tdq->length)) { |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | fifoBuffer[fifoPos++] = tdq->data[tdq->position]; |
| | | fifoPos %= FIFOMAX; |
| | | #endif |
| | | i2c->dev->fifo_data.val = tdq->data[tdq->position++]; |
| | | cnt++; |
| | | moveCnt--; |
| | | |
| | | } |
| | | } |
| | | } else { // read Queue Encountered, can't update QueuePos past this point, emptyRxfifo will do it |
| | | if( ! rxQueueEncountered ) { |
| | | rxQueueEncountered = true; |
| | | if(a > i2c->queuePos){ |
| | | i2c->queuePos = a; |
| | | } |
| | | } |
| | | } |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | |
| | | // update debug buffer tx counts |
| | | cnt += intBuff[intPos[i2c->num]][1][i2c->num]>>16; |
| | | intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF)|(cnt<<16); |
| | | |
| | | #endif |
| | | full=!(i2c->dev->status_reg.tx_fifo_cnt<31); |
| | | if(!full) { |
| | | a++; // check next buffer for address tx, or write data |
| | | } |
| | | } |
| | | |
| | | if(a >= i2c->queueCount ) { // disable TX IRQ, all tx Data has been queued |
| | | i2c->dev->int_ena.tx_fifo_empty= 0; |
| | | } |
| | | |
| | | i2c->dev->int_clr.tx_fifo_empty=1; |
| | | } |
| | | |
| | | |
| | | static void IRAM_ATTR emptyRxFifo(i2c_t * i2c) |
| | | { |
| | | uint32_t d, cnt=0, moveCnt; |
| | | |
| | | moveCnt = i2c->dev->status_reg.rx_fifo_cnt;//no need to check the reg until this many are read |
| | | |
| | | while((moveCnt > 0)&&(i2c->queuePos < i2c->queueCount)){ // data to move |
| | | |
| | | I2C_DATA_QUEUE_t *tdq =&i2c->dq[i2c->queuePos]; //short cut |
| | | |
| | | while((tdq->position >= tdq->length)&&( i2c->queuePos < i2c->queueCount)){ // find were to store |
| | | i2c->queuePos++; |
| | | tdq = &i2c->dq[i2c->queuePos]; |
| | | } |
| | | |
| | | if(i2c->queuePos >= i2c->queueCount){ // bad stuff, rx data but no place to put it! |
| | | log_e("no Storage location for %d",moveCnt); |
| | | // discard |
| | | while(moveCnt>0){ |
| | | d = i2c->dev->fifo_data.val; |
| | | moveCnt--; |
| | | cnt++; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | if(tdq->ctrl.mode == 1){ // read command |
| | | if(moveCnt > (tdq->length - tdq->position)) { //make sure they go in this dq |
| | | // part of these reads go into the next dq |
| | | moveCnt = (tdq->length - tdq->position); |
| | | } |
| | | } else {// error |
| | | log_e("RxEmpty(%d) call on TxBuffer? dq=%d",moveCnt,i2c->queuePos); |
| | | // discard |
| | | while(moveCnt>0){ |
| | | d = i2c->dev->fifo_data.val; |
| | | moveCnt--; |
| | | cnt++; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | while(moveCnt > 0) { // store data |
| | | d = i2c->dev->fifo_data.val; |
| | | moveCnt--; |
| | | cnt++; |
| | | tdq->data[tdq->position++] = (d&0xFF); |
| | | } |
| | | |
| | | moveCnt = i2c->dev->status_reg.rx_fifo_cnt; //any more out there? |
| | | } |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&& (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | // update Debug rxCount |
| | | cnt += (intBuff[intPos[i2c->num]][1][i2c->num])&0xffFF; |
| | | intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF0000)|cnt; |
| | | #endif |
| | | } |
| | | |
| | | static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal) |
| | | { |
| | | |
| | | switch(eventCode) { |
| | | case EVENT_DONE: |
| | | i2c->error = I2C_OK; |
| | | break; |
| | | case EVENT_ERROR_NAK : |
| | | i2c->error =I2C_ADDR_NAK; |
| | | break; |
| | | case EVENT_ERROR_DATA_NAK : |
| | | i2c->error =I2C_DATA_NAK; |
| | | break; |
| | | case EVENT_ERROR_TIMEOUT : |
| | | i2c->error = I2C_TIMEOUT; |
| | | break; |
| | | case EVENT_ERROR_ARBITRATION: |
| | | i2c->error = I2C_ARBITRATION; |
| | | break; |
| | | default : |
| | | i2c->error = I2C_ERROR; |
| | | } |
| | | uint32_t exitCode = EVENT_DONE | eventCode |(Fatal?EVENT_ERROR:0); |
| | | if((i2c->queuePos < i2c->queueCount) && (i2c->dq[i2c->queuePos].ctrl.mode == 1)) { |
| | | emptyRxFifo(i2c); // grab last few characters |
| | | } |
| | | i2c->dev->int_ena.val = 0; // shut down interrupts |
| | | i2c->dev->int_clr.val = 0x1FFF; |
| | | i2c->stage = I2C_DONE; |
| | | i2c->exitCode = exitCode; //true eventcode |
| | | |
| | | portBASE_TYPE HPTaskAwoken = pdFALSE,xResult; |
| | | // try to notify Dispatch we are done, |
| | | // else the 50ms time out will recover the APP, just a little slower |
| | | HPTaskAwoken = pdFALSE; |
| | | xResult = xEventGroupSetBitsFromISR(i2c->i2c_event, exitCode, &HPTaskAwoken); |
| | | if(xResult == pdPASS) { |
| | | if(HPTaskAwoken==pdTRUE) { |
| | | portYIELD_FROM_ISR(); |
| | | // log_e("Yield to Higher"); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | static void IRAM_ATTR i2c_update_error_byte_cnt(i2c_t * i2c) |
| | | { |
| | | /* i2c_update_error_byte_cnt 07/18/2018 |
| | | Only called after an error has occurred, so, most of the time this function is never used. |
| | | This function obliterates the need to interrupt monitor each byte transferred, at high bitrates |
| | | the byte interrupts were overwhelming the OS. Spurious Interrupts were being generated. |
| | | it updates errorByteCnt, errorQueue. |
| | | */ |
| | | uint16_t a=0; // start at top of DQ, count how many bytes added to tx fifo, and received from rx_fifo. |
| | | int16_t bc = 0; |
| | | I2C_DATA_QUEUE_t *tdq; |
| | | i2c->errorByteCnt = 0; |
| | | while( a < i2c->queueCount){ // add up all bytes loaded into fifo's |
| | | tdq = &i2c->dq[a]; |
| | | i2c->errorByteCnt += tdq->ctrl.addrSent; |
| | | i2c->errorByteCnt += tdq->position; |
| | | a++; |
| | | } |
| | | // now errorByteCnt contains total bytes moved into and out of FIFO's |
| | | // but, there may still be bytes waiting in Fifo's |
| | | i2c->errorByteCnt -= i2c->dev->status_reg.tx_fifo_cnt; // waiting to go out; |
| | | i2c->errorByteCnt += i2c->dev->status_reg.rx_fifo_cnt; // already received |
| | | // now walk thru DQ again, find which byte is 'current' |
| | | bc = i2c->errorByteCnt; |
| | | i2c->errorQueue = 0; |
| | | while( i2c->errorQueue < i2c->queueCount ){ |
| | | tdq = &i2c->dq[i2c->errorQueue]; |
| | | if(bc>0){ // not found yet |
| | | if( tdq->ctrl.addrSent >= bc){ // in address |
| | | bc = -1; // in address |
| | | break; |
| | | } else { |
| | | bc -= tdq->ctrl.addrSent; |
| | | if( tdq->length > bc) { // data nak |
| | | break; |
| | | } else { // count down |
| | | bc -= tdq->length; |
| | | } |
| | | } |
| | | } else break; |
| | | |
| | | i2c->errorQueue++; |
| | | } |
| | | |
| | | i2c->errorByteCnt = bc; |
| | | } |
| | | |
| | | static void IRAM_ATTR i2c_isr_handler_default(void* arg) |
| | | { |
| | | i2c_t* p_i2c = (i2c_t*) arg; // recover data |
| | | uint32_t activeInt = p_i2c->dev->int_status.val&0x7FF; |
| | | |
| | | if(p_i2c->stage==I2C_DONE) { //get Out, can't service, not configured |
| | | p_i2c->dev->int_ena.val = 0; |
| | | p_i2c->dev->int_clr.val = 0x1FFF; |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE |
| | | uint32_t raw = p_i2c->dev->int_raw.val; |
| | | log_w("eject raw=%p, int=%p",raw,activeInt); |
| | | #endif |
| | | return; |
| | | } |
| | | while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | if(activeInt==(intBuff[intPos[p_i2c->num]][0][p_i2c->num]&0x1fff)) { |
| | | intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (((intBuff[intPos[p_i2c->num]][0][p_i2c->num]>>16)+1)<<16)|activeInt; |
| | | } else { |
| | | intPos[p_i2c->num]++; |
| | | intPos[p_i2c->num] %= INTBUFFMAX; |
| | | intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (1<<16) | activeInt; |
| | | intBuff[intPos[p_i2c->num]][1][p_i2c->num] = 0; |
| | | } |
| | | |
| | | intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired |
| | | |
| | | #endif |
| | | |
| | | if (activeInt & I2C_TRANS_START_INT_ST_M) { |
| | | if(p_i2c->stage==I2C_STARTUP) { |
| | | p_i2c->stage=I2C_RUNNING; |
| | | } |
| | | |
| | | activeInt &=~I2C_TRANS_START_INT_ST_M; |
| | | p_i2c->dev->int_ena.trans_start = 1; // already enabled? why Again? |
| | | p_i2c->dev->int_clr.trans_start = 1; // so that will trigger after next 'END' |
| | | } |
| | | |
| | | if (activeInt & I2C_TXFIFO_EMPTY_INT_ST) {//should this be before Trans_start? |
| | | fillTxFifo(p_i2c); //fillTxFifo will enable/disable/clear interrupt |
| | | activeInt&=~I2C_TXFIFO_EMPTY_INT_ST; |
| | | } |
| | | |
| | | if(activeInt & I2C_RXFIFO_FULL_INT_ST) { |
| | | emptyRxFifo(p_i2c); |
| | | p_i2c->dev->int_clr.rx_fifo_full=1; |
| | | p_i2c->dev->int_ena.rx_fifo_full=1; //why? |
| | | |
| | | activeInt &=~I2C_RXFIFO_FULL_INT_ST; |
| | | } |
| | | |
| | | if (activeInt & I2C_ACK_ERR_INT_ST_M) {//fatal error, abort i2c service |
| | | if (p_i2c->mode == I2C_MASTER) { |
| | | i2c_update_error_byte_cnt(p_i2c); // calc which byte caused ack Error, check if address or data |
| | | if(p_i2c->errorByteCnt < 0 ) { // address |
| | | i2cIsrExit(p_i2c,EVENT_ERROR_NAK,true); |
| | | } else { |
| | | i2cIsrExit(p_i2c,EVENT_ERROR_DATA_NAK,true); //data |
| | | } |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (activeInt & I2C_TIME_OUT_INT_ST_M) { |
| | | // let Gross timeout occur, Slave may release SCL before the configured timeout expires |
| | | // the Statemachine only has a 13.1ms max timout, some Devices >500ms |
| | | p_i2c->dev->int_clr.time_out =1; |
| | | activeInt &=~I2C_TIME_OUT_INT_ST; |
| | | // since a timeout occurred, capture the rxFifo data |
| | | emptyRxFifo(p_i2c); |
| | | p_i2c->dev->int_clr.rx_fifo_full=1; |
| | | p_i2c->dev->int_ena.rx_fifo_full=1; //why? |
| | | |
| | | } |
| | | |
| | | if (activeInt & I2C_TRANS_COMPLETE_INT_ST_M) { |
| | | p_i2c->dev->int_clr.trans_complete = 1; |
| | | i2cIsrExit(p_i2c,EVENT_DONE,false); |
| | | return; // no more work to do |
| | | /* |
| | | // how does slave mode act? |
| | | if (p_i2c->mode == I2C_SLAVE) { // STOP detected |
| | | // empty fifo |
| | | // dispatch callback |
| | | */ |
| | | } |
| | | |
| | | if (activeInt & I2C_ARBITRATION_LOST_INT_ST_M) { //fatal |
| | | i2cIsrExit(p_i2c,EVENT_ERROR_ARBITRATION,true); |
| | | return; // no more work to do |
| | | } |
| | | |
| | | if (activeInt & I2C_SLAVE_TRAN_COMP_INT_ST_M) { |
| | | p_i2c->dev->int_clr.slave_tran_comp = 1; |
| | | // need to complete this ! |
| | | } |
| | | |
| | | if (activeInt & I2C_END_DETECT_INT_ST_M) { |
| | | p_i2c->dev->int_ena.end_detect = 0; |
| | | p_i2c->dev->int_clr.end_detect = 1; |
| | | p_i2c->dev->ctr.trans_start=0; |
| | | fillCmdQueue(p_i2c,true); // enable interrupts |
| | | p_i2c->dev->ctr.trans_start=1; // go for it |
| | | activeInt&=~I2C_END_DETECT_INT_ST_M; |
| | | } |
| | | |
| | | if(activeInt) { // clear unhandled if possible? What about Disabling interrupt? |
| | | p_i2c->dev->int_clr.val = activeInt; |
| | | log_e("unknown int=%x",activeInt); |
| | | // disable unhandled IRQ, |
| | | p_i2c->dev->int_ena.val = p_i2c->dev->int_ena.val & (~activeInt); |
| | | } |
| | | |
| | | // activeInt = p_i2c->dev->int_status.val; // start all over if another interrupt happened |
| | | // 01AUG2018 if another interrupt happened, the OS will schedule another interrupt |
| | | // this is the source of spurious interrupts |
| | | } |
| | | } |
| | | |
| | | /* Stickbreaker added for ISR 11/2017 |
| | | functional with Silicon date=0x16042000 |
| | | */ |
| | | static i2c_err_t i2cAddQueue(i2c_t * i2c,uint8_t mode, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen,bool sendStop, bool dataOnly, EventGroupHandle_t event) |
| | | { |
| | | // need to grab a MUTEX for exclusive Queue, |
| | | // what about if ISR is running? |
| | | |
| | | if(i2c==NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | |
| | | I2C_DATA_QUEUE_t dqx; |
| | | dqx.data = dataPtr; |
| | | dqx.length = dataLen; |
| | | dqx.position = 0; |
| | | dqx.cmdBytesNeeded = dataLen; |
| | | dqx.ctrl.val = 0; |
| | | if( dataOnly) { |
| | | /* special case to add a queue data only element. |
| | | START and devAddr will not be sent, this dq element can have a STOP. |
| | | allows multiple buffers to be used for one transaction. |
| | | sequence: normal transaction(sendStop==false), [dataonly(sendStop==false)],dataOnly(sendStop==true) |
| | | *** Currently only works with WRITE, final byte NAK an READ will cause a fail between dq buffer elements. (in progress 30JUL2018) |
| | | */ |
| | | dqx.ctrl.startCmdSent = 1; // mark as already sent |
| | | dqx.ctrl.addrCmdSent = 1; |
| | | } else { |
| | | dqx.ctrl.addrReq = ((i2cDeviceAddr&0xFC00)==0x7800)?2:1; // 10bit or 7bit address |
| | | } |
| | | dqx.ctrl.addr = i2cDeviceAddr; |
| | | dqx.ctrl.mode = mode; |
| | | dqx.ctrl.stop= sendStop; |
| | | dqx.queueEvent = event; |
| | | |
| | | if(event) { // an eventGroup exist, so, initialize it |
| | | xEventGroupClearBits(event, EVENT_MASK); // all of them |
| | | } |
| | | |
| | | if(i2c->dq!=NULL) { // expand |
| | | //log_i("expand"); |
| | | I2C_DATA_QUEUE_t* tq =(I2C_DATA_QUEUE_t*)realloc(i2c->dq,sizeof(I2C_DATA_QUEUE_t)*(i2c->queueCount +1)); |
| | | if(tq!=NULL) { // ok |
| | | i2c->dq = tq; |
| | | memmove(&i2c->dq[i2c->queueCount++],&dqx,sizeof(I2C_DATA_QUEUE_t)); |
| | | } else { // bad stuff, unable to allocate more memory! |
| | | log_e("realloc Failure"); |
| | | return I2C_ERROR_MEMORY; |
| | | } |
| | | } else { // first Time |
| | | //log_i("new"); |
| | | i2c->queueCount=0; |
| | | i2c->dq =(I2C_DATA_QUEUE_t*)malloc(sizeof(I2C_DATA_QUEUE_t)); |
| | | if(i2c->dq!=NULL) { |
| | | memmove(&i2c->dq[i2c->queueCount++],&dqx,sizeof(I2C_DATA_QUEUE_t)); |
| | | } else { |
| | | log_e("malloc failure"); |
| | | return I2C_ERROR_MEMORY; |
| | | } |
| | | } |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | i2c_err_t i2cAddQueueWrite(i2c_t * i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen,bool sendStop,EventGroupHandle_t event) |
| | | { |
| | | return i2cAddQueue(i2c,0,i2cDeviceAddr,dataPtr,dataLen,sendStop,false,event); |
| | | } |
| | | |
| | | i2c_err_t i2cAddQueueRead(i2c_t * i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen,bool sendStop,EventGroupHandle_t event) |
| | | { |
| | | //10bit read is kind of weird, first you do a 0byte Write with 10bit |
| | | // address, then a ReSTART then a 7bit Read using the the upper 7bit + |
| | | // readBit. |
| | | |
| | | // this might cause an internal register pointer problem with 10bit |
| | | // devices, But, Don't have any to test against. |
| | | // this is the Industry Standard specification. |
| | | |
| | | if((i2cDeviceAddr &0xFC00)==0x7800) { // ten bit read |
| | | i2c_err_t err = i2cAddQueue(i2c,0,i2cDeviceAddr,NULL,0,false,false,event); |
| | | if(err==I2C_ERROR_OK) { |
| | | return i2cAddQueue(i2c,1,(i2cDeviceAddr>>8),dataPtr,dataLen,sendStop,false,event); |
| | | } else { |
| | | return err; |
| | | } |
| | | } |
| | | return i2cAddQueue(i2c,1,i2cDeviceAddr,dataPtr,dataLen,sendStop,false,event); |
| | | } |
| | | |
| | | i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis) |
| | | { |
| | | /* do the hard stuff here |
| | | install ISR if necessary |
| | | setup EventGroup |
| | | handle bus busy? |
| | | */ |
| | | //log_e("procQueue i2c=%p",&i2c); |
| | | if(readCount){ //total reads accomplished in all queue elements |
| | | *readCount = 0; |
| | | } |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | if(i2c->debugFlags & 0xff000000) i2cTriggerDumps(i2c,(i2c->debugFlags>>24),"before ProcQueue"); |
| | | if (i2c->dev->status_reg.bus_busy) { // return error, let TwoWire() handle resetting the hardware. |
| | | /* if multi master then this if should be changed to this 03/12/2018 |
| | | if(multiMaster){// try to let the bus clear by its self |
| | | uint32_t timeOutTick = millis(); |
| | | while((i2c->dev->status_reg.bus_busy)&&(millis()-timeOutTick<timeOutMillis())){ |
| | | delay(2); // allow task switch |
| | | } |
| | | } |
| | | if(i2c->dev->status_reg.bus_busy){ // still busy, so die |
| | | */ |
| | | log_i("Bus busy, reinit"); |
| | | return I2C_ERROR_BUSY; |
| | | } |
| | | |
| | | I2C_MUTEX_LOCK(); |
| | | /* what about co-existence with SLAVE mode? |
| | | Should I check if a slaveMode xfer is in progress and hang |
| | | until it completes? |
| | | if i2c->stage == I2C_RUNNING or I2C_SLAVE_ACTIVE |
| | | */ |
| | | i2c->stage = I2C_DONE; // until ready |
| | | |
| | | #if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER) |
| | | for(uint16_t i=0; i<INTBUFFMAX; i++) { |
| | | intBuff[i][0][i2c->num] = 0; |
| | | intBuff[i][1][i2c->num] = 0; |
| | | intBuff[i][2][i2c->num] = 0; |
| | | } |
| | | intPos[i2c->num] = 0; |
| | | fifoPos = 0; |
| | | memset(fifoBuffer,0,FIFOMAX); |
| | | #endif |
| | | // EventGroup is used to signal transmission completion from ISR |
| | | // not always reliable. Sometimes, the FreeRTOS scheduler is maxed out and refuses request |
| | | // if that happens, this call hangs until the timeout period expires, then it continues. |
| | | if(!i2c->i2c_event) { |
| | | i2c->i2c_event = xEventGroupCreate(); |
| | | } |
| | | if(i2c->i2c_event) { |
| | | xEventGroupClearBits(i2c->i2c_event, 0xFF); |
| | | } else { // failed to create EventGroup |
| | | log_e("eventCreate failed=%p",i2c->i2c_event); |
| | | I2C_MUTEX_UNLOCK(); |
| | | return I2C_ERROR_MEMORY; |
| | | } |
| | | |
| | | i2c_err_t reason = I2C_ERROR_OK; |
| | | i2c->mode = I2C_MASTER; |
| | | i2c->dev->ctr.trans_start=0; // Pause Machine |
| | | i2c->dev->timeout.tout = 0xFFFFF; // max 13ms |
| | | i2c->dev->int_clr.val = 0x1FFF; // kill them All! |
| | | |
| | | i2c->dev->ctr.ms_mode = 1; // master! |
| | | i2c->queuePos=0; |
| | | i2c->errorByteCnt=0; |
| | | i2c->errorQueue = 0; |
| | | uint32_t totalBytes=0; // total number of bytes to be Moved! |
| | | // convert address field to required I2C format |
| | | while(i2c->queuePos < i2c->queueCount) { // need to push these address modes upstream, to AddQueue |
| | | I2C_DATA_QUEUE_t *tdq = &i2c->dq[i2c->queuePos++]; |
| | | uint16_t taddr=0; |
| | | if(tdq->ctrl.addrReq ==2) { // 10bit address |
| | | taddr =((tdq->ctrl.addr >> 7) & 0xFE) |
| | | |tdq->ctrl.mode; |
| | | taddr = (taddr <<8) | (tdq->ctrl.addr&0xFF); |
| | | } else { // 7bit address |
| | | taddr = ((tdq->ctrl.addr<<1)&0xFE) |
| | | |tdq->ctrl.mode; |
| | | } |
| | | tdq->ctrl.addr = taddr; // all fixed with R/W bit |
| | | totalBytes += tdq->length + tdq->ctrl.addrReq; // total number of byte to be moved! |
| | | } |
| | | i2c->queuePos=0; |
| | | |
| | | fillCmdQueue(i2c,false); // don't enable Tx/RX irq's |
| | | // start adding command[], END irq will keep it full |
| | | //Data Fifo will be filled after trans_start is issued |
| | | i2c->exitCode=0; |
| | | |
| | | I2C_FIFO_CONF_t f; |
| | | f.val = i2c->dev->fifo_conf.val; |
| | | f.rx_fifo_rst = 1; // fifo in reset |
| | | f.tx_fifo_rst = 1; // fifo in reset |
| | | f.nonfifo_en = 0; // use fifo mode |
| | | f.nonfifo_tx_thres = 31; |
| | | // need to adjust threshold based on I2C clock rate, at 100k, 30 usually works, |
| | | // sometimes the emptyRx() actually moves 31 bytes |
| | | // it hasn't overflowed yet, I cannot tell if the new byte is added while |
| | | // emptyRX() is executing or before? |
| | | // let i2cSetFrequency() set thrhds |
| | | // f.rx_fifo_full_thrhd = 30; // 30 bytes before INT is issued |
| | | // f.tx_fifo_empty_thrhd = 0; |
| | | f.fifo_addr_cfg_en = 0; // no directed access |
| | | i2c->dev->fifo_conf.val = f.val; // post them all |
| | | |
| | | f.rx_fifo_rst = 0; // release fifo |
| | | f.tx_fifo_rst = 0; |
| | | i2c->dev->fifo_conf.val = f.val; // post them all |
| | | |
| | | i2c->stage = I2C_STARTUP; // everything configured, now start the I2C StateMachine, and |
| | | // As soon as interrupts are enabled, the ISR will start handling them. |
| | | // it should receive a TXFIFO_EMPTY immediately, even before it |
| | | // receives the TRANS_START |
| | | |
| | | |
| | | uint32_t interruptsEnabled = |
| | | I2C_ACK_ERR_INT_ENA | // (BIT(10)) Causes Fatal Error Exit |
| | | I2C_TRANS_START_INT_ENA | // (BIT(9)) Triggered by trans_start=1, initial,END |
| | | I2C_TIME_OUT_INT_ENA | //(BIT(8)) Trigger by SLAVE SCL stretching, NOT an ERROR |
| | | I2C_TRANS_COMPLETE_INT_ENA | // (BIT(7)) triggered by STOP, successful exit |
| | | I2C_ARBITRATION_LOST_INT_ENA | // (BIT(5)) cause fatal error exit |
| | | I2C_SLAVE_TRAN_COMP_INT_ENA | // (BIT(4)) unhandled |
| | | I2C_END_DETECT_INT_ENA | // (BIT(3)) refills cmd[] list |
| | | I2C_RXFIFO_OVF_INT_ENA | //(BIT(2)) unhandled |
| | | I2C_TXFIFO_EMPTY_INT_ENA | // (BIT(1)) triggers fillTxFifo() |
| | | I2C_RXFIFO_FULL_INT_ENA; // (BIT(0)) trigger emptyRxFifo() |
| | | |
| | | i2c->dev->int_ena.val = interruptsEnabled; |
| | | |
| | | if(!i2c->intr_handle) { // create ISR for either peripheral |
| | | // log_i("create ISR %d",i2c->num); |
| | | uint32_t ret = 0; |
| | | uint32_t flags = ESP_INTR_FLAG_IRAM | //< ISR can be called if cache is disabled |
| | | ESP_INTR_FLAG_LOWMED | //< Low and medium prio interrupts. These can be handled in C. |
| | | ESP_INTR_FLAG_SHARED; //< Reduce resource requirements, Share interrupts |
| | | |
| | | if(i2c->num) { |
| | | ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT1_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, interruptsEnabled, &i2c_isr_handler_default,i2c, &i2c->intr_handle); |
| | | } else { |
| | | ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT0_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, interruptsEnabled, &i2c_isr_handler_default,i2c, &i2c->intr_handle); |
| | | } |
| | | |
| | | if(ret!=ESP_OK) { |
| | | log_e("install interrupt handler Failed=%d",ret); |
| | | I2C_MUTEX_UNLOCK(); |
| | | return I2C_ERROR_MEMORY; |
| | | } |
| | | if( !addApbChangeCallback( i2c, i2cApbChangeCallback)) { |
| | | log_e("install apb Callback failed"); |
| | | I2C_MUTEX_UNLOCK(); |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | |
| | | } |
| | | //hang until it completes. |
| | | |
| | | // how many ticks should it take to transfer totalBytes through the I2C hardware, |
| | | // add user supplied timeOutMillis to Calculated Value |
| | | |
| | | portTickType ticksTimeOut = ((totalBytes*10*1000)/(i2cGetFrequency(i2c))+timeOutMillis)/portTICK_PERIOD_MS; |
| | | |
| | | i2c->dev->ctr.trans_start=1; // go for it |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR |
| | | portTickType tBefore=xTaskGetTickCount(); |
| | | #endif |
| | | |
| | | // wait for ISR to complete the transfer, or until timeOut in case of bus fault, hardware problem |
| | | |
| | | uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut); |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR |
| | | portTickType tAfter=xTaskGetTickCount(); |
| | | #endif |
| | | |
| | | |
| | | // if xEventGroupSetBitsFromISR() failed, the ISR could have succeeded but never been |
| | | // able to mark the success |
| | | |
| | | if(i2c->exitCode!=eBits) { // try to recover from O/S failure |
| | | // log_e("EventGroup Failed:%p!=%p",eBits,i2c->exitCode); |
| | | eBits=i2c->exitCode; |
| | | } |
| | | if((eBits&EVENT_ERROR)||(!(eBits & EVENT_DONE))){ // need accurate errorByteCnt for debug |
| | | i2c_update_error_byte_cnt(i2c); |
| | | } |
| | | |
| | | if(!(eBits==EVENT_DONE)&&(eBits&~(EVENT_ERROR_NAK|EVENT_ERROR_DATA_NAK|EVENT_ERROR|EVENT_DONE))) { // not only Done, therefore error, exclude ADDR NAK, DATA_NAK |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO |
| | | i2cDumpI2c(i2c); |
| | | i2cDumpInts(i2c->num); |
| | | #endif |
| | | } |
| | | |
| | | if(eBits&EVENT_DONE) { // no gross timeout |
| | | switch(i2c->error) { |
| | | case I2C_OK : |
| | | reason = I2C_ERROR_OK; |
| | | break; |
| | | case I2C_ERROR : |
| | | reason = I2C_ERROR_DEV; |
| | | break; |
| | | case I2C_ADDR_NAK: |
| | | reason = I2C_ERROR_ACK; |
| | | break; |
| | | case I2C_DATA_NAK: |
| | | reason = I2C_ERROR_ACK; |
| | | break; |
| | | case I2C_ARBITRATION: |
| | | reason = I2C_ERROR_BUS; |
| | | break; |
| | | case I2C_TIMEOUT: |
| | | reason = I2C_ERROR_TIMEOUT; |
| | | break; |
| | | default : |
| | | reason = I2C_ERROR_DEV; |
| | | } |
| | | } else { // GROSS timeout, shutdown ISR , report Timeout |
| | | i2c->stage = I2C_DONE; |
| | | i2c->dev->int_ena.val =0; |
| | | i2c->dev->int_clr.val = 0x1FFF; |
| | | i2c_update_error_byte_cnt(i2c); |
| | | if((i2c->errorByteCnt == 0)&&(i2c->errorQueue==0)) { // Bus Busy no bytes Moved |
| | | reason = I2C_ERROR_BUSY; |
| | | eBits = eBits | EVENT_ERROR_BUS_BUSY|EVENT_ERROR|EVENT_DONE; |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG |
| | | log_d(" Busy Timeout start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error); |
| | | i2cDumpI2c(i2c); |
| | | i2cDumpInts(i2c->num); |
| | | #endif |
| | | } else { // just a timeout, some data made it out or in. |
| | | reason = I2C_ERROR_TIMEOUT; |
| | | eBits = eBits | EVENT_ERROR_TIMEOUT|EVENT_ERROR|EVENT_DONE; |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG |
| | | log_d(" Gross Timeout Dead start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error); |
| | | i2cDumpI2c(i2c); |
| | | i2cDumpInts(i2c->num); |
| | | #endif |
| | | } |
| | | } |
| | | |
| | | /* offloading all EventGroups to dispatch, EventGroups in ISR is not always successful |
| | | 11/20/2017 |
| | | if error, need to trigger all succeeding dataQueue events with the EVENT_ERROR_PREV |
| | | 07/22/2018 |
| | | Need to use the queueEvent value to identify transaction blocks, if an error occurs, |
| | | all subsequent queue items with the same queueEvent value will receive the EVENT_ERROR_PREV. |
| | | But, ProcQue should re-queue queue items that have a different queueEvent value(different transaction) |
| | | This change will support multi-thread i2c usage. Use the queueEvent as the transaction event |
| | | identifier. |
| | | */ |
| | | uint32_t b = 0; |
| | | |
| | | while(b < i2c->queueCount) { |
| | | if(i2c->dq[b].ctrl.mode==1 && readCount) { |
| | | *readCount += i2c->dq[b].position; // number of data bytes received |
| | | } |
| | | if(b < i2c->queuePos) { // before any error |
| | | if(i2c->dq[b].queueEvent) { // this data queue element has an EventGroup |
| | | xEventGroupSetBits(i2c->dq[b].queueEvent,EVENT_DONE); |
| | | } |
| | | } else if(b == i2c->queuePos) { // last processed queue |
| | | if(i2c->dq[b].queueEvent) { // this data queue element has an EventGroup |
| | | xEventGroupSetBits(i2c->dq[b].queueEvent,eBits); |
| | | } |
| | | } else { // never processed queues |
| | | if(i2c->dq[b].queueEvent) { // this data queue element has an EventGroup |
| | | xEventGroupSetBits(i2c->dq[b].queueEvent,eBits|EVENT_ERROR_PREV); |
| | | } |
| | | } |
| | | b++; |
| | | } |
| | | if(i2c->debugFlags & 0x00ff0000) i2cTriggerDumps(i2c,(i2c->debugFlags>>16),"after ProcQueue"); |
| | | |
| | | I2C_MUTEX_UNLOCK(); |
| | | return reason; |
| | | } |
| | | |
| | | static void i2cReleaseISR(i2c_t * i2c) |
| | | { |
| | | if(i2c->intr_handle) { |
| | | esp_intr_free(i2c->intr_handle); |
| | | i2c->intr_handle=NULL; |
| | | if (!removeApbChangeCallback( i2c, i2cApbChangeCallback)) { |
| | | log_e("unable to release apbCallback"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static bool i2cCheckLineState(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 |
| | | digitalWrite(sda, HIGH); |
| | | digitalWrite(scl, HIGH); |
| | | pinMode(sda, PULLUP|OPEN_DRAIN|INPUT); |
| | | pinMode(scl, PULLUP|OPEN_DRAIN|OUTPUT); |
| | | |
| | | if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state |
| | | log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, digitalRead(sda), scl, digitalRead(scl)); |
| | | digitalWrite(scl, HIGH); |
| | | for(uint8_t a=0; a<9; a++) { |
| | | delayMicroseconds(5); |
| | | digitalWrite(scl, LOW); |
| | | delayMicroseconds(5); |
| | | digitalWrite(scl, HIGH); |
| | | if(digitalRead(sda)){ // bus recovered |
| | | log_d("Recovered after %d Cycles",a+1); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state |
| | | log_e("Bus Invalid State, TwoWire() Can't init sda=%d, scl=%d",digitalRead(sda),digitalRead(scl)); |
| | | return false; // bus is busy |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl) |
| | | { |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | digitalWrite(scl, HIGH); |
| | | pinMode(scl, OPEN_DRAIN | PULLUP | INPUT | OUTPUT); |
| | | pinMatrixOutAttach(scl, I2C_SCL_IDX(i2c->num), false, false); |
| | | pinMatrixInAttach(scl, I2C_SCL_IDX(i2c->num), false); |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl) |
| | | { |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | pinMatrixOutDetach(scl, false, false); |
| | | pinMatrixInDetach(I2C_SCL_IDX(i2c->num), false, false); |
| | | pinMode(scl, INPUT | PULLUP); |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda) |
| | | { |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | digitalWrite(sda, HIGH); |
| | | pinMode(sda, OPEN_DRAIN | PULLUP | INPUT | OUTPUT ); |
| | | pinMatrixOutAttach(sda, I2C_SDA_IDX(i2c->num), false, false); |
| | | pinMatrixInAttach(sda, I2C_SDA_IDX(i2c->num), false); |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda) |
| | | { |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | pinMatrixOutDetach(sda, false, false); |
| | | pinMatrixInDetach(I2C_SDA_IDX(i2c->num), false, false); |
| | | pinMode(sda, INPUT | PULLUP); |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | /* |
| | | * PUBLIC API |
| | | * */ |
| | | // 24Nov17 only supports Master Mode |
| | | i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) { |
| | | #ifdef ENABLE_I2C_DEBUG_BUFFER |
| | | log_v("num=%d sda=%d scl=%d freq=%d",i2c_num, sda, scl, frequency); |
| | | #endif |
| | | if(i2c_num > 1) { |
| | | return NULL; |
| | | } |
| | | |
| | | i2c_t * i2c = &_i2c_bus_array[i2c_num]; |
| | | |
| | | // pins should be detached, else glitch |
| | | if(i2c->sda >= 0){ |
| | | i2cDetachSDA(i2c, i2c->sda); |
| | | } |
| | | if(i2c->scl >= 0){ |
| | | i2cDetachSCL(i2c, i2c->scl); |
| | | } |
| | | i2c->sda = sda; |
| | | i2c->scl = scl; |
| | | |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(i2c->lock == NULL) { |
| | | i2c->lock = xSemaphoreCreateRecursiveMutex(); |
| | | if(i2c->lock == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | #endif |
| | | I2C_MUTEX_LOCK(); |
| | | |
| | | i2cReleaseISR(i2c); // ISR exists, release it before disabling hardware |
| | | |
| | | if(frequency == 0) {// don't change existing frequency |
| | | frequency = i2cGetFrequency(i2c); |
| | | if(frequency == 0) { |
| | | frequency = 100000L; // default to 100khz |
| | | } |
| | | } |
| | | |
| | | if(i2c_num == 0) { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST);// release reset |
| | | } else { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); |
| | | } |
| | | i2c->dev->ctr.val = 0; |
| | | i2c->dev->ctr.ms_mode = 1; |
| | | i2c->dev->ctr.sda_force_out = 1 ; |
| | | i2c->dev->ctr.scl_force_out = 1 ; |
| | | i2c->dev->ctr.clk_en = 1; |
| | | |
| | | //the max clock number of receiving a data |
| | | i2c->dev->timeout.tout = 400000;//clocks max=1048575 |
| | | //disable apb nonfifo access |
| | | i2c->dev->fifo_conf.nonfifo_en = 0; |
| | | |
| | | i2c->dev->slave_addr.val = 0; |
| | | I2C_MUTEX_UNLOCK(); |
| | | |
| | | i2cSetFrequency(i2c, frequency); // reconfigure |
| | | |
| | | if(!i2cCheckLineState(i2c->sda, i2c->scl)){ |
| | | return NULL; |
| | | } |
| | | |
| | | if(i2c->sda >= 0){ |
| | | i2cAttachSDA(i2c, i2c->sda); |
| | | } |
| | | if(i2c->scl >= 0){ |
| | | i2cAttachSCL(i2c, i2c->scl); |
| | | } |
| | | return i2c; |
| | | } |
| | | |
| | | void i2cRelease(i2c_t *i2c) // release all resources, power down peripheral |
| | | { |
| | | I2C_MUTEX_LOCK(); |
| | | |
| | | if(i2c->sda >= 0){ |
| | | i2cDetachSDA(i2c, i2c->sda); |
| | | } |
| | | if(i2c->scl >= 0){ |
| | | i2cDetachSCL(i2c, i2c->scl); |
| | | } |
| | | |
| | | i2cReleaseISR(i2c); |
| | | |
| | | if(i2c->i2c_event) { |
| | | vEventGroupDelete(i2c->i2c_event); |
| | | i2c->i2c_event = NULL; |
| | | } |
| | | |
| | | i2cFlush(i2c); |
| | | |
| | | // reset the I2C hardware and shut off the clock, power it down. |
| | | if(i2c->num == 0) { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT0_RST); //reset hardware |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT0_CLK_EN); // shutdown hardware |
| | | } else { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,DPORT_I2C_EXT1_RST); //reset Hardware |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG,DPORT_I2C_EXT1_CLK_EN); // shutdown Hardware |
| | | } |
| | | |
| | | I2C_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | i2c_err_t i2cFlush(i2c_t * i2c) |
| | | { |
| | | if(i2c==NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | i2cTriggerDumps(i2c,i2c->debugFlags & 0xff, "FLUSH"); |
| | | |
| | | // need to grab a MUTEX for exclusive Queue, |
| | | // what out if ISR is running? |
| | | i2c_err_t rc=I2C_ERROR_OK; |
| | | if(i2c->dq!=NULL) { |
| | | // log_i("free"); |
| | | // what about EventHandle? |
| | | free(i2c->dq); |
| | | i2c->dq = NULL; |
| | | } |
| | | i2c->queueCount=0; |
| | | i2c->queuePos=0; |
| | | // release Mutex |
| | | return rc; |
| | | } |
| | | |
| | | i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis){ |
| | | if((i2c==NULL)||((size>0)&&(buff==NULL))) { // need to have location to store requested data |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | i2c_err_t last_error = i2cAddQueueWrite(i2c, address, buff, size, sendStop, NULL); |
| | | |
| | | if(last_error == I2C_ERROR_OK) { //queued |
| | | if(sendStop) { //now actually process the queued commands, including READs |
| | | last_error = i2cProcQueue(i2c, NULL, timeOutMillis); |
| | | if(last_error == I2C_ERROR_BUSY) { // try to clear the bus |
| | | if(i2cInit(i2c->num, i2c->sda, i2c->scl, 0)) { |
| | | last_error = i2cProcQueue(i2c, NULL, timeOutMillis); |
| | | } |
| | | } |
| | | i2cFlush(i2c); |
| | | } else { // stop not received, so wait for I2C stop, |
| | | last_error = I2C_ERROR_CONTINUE; |
| | | } |
| | | } |
| | | return last_error; |
| | | } |
| | | |
| | | i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount){ |
| | | if((size == 0)||(i2c == NULL)||(buff==NULL)){ // hardware will hang if no data requested on READ |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | i2c_err_t last_error=i2cAddQueueRead(i2c, address, buff, size, sendStop, NULL); |
| | | |
| | | if(last_error == I2C_ERROR_OK) { //queued |
| | | if(sendStop) { //now actually process the queued commands, including READs |
| | | last_error = i2cProcQueue(i2c, readCount, timeOutMillis); |
| | | if(last_error == I2C_ERROR_BUSY) { // try to clear the bus |
| | | if(i2cInit(i2c->num, i2c->sda, i2c->scl, 0)) { |
| | | last_error = i2cProcQueue(i2c, readCount, timeOutMillis); |
| | | } |
| | | } |
| | | i2cFlush(i2c); |
| | | } else { // stop not received, so wait for I2C stop, |
| | | last_error = I2C_ERROR_CONTINUE; |
| | | } |
| | | } |
| | | return last_error; |
| | | } |
| | | |
| | | #define MIN_I2C_CLKS 100 // minimum ratio between cpu and i2c Bus clocks |
| | | #define INTERRUPT_CYCLE_OVERHEAD 16000 // number of cpu clocks necessary to respond to interrupt |
| | | i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed) |
| | | { |
| | | if(i2c == NULL) { |
| | | return I2C_ERROR_DEV; |
| | | } |
| | | uint32_t apb = getApbFrequency(); |
| | | uint32_t period = (apb/clk_speed) / 2; |
| | | |
| | | if((apb/8192 > clk_speed)||(apb/MIN_I2C_CLKS < clk_speed)){ //out of bounds |
| | | log_d("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d",clk_speed,apb,(apb/8192),(apb/MIN_I2C_CLKS)); |
| | | } |
| | | if(period < (MIN_I2C_CLKS/2) ){ |
| | | period = (MIN_I2C_CLKS/2); |
| | | clk_speed = apb/(period*2); |
| | | log_d("APB Freq too slow, Reducing i2c Freq to %d Hz",clk_speed); |
| | | } else if ( period> 4095) { |
| | | period = 4095; |
| | | clk_speed = apb/(period*2); |
| | | log_d("APB Freq too fast, Increasing i2c Freq to %d Hz",clk_speed); |
| | | } |
| | | #ifdef ENABLE_I2C_DEBUG_BUFFER |
| | | log_v("freq=%dHz",clk_speed); |
| | | #endif |
| | | uint32_t halfPeriod = period/2; |
| | | uint32_t quarterPeriod = period/4; |
| | | |
| | | I2C_MUTEX_LOCK(); |
| | | |
| | | I2C_FIFO_CONF_t f; |
| | | |
| | | f.val = i2c->dev->fifo_conf.val; |
| | | /* Adjust Fifo thresholds based on differential between cpu frequency and bus clock. |
| | | The fifo_delta is calculated such that at least INTERRUPT_CYCLE_OVERHEAD cpu clocks are |
| | | available when a Fifo interrupt is triggered. This allows enough room in the Fifo so that |
| | | interrupt latency does not cause a Fifo overflow/underflow event. |
| | | */ |
| | | #ifdef ENABLE_I2C_DEBUG_BUFFER |
| | | log_v("cpu Freq=%dMhz, i2c Freq=%dHz",getCpuFrequencyMhz(),clk_speed); |
| | | #endif |
| | | uint32_t fifo_delta = (INTERRUPT_CYCLE_OVERHEAD/((getCpuFrequencyMhz()*1000000 / clk_speed)*10))+1; |
| | | if (fifo_delta > 24) fifo_delta=24; |
| | | f.rx_fifo_full_thrhd = 32 - fifo_delta; |
| | | f.tx_fifo_empty_thrhd = fifo_delta; |
| | | i2c->dev->fifo_conf.val = f.val; // set thresholds |
| | | #ifdef ENABLE_I2C_DEBUG_BUFFER |
| | | log_v("Fifo delta=%d",fifo_delta); |
| | | #endif |
| | | //the clock num during SCL is low level |
| | | i2c->dev->scl_low_period.period = period; |
| | | //the clock num during SCL is high level |
| | | i2c->dev->scl_high_period.period = period; |
| | | |
| | | //the clock num between the negedge of SDA and negedge of SCL for start mark |
| | | i2c->dev->scl_start_hold.time = halfPeriod; |
| | | //the clock num between the posedge of SCL and the negedge of SDA for restart mark |
| | | i2c->dev->scl_rstart_setup.time = halfPeriod; |
| | | |
| | | //the clock num after the STOP bit's posedge |
| | | i2c->dev->scl_stop_hold.time = halfPeriod; |
| | | //the clock num between the posedge of SCL and the posedge of SDA |
| | | i2c->dev->scl_stop_setup.time = halfPeriod; |
| | | |
| | | //the clock num I2C used to hold the data after the negedge of SCL. |
| | | i2c->dev->sda_hold.time = quarterPeriod; |
| | | //the clock num I2C used to sample data on SDA after the posedge of SCL |
| | | i2c->dev->sda_sample.time = quarterPeriod; |
| | | I2C_MUTEX_UNLOCK(); |
| | | return I2C_ERROR_OK; |
| | | } |
| | | |
| | | uint32_t i2cGetFrequency(i2c_t * i2c) |
| | | { |
| | | if(i2c == NULL) { |
| | | return 0; |
| | | } |
| | | uint32_t result = 0; |
| | | uint32_t old_count = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period); |
| | | if(old_count>0) { |
| | | result = getApbFrequency() / old_count; |
| | | } else { |
| | | result = 0; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | uint32_t i2cDebug(i2c_t * i2c, uint32_t setBits, uint32_t resetBits){ |
| | | if(i2c != NULL) { |
| | | i2c->debugFlags = ((i2c->debugFlags | setBits) & ~resetBits); |
| | | return i2c->debugFlags; |
| | | } |
| | | return 0; |
| | | |
| | | } |
| | | |
| | | uint32_t i2cGetStatus(i2c_t * i2c){ |
| | | if(i2c != NULL){ |
| | | return i2c->dev->status_reg.val; |
| | | } |
| | | else return 0; |
| | | } |
| | | |
| | | |
| | | /* todo |
| | | 22JUL18 |
| | | need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads |
| | | transactions are present in the same queue, and an error occurs, abort all succeeding unserviced transactions |
| | | with the same dq.queueEvent value. Succeeding unserviced transactions with different dq.queueEvent values |
| | | can be re-queued and processed independently. |
| | | 30JUL18 complete data only queue elements, this will allow transfers to use multiple data blocks, |
| | | */ |
| | | |
| New file |
| | |
| | | // 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. |
| | | // modified Nov 2017 by Chuck Todd <StickBreaker> to support Interrupt Driven I/O |
| | | |
| | | #ifndef _ESP32_HAL_I2C_H_ |
| | | #define _ESP32_HAL_I2C_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/event_groups.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 |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_HAL_I2C_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/semphr.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp32-hal-matrix.h" |
| | | #include "soc/dport_reg.h" |
| | | #include "soc/ledc_reg.h" |
| | | #include "soc/ledc_struct.h" |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | #define LEDC_MUTEX_LOCK() |
| | | #define LEDC_MUTEX_UNLOCK() |
| | | #else |
| | | #define LEDC_MUTEX_LOCK() do {} while (xSemaphoreTake(_ledc_sys_lock, portMAX_DELAY) != pdPASS) |
| | | #define LEDC_MUTEX_UNLOCK() xSemaphoreGive(_ledc_sys_lock) |
| | | xSemaphoreHandle _ledc_sys_lock; |
| | | #endif |
| | | |
| | | /* |
| | | * LEDC Chan to Group/Channel/Timer Mapping |
| | | ** ledc: 0 => Group: 0, Channel: 0, Timer: 0 |
| | | ** ledc: 1 => Group: 0, Channel: 1, Timer: 0 |
| | | ** ledc: 2 => Group: 0, Channel: 2, Timer: 1 |
| | | ** ledc: 3 => Group: 0, Channel: 3, Timer: 1 |
| | | ** ledc: 4 => Group: 0, Channel: 4, Timer: 2 |
| | | ** ledc: 5 => Group: 0, Channel: 5, Timer: 2 |
| | | ** ledc: 6 => Group: 0, Channel: 6, Timer: 3 |
| | | ** ledc: 7 => Group: 0, Channel: 7, Timer: 3 |
| | | ** ledc: 8 => Group: 1, Channel: 0, Timer: 0 |
| | | ** ledc: 9 => Group: 1, Channel: 1, Timer: 0 |
| | | ** ledc: 10 => Group: 1, Channel: 2, Timer: 1 |
| | | ** ledc: 11 => Group: 1, Channel: 3, Timer: 1 |
| | | ** ledc: 12 => Group: 1, Channel: 4, Timer: 2 |
| | | ** ledc: 13 => Group: 1, Channel: 5, Timer: 2 |
| | | ** ledc: 14 => Group: 1, Channel: 6, Timer: 3 |
| | | ** ledc: 15 => Group: 1, Channel: 7, Timer: 3 |
| | | */ |
| | | #define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)] |
| | | #define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)] |
| | | |
| | | static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
| | | if(ev_type == APB_AFTER_CHANGE && old_apb != new_apb){ |
| | | uint32_t iarg = (uint32_t)arg; |
| | | uint8_t chan = iarg; |
| | | uint8_t group=(chan/8), timer=((chan/2)%4); |
| | | old_apb /= 1000000; |
| | | new_apb /= 1000000; |
| | | if(LEDC_TIMER(group, timer).conf.tick_sel){ |
| | | LEDC_MUTEX_LOCK(); |
| | | uint32_t old_div = LEDC_TIMER(group, timer).conf.clock_divider; |
| | | uint32_t div_num = (new_apb * old_div) / old_apb; |
| | | if(div_num > LEDC_DIV_NUM_HSTIMER0_V){ |
| | | new_apb = REF_CLK_FREQ / 1000000; |
| | | div_num = (new_apb * old_div) / old_apb; |
| | | if(div_num > LEDC_DIV_NUM_HSTIMER0_V) { |
| | | div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible |
| | | } |
| | | LEDC_TIMER(group, timer).conf.tick_sel = 0; |
| | | } else if(div_num < 256) { |
| | | div_num = 256;//highest clock possible |
| | | } |
| | | LEDC_TIMER(group, timer).conf.clock_divider = div_num; |
| | | LEDC_MUTEX_UNLOCK(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num)); |
| | | static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk) |
| | | { |
| | | uint8_t group=(chan/8), timer=((chan/2)%4); |
| | | static bool tHasStarted = false; |
| | | if(!tHasStarted) { |
| | | tHasStarted = true; |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST); |
| | | LEDC.conf.apb_clk_sel = 1;//LS use apb clock |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | _ledc_sys_lock = xSemaphoreCreateMutex(); |
| | | #endif |
| | | } |
| | | LEDC_MUTEX_LOCK(); |
| | | LEDC_TIMER(group, timer).conf.clock_divider = div_num;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part. |
| | | LEDC_TIMER(group, timer).conf.duty_resolution = bit_num;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20. |
| | | LEDC_TIMER(group, timer).conf.tick_sel = apb_clk;//apb clock |
| | | if(group) { |
| | | LEDC_TIMER(group, timer).conf.low_speed_update = 1;//This bit is only useful for low speed timer channels, reserved for high speed timers |
| | | } |
| | | LEDC_TIMER(group, timer).conf.pause = 0; |
| | | LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset. |
| | | LEDC_TIMER(group, timer).conf.rst = 0; |
| | | LEDC_MUTEX_UNLOCK(); |
| | | uint32_t iarg = chan; |
| | | addApbChangeCallback((void*)iarg, _on_apb_change); |
| | | } |
| | | |
| | | //max div_num 0x3FFFF (262143) |
| | | //max bit_num 0x1F (31) |
| | | static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num) |
| | | { |
| | | uint64_t clk_freq = getApbFrequency(); |
| | | clk_freq <<= 8;//div_num is 8 bit decimal |
| | | uint32_t div_num = (clk_freq >> bit_num) / freq; |
| | | bool apb_clk = true; |
| | | if(div_num > LEDC_DIV_NUM_HSTIMER0_V) { |
| | | clk_freq /= 80; |
| | | div_num = (clk_freq >> bit_num) / freq; |
| | | if(div_num > LEDC_DIV_NUM_HSTIMER0_V) { |
| | | div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible |
| | | } |
| | | apb_clk = false; |
| | | } else if(div_num < 256) { |
| | | div_num = 256;//highest clock possible |
| | | } |
| | | _ledcSetupTimer(chan, div_num, bit_num, apb_clk); |
| | | //log_i("Fin: %f, Fclk: %uMhz, bits: %u, DIV: %u, Fout: %f", |
| | | // freq, apb_clk?80:1, bit_num, div_num, (clk_freq >> bit_num) / (double)div_num); |
| | | return (clk_freq >> bit_num) / (double)div_num; |
| | | } |
| | | |
| | | static double _ledcTimerRead(uint8_t chan) |
| | | { |
| | | uint32_t div_num; |
| | | uint8_t bit_num; |
| | | bool apb_clk; |
| | | uint8_t group=(chan/8), timer=((chan/2)%4); |
| | | LEDC_MUTEX_LOCK(); |
| | | div_num = LEDC_TIMER(group, timer).conf.clock_divider;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part. |
| | | bit_num = LEDC_TIMER(group, timer).conf.duty_resolution;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20. |
| | | apb_clk = LEDC_TIMER(group, timer).conf.tick_sel;//apb clock |
| | | LEDC_MUTEX_UNLOCK(); |
| | | uint64_t clk_freq = 1000000; |
| | | if(apb_clk) { |
| | | clk_freq = getApbFrequency(); |
| | | } |
| | | clk_freq <<= 8;//div_num is 8 bit decimal |
| | | return (clk_freq >> bit_num) / (double)div_num; |
| | | } |
| | | |
| | | static void _ledcSetupChannel(uint8_t chan, uint8_t idle_level) |
| | | { |
| | | uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4); |
| | | LEDC_MUTEX_LOCK(); |
| | | LEDC_CHAN(group, channel).conf0.timer_sel = timer;//2 bit Selects the timer to attach 0-3 |
| | | LEDC_CHAN(group, channel).conf0.idle_lv = idle_level;//1 bit This bit is used to control the output value when channel is off. |
| | | LEDC_CHAN(group, channel).hpoint.hpoint = 0;//20 bit The output value changes to high when timer selected by channel has reached hpoint |
| | | LEDC_CHAN(group, channel).conf1.duty_inc = 1;//1 bit This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel |
| | | LEDC_CHAN(group, channel).conf1.duty_num = 1;//10 bit This register is used to control the number of increased or decreased times for channel |
| | | LEDC_CHAN(group, channel).conf1.duty_cycle = 1;//10 bit This register is used to increase or decrease the duty every duty_cycle cycles for channel |
| | | LEDC_CHAN(group, channel).conf1.duty_scale = 0;//10 bit This register controls the increase or decrease step scale for channel. |
| | | LEDC_CHAN(group, channel).duty.duty = 0; |
| | | LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel |
| | | LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware. |
| | | if(group) { |
| | | LEDC_CHAN(group, channel).conf0.low_speed_update = 1; |
| | | } else { |
| | | LEDC_CHAN(group, channel).conf0.clk_en = 0; |
| | | } |
| | | LEDC_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) |
| | | { |
| | | if(chan > 15) { |
| | | return 0; |
| | | } |
| | | double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num); |
| | | _ledcSetupChannel(chan, LOW); |
| | | return res_freq; |
| | | } |
| | | |
| | | void ledcWrite(uint8_t chan, uint32_t duty) |
| | | { |
| | | if(chan > 15) { |
| | | return; |
| | | } |
| | | uint8_t group=(chan/8), channel=(chan%8); |
| | | LEDC_MUTEX_LOCK(); |
| | | LEDC_CHAN(group, channel).duty.duty = duty << 4;//25 bit (21.4) |
| | | if(duty) { |
| | | LEDC_CHAN(group, channel).conf0.sig_out_en = 1;//This is the output enable control bit for channel |
| | | LEDC_CHAN(group, channel).conf1.duty_start = 1;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware. |
| | | if(group) { |
| | | LEDC_CHAN(group, channel).conf0.low_speed_update = 1; |
| | | } else { |
| | | LEDC_CHAN(group, channel).conf0.clk_en = 1; |
| | | } |
| | | } else { |
| | | LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel |
| | | LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware. |
| | | if(group) { |
| | | LEDC_CHAN(group, channel).conf0.low_speed_update = 1; |
| | | } else { |
| | | LEDC_CHAN(group, channel).conf0.clk_en = 0; |
| | | } |
| | | } |
| | | LEDC_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint32_t ledcRead(uint8_t chan) |
| | | { |
| | | if(chan > 15) { |
| | | return 0; |
| | | } |
| | | return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4; |
| | | } |
| | | |
| | | double ledcReadFreq(uint8_t chan) |
| | | { |
| | | if(!ledcRead(chan)){ |
| | | return 0; |
| | | } |
| | | return _ledcTimerRead(chan); |
| | | } |
| | | |
| | | double ledcWriteTone(uint8_t chan, double freq) |
| | | { |
| | | if(chan > 15) { |
| | | return 0; |
| | | } |
| | | if(!freq) { |
| | | ledcWrite(chan, 0); |
| | | return 0; |
| | | } |
| | | double res_freq = _ledcSetupTimerFreq(chan, freq, 10); |
| | | ledcWrite(chan, 0x1FF); |
| | | return res_freq; |
| | | } |
| | | |
| | | double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){ |
| | | const uint16_t noteFrequencyBase[12] = { |
| | | // C C# D Eb E F F# G G# A Bb B |
| | | 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 |
| | | }; |
| | | |
| | | if(octave > 8 || note >= NOTE_MAX){ |
| | | return 0; |
| | | } |
| | | double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave)); |
| | | return ledcWriteTone(chan, noteFreq); |
| | | } |
| | | |
| | | void ledcAttachPin(uint8_t pin, uint8_t chan) |
| | | { |
| | | if(chan > 15) { |
| | | return; |
| | | } |
| | | pinMode(pin, OUTPUT); |
| | | pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false); |
| | | } |
| | | |
| | | void ledcDetachPin(uint8_t pin) |
| | | { |
| | | pinMatrixOutDetach(pin, false, false); |
| | | } |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_HAL_LEDC_H_ |
| | | #define _ESP32_HAL_LEDC_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | |
| | | typedef enum { |
| | | NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX |
| | | } note_t; |
| | | |
| | | //channel 0-15 resolution 1-16bits freq limits depend on resolution |
| | | double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits); |
| | | void ledcWrite(uint8_t channel, uint32_t duty); |
| | | double ledcWriteTone(uint8_t channel, double freq); |
| | | double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave); |
| | | uint32_t ledcRead(uint8_t channel); |
| | | double ledcReadFreq(uint8_t channel); |
| | | void ledcAttachPin(uint8_t pin, uint8_t channel); |
| | | void ledcDetachPin(uint8_t pin); |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_HAL_LEDC_H_ */ |
| New file |
| | |
| | | // 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. |
| | | #ifndef __ARDUHAL_LOG_H__ |
| | | #define __ARDUHAL_LOG_H__ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" |
| | | { |
| | | #endif |
| | | |
| | | #include "sdkconfig.h" |
| | | |
| | | #define ARDUHAL_LOG_LEVEL_NONE (0) |
| | | #define ARDUHAL_LOG_LEVEL_ERROR (1) |
| | | #define ARDUHAL_LOG_LEVEL_WARN (2) |
| | | #define ARDUHAL_LOG_LEVEL_INFO (3) |
| | | #define ARDUHAL_LOG_LEVEL_DEBUG (4) |
| | | #define ARDUHAL_LOG_LEVEL_VERBOSE (5) |
| | | |
| | | #ifndef CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL |
| | | #define CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL ARDUHAL_LOG_LEVEL_NONE |
| | | #endif |
| | | |
| | | #ifndef CORE_DEBUG_LEVEL |
| | | #define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL |
| | | #else |
| | | #define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL |
| | | #endif |
| | | |
| | | #ifndef CONFIG_ARDUHAL_LOG_COLORS |
| | | #define CONFIG_ARDUHAL_LOG_COLORS 0 |
| | | #endif |
| | | |
| | | #if CONFIG_ARDUHAL_LOG_COLORS |
| | | #define ARDUHAL_LOG_COLOR_BLACK "30" |
| | | #define ARDUHAL_LOG_COLOR_RED "31" //ERROR |
| | | #define ARDUHAL_LOG_COLOR_GREEN "32" //INFO |
| | | #define ARDUHAL_LOG_COLOR_YELLOW "33" //WARNING |
| | | #define ARDUHAL_LOG_COLOR_BLUE "34" |
| | | #define ARDUHAL_LOG_COLOR_MAGENTA "35" |
| | | #define ARDUHAL_LOG_COLOR_CYAN "36" //DEBUG |
| | | #define ARDUHAL_LOG_COLOR_GRAY "37" //VERBOSE |
| | | #define ARDUHAL_LOG_COLOR_WHITE "38" |
| | | |
| | | #define ARDUHAL_LOG_COLOR(COLOR) "\033[0;" COLOR "m" |
| | | #define ARDUHAL_LOG_BOLD(COLOR) "\033[1;" COLOR "m" |
| | | #define ARDUHAL_LOG_RESET_COLOR "\033[0m" |
| | | |
| | | #define ARDUHAL_LOG_COLOR_E ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_RED) |
| | | #define ARDUHAL_LOG_COLOR_W ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_YELLOW) |
| | | #define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN) |
| | | #define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN) |
| | | #define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY) |
| | | #else |
| | | #define ARDUHAL_LOG_COLOR_E |
| | | #define ARDUHAL_LOG_COLOR_W |
| | | #define ARDUHAL_LOG_COLOR_I |
| | | #define ARDUHAL_LOG_COLOR_D |
| | | #define ARDUHAL_LOG_COLOR_V |
| | | #define ARDUHAL_LOG_RESET_COLOR |
| | | #endif |
| | | |
| | | const char * pathToFileName(const char * path); |
| | | int log_printf(const char *fmt, ...); |
| | | |
| | | #define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n" |
| | | #define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", pathToFileName(__FILE__), __LINE__, __FUNCTION__ |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE |
| | | #define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) |
| | | #define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_v(format, ...) |
| | | #define isr_log_v(format, ...) |
| | | #endif |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG |
| | | #define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) |
| | | #define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_d(format, ...) |
| | | #define isr_log_d(format, ...) |
| | | #endif |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO |
| | | #define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) |
| | | #define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_i(format, ...) |
| | | #define isr_log_i(format, ...) |
| | | #endif |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN |
| | | #define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) |
| | | #define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_w(format, ...) |
| | | #define isr_log_w(format, ...) |
| | | #endif |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR |
| | | #define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) |
| | | #define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_e(format, ...) |
| | | #define isr_log_e(format, ...) |
| | | #endif |
| | | |
| | | #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE |
| | | #define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) |
| | | #define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) |
| | | #else |
| | | #define log_n(format, ...) |
| | | #define isr_log_n(format, ...) |
| | | #endif |
| | | |
| | | #include "esp_log.h" |
| | | |
| | | #ifdef CONFIG_ARDUHAL_ESP_LOG |
| | | #undef ESP_LOGE |
| | | #undef ESP_LOGW |
| | | #undef ESP_LOGI |
| | | #undef ESP_LOGD |
| | | #undef ESP_LOGV |
| | | #undef ESP_EARLY_LOGE |
| | | #undef ESP_EARLY_LOGW |
| | | #undef ESP_EARLY_LOGI |
| | | #undef ESP_EARLY_LOGD |
| | | #undef ESP_EARLY_LOGV |
| | | |
| | | #define ESP_LOGE(tag, ...) log_e(__VA_ARGS__) |
| | | #define ESP_LOGW(tag, ...) log_w(__VA_ARGS__) |
| | | #define ESP_LOGI(tag, ...) log_i(__VA_ARGS__) |
| | | #define ESP_LOGD(tag, ...) log_d(__VA_ARGS__) |
| | | #define ESP_LOGV(tag, ...) log_v(__VA_ARGS__) |
| | | #define ESP_EARLY_LOGE(tag, ...) isr_log_e(__VA_ARGS__) |
| | | #define ESP_EARLY_LOGW(tag, ...) isr_log_w(__VA_ARGS__) |
| | | #define ESP_EARLY_LOGI(tag, ...) isr_log_i(__VA_ARGS__) |
| | | #define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__) |
| | | #define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__) |
| | | #endif |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* __ESP_LOGGING_H__ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-matrix.h" |
| | | #include "esp_attr.h" |
| | | #include "rom/gpio.h" |
| | | |
| | | #define MATRIX_DETACH_OUT_SIG 0x100 |
| | | #define MATRIX_DETACH_IN_LOW_PIN 0x30 |
| | | #define MATRIX_DETACH_IN_LOW_HIGH 0x38 |
| | | |
| | | void IRAM_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable) |
| | | { |
| | | gpio_matrix_out(pin, function, invertOut, invertEnable); |
| | | } |
| | | |
| | | void IRAM_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable) |
| | | { |
| | | gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable); |
| | | } |
| | | |
| | | void IRAM_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted) |
| | | { |
| | | gpio_matrix_in(pin, signal, inverted); |
| | | } |
| | | |
| | | void IRAM_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted) |
| | | { |
| | | gpio_matrix_in(high?MATRIX_DETACH_IN_LOW_HIGH:MATRIX_DETACH_IN_LOW_PIN, signal, inverted); |
| | | } |
| | | /* |
| | | void IRAM_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){ |
| | | intr_matrix_set(PRO_CPU_NUM, source, inum); |
| | | } |
| | | */ |
| | | |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_HAL_MATRIX_H_ |
| | | #define _ESP32_HAL_MATRIX_H_ |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "soc/gpio_sig_map.h" |
| | | |
| | | void pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable); |
| | | void pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable); |
| | | void pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted); |
| | | void pinMatrixInDetach(uint8_t signal, bool high, bool inverted); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* COMPONENTS_ARDUHAL_INCLUDE_ESP32_HAL_MATRIX_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "sdkconfig.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "esp_attr.h" |
| | | #include "nvs_flash.h" |
| | | #include "nvs.h" |
| | | #include "esp_partition.h" |
| | | #include "esp_log.h" |
| | | #include "esp_timer.h" |
| | | #ifdef CONFIG_APP_ROLLBACK_ENABLE |
| | | #include "esp_ota_ops.h" |
| | | #endif //CONFIG_APP_ROLLBACK_ENABLE |
| | | #ifdef CONFIG_BT_ENABLED |
| | | #include "esp_bt.h" |
| | | #endif //CONFIG_BT_ENABLED |
| | | #include <sys/time.h> |
| | | #include "soc/rtc.h" |
| | | #include "soc/rtc_cntl_reg.h" |
| | | #include "soc/apb_ctrl_reg.h" |
| | | #include "rom/rtc.h" |
| | | #include "esp_task_wdt.h" |
| | | #include "esp32-hal.h" |
| | | |
| | | //Undocumented!!! Get chip temperature in Farenheit |
| | | //Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino |
| | | uint8_t temprature_sens_read(); |
| | | |
| | | float temperatureRead() |
| | | { |
| | | return (temprature_sens_read() - 32) / 1.8; |
| | | } |
| | | |
| | | void yield() |
| | | { |
| | | vPortYield(); |
| | | } |
| | | |
| | | #if CONFIG_AUTOSTART_ARDUINO |
| | | |
| | | extern TaskHandle_t loopTaskHandle; |
| | | extern bool loopTaskWDTEnabled; |
| | | |
| | | void enableLoopWDT(){ |
| | | if(loopTaskHandle != NULL){ |
| | | if(esp_task_wdt_add(loopTaskHandle) != ESP_OK){ |
| | | log_e("Failed to add loop task to WDT"); |
| | | } else { |
| | | loopTaskWDTEnabled = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void disableLoopWDT(){ |
| | | if(loopTaskHandle != NULL && loopTaskWDTEnabled){ |
| | | loopTaskWDTEnabled = false; |
| | | if(esp_task_wdt_delete(loopTaskHandle) != ESP_OK){ |
| | | log_e("Failed to remove loop task from WDT"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void feedLoopWDT(){ |
| | | esp_err_t err = esp_task_wdt_reset(); |
| | | if(err != ESP_OK){ |
| | | log_e("Failed to feed WDT! Error: %d", err); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | void enableCore0WDT(){ |
| | | TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); |
| | | if(idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK){ |
| | | log_e("Failed to add Core 0 IDLE task to WDT"); |
| | | } |
| | | } |
| | | |
| | | void disableCore0WDT(){ |
| | | TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); |
| | | if(idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK){ |
| | | log_e("Failed to remove Core 0 IDLE task from WDT"); |
| | | } |
| | | } |
| | | |
| | | #ifndef CONFIG_FREERTOS_UNICORE |
| | | void enableCore1WDT(){ |
| | | TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); |
| | | if(idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK){ |
| | | log_e("Failed to add Core 1 IDLE task to WDT"); |
| | | } |
| | | } |
| | | |
| | | void disableCore1WDT(){ |
| | | TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); |
| | | if(idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK){ |
| | | log_e("Failed to remove Core 1 IDLE task from WDT"); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode, |
| | | const char * const pcName, |
| | | const uint32_t usStackDepth, |
| | | void * const pvParameters, |
| | | UBaseType_t uxPriority, |
| | | TaskHandle_t * const pxCreatedTask, |
| | | const BaseType_t xCoreID ){ |
| | | #ifndef CONFIG_FREERTOS_UNICORE |
| | | if(xCoreID >= 0 && xCoreID < 2) { |
| | | return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); |
| | | } else { |
| | | #endif |
| | | return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); |
| | | #ifndef CONFIG_FREERTOS_UNICORE |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | unsigned long IRAM_ATTR micros() |
| | | { |
| | | return (unsigned long) (esp_timer_get_time()); |
| | | } |
| | | |
| | | unsigned long IRAM_ATTR millis() |
| | | { |
| | | return (unsigned long) (esp_timer_get_time() / 1000ULL); |
| | | } |
| | | |
| | | void delay(uint32_t ms) |
| | | { |
| | | vTaskDelay(ms / portTICK_PERIOD_MS); |
| | | } |
| | | |
| | | void IRAM_ATTR delayMicroseconds(uint32_t us) |
| | | { |
| | | uint32_t m = micros(); |
| | | if(us){ |
| | | uint32_t e = (m + us); |
| | | if(m > e){ //overflow |
| | | while(micros() > e){ |
| | | NOP(); |
| | | } |
| | | } |
| | | while(micros() < e){ |
| | | NOP(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void initVariant() __attribute__((weak)); |
| | | void initVariant() {} |
| | | |
| | | void init() __attribute__((weak)); |
| | | void init() {} |
| | | |
| | | bool verifyOta() __attribute__((weak)); |
| | | bool verifyOta() { return true; } |
| | | |
| | | #ifdef CONFIG_BT_ENABLED |
| | | //overwritten in esp32-hal-bt.c |
| | | bool btInUse() __attribute__((weak)); |
| | | bool btInUse(){ return false; } |
| | | #endif |
| | | |
| | | void initArduino() |
| | | { |
| | | #ifdef CONFIG_APP_ROLLBACK_ENABLE |
| | | const esp_partition_t *running = esp_ota_get_running_partition(); |
| | | esp_ota_img_states_t ota_state; |
| | | if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) { |
| | | if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) { |
| | | if (verifyOta()) { |
| | | esp_ota_mark_app_valid_cancel_rollback(); |
| | | } else { |
| | | log_e("OTA verification failed! Start rollback to the previous version ..."); |
| | | esp_ota_mark_app_invalid_rollback_and_reboot(); |
| | | } |
| | | } |
| | | } |
| | | #endif |
| | | //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) |
| | | //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; |
| | | #ifdef F_CPU |
| | | setCpuFrequencyMhz(F_CPU/1000000); |
| | | #endif |
| | | #if CONFIG_SPIRAM_SUPPORT |
| | | psramInit(); |
| | | #endif |
| | | esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL); |
| | | esp_err_t err = nvs_flash_init(); |
| | | if(err == ESP_ERR_NVS_NO_FREE_PAGES){ |
| | | const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); |
| | | if (partition != NULL) { |
| | | err = esp_partition_erase_range(partition, 0, partition->size); |
| | | if(!err){ |
| | | err = nvs_flash_init(); |
| | | } else { |
| | | log_e("Failed to format the broken NVS partition!"); |
| | | } |
| | | } |
| | | } |
| | | if(err) { |
| | | log_e("Failed to initialize NVS! Error: %u", err); |
| | | } |
| | | #ifdef CONFIG_BT_ENABLED |
| | | if(!btInUse()){ |
| | | esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); |
| | | } |
| | | #endif |
| | | init(); |
| | | initVariant(); |
| | | } |
| | | |
| | | //used by hal log |
| | | const char * IRAM_ATTR pathToFileName(const char * path) |
| | | { |
| | | size_t i = 0; |
| | | size_t pos = 0; |
| | | char * p = (char *)path; |
| | | while(*p){ |
| | | i++; |
| | | if(*p == '/' || *p == '\\'){ |
| | | pos = i; |
| | | } |
| | | p++; |
| | | } |
| | | return path+pos; |
| | | } |
| | | |
| New file |
| | |
| | | |
| | | #include "esp32-hal.h" |
| | | |
| | | #if CONFIG_SPIRAM_SUPPORT |
| | | #include "esp_spiram.h" |
| | | #include "soc/efuse_reg.h" |
| | | #include "esp_heap_caps.h" |
| | | |
| | | static volatile bool spiramDetected = false; |
| | | static volatile bool spiramFailed = false; |
| | | |
| | | bool psramInit(){ |
| | | if (spiramDetected) { |
| | | return true; |
| | | } |
| | | #ifndef CONFIG_SPIRAM_BOOT_INIT |
| | | if (spiramFailed) { |
| | | return false; |
| | | } |
| | | uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); |
| | | uint32_t pkg_ver = chip_ver & 0x7; |
| | | if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { |
| | | spiramFailed = true; |
| | | log_w("PSRAM not supported!"); |
| | | return false; |
| | | } |
| | | esp_spiram_init_cache(); |
| | | if (esp_spiram_init() != ESP_OK) { |
| | | spiramFailed = true; |
| | | log_w("PSRAM init failed!"); |
| | | pinMatrixOutDetach(16, false, false); |
| | | pinMatrixOutDetach(17, false, false); |
| | | return false; |
| | | } |
| | | if (!esp_spiram_test()) { |
| | | spiramFailed = true; |
| | | log_e("PSRAM test failed!"); |
| | | return false; |
| | | } |
| | | if (esp_spiram_add_to_heapalloc() != ESP_OK) { |
| | | spiramFailed = true; |
| | | log_e("PSRAM could not be added to the heap!"); |
| | | return false; |
| | | } |
| | | #endif |
| | | spiramDetected = true; |
| | | log_d("PSRAM enabled"); |
| | | return true; |
| | | } |
| | | |
| | | bool IRAM_ATTR psramFound(){ |
| | | return spiramDetected; |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_malloc(size_t size){ |
| | | if(!spiramDetected){ |
| | | return NULL; |
| | | } |
| | | return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_calloc(size_t n, size_t size){ |
| | | if(!spiramDetected){ |
| | | return NULL; |
| | | } |
| | | return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_realloc(void *ptr, size_t size){ |
| | | if(!spiramDetected){ |
| | | return NULL; |
| | | } |
| | | return heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); |
| | | } |
| | | |
| | | #else |
| | | |
| | | bool psramInit(){ |
| | | return false; |
| | | } |
| | | |
| | | bool IRAM_ATTR psramFound(){ |
| | | return false; |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_malloc(size_t size){ |
| | | return NULL; |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_calloc(size_t n, size_t size){ |
| | | return NULL; |
| | | } |
| | | |
| | | void IRAM_ATTR *ps_realloc(void *ptr, size_t size){ |
| | | return NULL; |
| | | } |
| | | |
| | | #endif |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_HAL_PSRAM_H_ |
| | | #define _ESP32_HAL_PSRAM_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | bool psramInit(); |
| | | bool psramFound(); |
| | | |
| | | void *ps_malloc(size_t size); |
| | | void *ps_calloc(size_t n, size_t size); |
| | | void *ps_realloc(void *ptr, size_t size); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_HAL_PSRAM_H_ */ |
| New file |
| | |
| | | // Copyright 2018 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 "freertos/FreeRTOS.h" |
| | | #include "freertos/event_groups.h" |
| | | #include "freertos/semphr.h" |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "esp8266-compat.h" |
| | | #include "soc/gpio_reg.h" |
| | | #include "soc/gpio_reg.h" |
| | | |
| | | #include "esp32-hal-rmt.h" |
| | | #include "driver/periph_ctrl.h" |
| | | |
| | | #include "soc/rmt_struct.h" |
| | | #include "esp_intr_alloc.h" |
| | | |
| | | /** |
| | | * Internal macros |
| | | */ |
| | | #define MAX_CHANNELS 8 |
| | | #define MAX_DATA_PER_CHANNEL 64 |
| | | #define MAX_DATA_PER_ITTERATION 62 |
| | | #define _ABS(a) (a>0?a:-a) |
| | | #define _LIMIT(a,b) (a>b?b:a) |
| | | #define __INT_TX_END (1) |
| | | #define __INT_RX_END (2) |
| | | #define __INT_ERROR (4) |
| | | #define __INT_THR_EVNT (1<<24) |
| | | |
| | | #define _INT_TX_END(channel) (__INT_TX_END<<(channel*3)) |
| | | #define _INT_RX_END(channel) (__INT_RX_END<<(channel*3)) |
| | | #define _INT_ERROR(channel) (__INT_ERROR<<(channel*3)) |
| | | #define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel)) |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | # define RMT_MUTEX_LOCK(channel) |
| | | # define RMT_MUTEX_UNLOCK(channel) |
| | | #else |
| | | # define RMT_MUTEX_LOCK(channel) do {} while (xSemaphoreTake(g_rmt_objlocks[channel], portMAX_DELAY) != pdPASS) |
| | | # define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel]) |
| | | #endif /* CONFIG_DISABLE_HAL_LOCKS */ |
| | | |
| | | #define _RMT_INTERNAL_DEBUG |
| | | #ifdef _RMT_INTERNAL_DEBUG |
| | | # define DEBUG_INTERRUPT_START(pin) digitalWrite(pin, 1); |
| | | # define DEBUG_INTERRUPT_END(pin) digitalWrite(pin, 0); |
| | | #else |
| | | # define DEBUG_INTERRUPT_START(pin) |
| | | # define DEBUG_INTERRUPT_END(pin) |
| | | #endif /* _RMT_INTERNAL_DEBUG */ |
| | | |
| | | /** |
| | | * Typedefs for internal stuctures, enums |
| | | */ |
| | | typedef enum { |
| | | E_NO_INTR = 0, |
| | | E_TX_INTR = 1, |
| | | E_TXTHR_INTR = 2, |
| | | E_RX_INTR = 4, |
| | | } intr_mode_t; |
| | | |
| | | typedef enum { |
| | | E_INACTIVE = 0, |
| | | E_FIRST_HALF = 1, |
| | | E_LAST_DATA = 2, |
| | | E_END_TRANS = 4, |
| | | E_SET_CONTI = 8, |
| | | } transaction_state_t; |
| | | |
| | | struct rmt_obj_s |
| | | { |
| | | bool allocated; |
| | | EventGroupHandle_t events; |
| | | int pin; |
| | | int channel; |
| | | bool tx_not_rx; |
| | | int buffers; |
| | | int data_size; |
| | | uint32_t* data_ptr; |
| | | intr_mode_t intr_mode; |
| | | transaction_state_t tx_state; |
| | | rmt_rx_data_cb_t cb; |
| | | bool data_alloc; |
| | | }; |
| | | |
| | | /** |
| | | * Internal variables for channel descriptors |
| | | */ |
| | | static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { |
| | | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
| | | }; |
| | | |
| | | static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, |
| | | }; |
| | | |
| | | /** |
| | | * Internal variables for driver data |
| | | */ |
| | | static intr_handle_t intr_handle; |
| | | |
| | | static bool periph_enabled = false; |
| | | |
| | | static xSemaphoreHandle g_rmt_block_lock = NULL; |
| | | |
| | | /** |
| | | * Internal method (private) declarations |
| | | */ |
| | | static void _initPin(int pin, int channel, bool tx_not_rx); |
| | | |
| | | static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size); |
| | | |
| | | static void IRAM_ATTR _rmt_isr(void* arg); |
| | | |
| | | static rmt_obj_t* _rmtAllocate(int pin, int from, int size); |
| | | |
| | | static void _initPin(int pin, int channel, bool tx_not_rx); |
| | | |
| | | static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel); |
| | | |
| | | static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch); |
| | | |
| | | static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch); |
| | | |
| | | |
| | | /** |
| | | * Public method definitions |
| | | */ |
| | | bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high) |
| | | { |
| | | if (!rmt || low > 0xFFFF || high > 0xFFFF) { |
| | | return false; |
| | | } |
| | | size_t channel = rmt->channel; |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | |
| | | RMT.carrier_duty_ch[channel].low = low; |
| | | RMT.carrier_duty_ch[channel].high = high; |
| | | RMT.conf_ch[channel].conf0.carrier_en = carrier_en; |
| | | RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level; |
| | | |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return true; |
| | | |
| | | } |
| | | |
| | | bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) |
| | | { |
| | | if (!rmt || filter_level > 0xFF) { |
| | | return false; |
| | | } |
| | | size_t channel = rmt->channel; |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | |
| | | RMT.conf_ch[channel].conf1.rx_filter_thres = filter_level; |
| | | RMT.conf_ch[channel].conf1.rx_filter_en = filter_en; |
| | | |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return true; |
| | | |
| | | } |
| | | |
| | | bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value) |
| | | { |
| | | if (!rmt || value > 0xFFFF) { |
| | | return false; |
| | | } |
| | | size_t channel = rmt->channel; |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | RMT.conf_ch[channel].conf0.idle_thres = value; |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | bool rmtDeinit(rmt_obj_t *rmt) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | |
| | | // sanity check |
| | | if (rmt != &(g_rmt_objects[rmt->channel])) { |
| | | return false; |
| | | } |
| | | |
| | | size_t from = rmt->channel; |
| | | size_t to = rmt->buffers + rmt->channel; |
| | | size_t i; |
| | | |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(g_rmt_objlocks[from] != NULL) { |
| | | vSemaphoreDelete(g_rmt_objlocks[from]); |
| | | } |
| | | #endif |
| | | |
| | | if (g_rmt_objects[from].data_alloc) { |
| | | free(g_rmt_objects[from].data_ptr); |
| | | } |
| | | |
| | | for (i = from; i < to; i++) { |
| | | g_rmt_objects[i].allocated = false; |
| | | } |
| | | |
| | | g_rmt_objects[from].channel = 0; |
| | | g_rmt_objects[from].buffers = 0; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | |
| | | int channel = rmt->channel; |
| | | int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers; |
| | | |
| | | if (size > allocated_size) { |
| | | |
| | | int half_tx_nr = MAX_DATA_PER_ITTERATION/2; |
| | | RMT_MUTEX_LOCK(channel); |
| | | // setup interrupt handler if not yet installed for half and full tx |
| | | if (!intr_handle) { |
| | | esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); |
| | | } |
| | | |
| | | rmt->data_size = size - MAX_DATA_PER_ITTERATION; |
| | | rmt->data_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION; |
| | | rmt->intr_mode = E_TX_INTR | E_TXTHR_INTR; |
| | | rmt->tx_state = E_SET_CONTI | E_FIRST_HALF; |
| | | |
| | | // init the tx limit for interruption |
| | | RMT.tx_lim_ch[channel].limit = half_tx_nr+2; |
| | | // reset memory pointer |
| | | RMT.conf_ch[channel].conf1.apb_mem_rst = 1; |
| | | RMT.conf_ch[channel].conf1.apb_mem_rst = 0; |
| | | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; |
| | | RMT.conf_ch[channel].conf1.mem_rd_rst = 0; |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 0; |
| | | |
| | | // set the tx end mark |
| | | RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0; |
| | | |
| | | // clear and enable both Tx completed and half tx event |
| | | RMT.int_clr.val = _INT_TX_END(channel); |
| | | RMT.int_clr.val = _INT_THR_EVNT(channel); |
| | | RMT.int_clr.val = _INT_ERROR(channel); |
| | | |
| | | RMT.int_ena.val |= _INT_TX_END(channel); |
| | | RMT.int_ena.val |= _INT_THR_EVNT(channel); |
| | | RMT.int_ena.val |= _INT_ERROR(channel); |
| | | |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | // start the transation |
| | | return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION); |
| | | } else { |
| | | // use one-go mode if data fits one buffer |
| | | return _rmtSendOnce(rmt, data, size); |
| | | } |
| | | } |
| | | |
| | | bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | |
| | | if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) { |
| | | return false; |
| | | } |
| | | |
| | | size_t i; |
| | | volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); |
| | | for (i=0; i<size; i++) { |
| | | data[i] = *rmt_mem_ptr++; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool rmtBeginReceive(rmt_obj_t* rmt) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | |
| | | RMT.int_clr.val = _INT_ERROR(channel); |
| | | RMT.int_ena.val |= _INT_ERROR(channel); |
| | | |
| | | RMT.conf_ch[channel].conf1.mem_owner = 1; |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; |
| | | RMT.conf_ch[channel].conf1.rx_en = 1; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool rmtReceiveCompleted(rmt_obj_t* rmt) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | |
| | | if (RMT.int_raw.val&_INT_RX_END(channel)) { |
| | | // RX end flag |
| | | RMT.int_clr.val = _INT_RX_END(channel); |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) |
| | | { |
| | | if (!rmt && !cb) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | rmt->intr_mode = E_RX_INTR; |
| | | rmt->tx_state = E_FIRST_HALF; |
| | | rmt->cb = cb; |
| | | // allocate internally two buffers which would alternate |
| | | if (!rmt->data_alloc) { |
| | | rmt->data_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t)); |
| | | rmt->data_size = MAX_DATA_PER_CHANNEL*rmt->buffers; |
| | | rmt->data_alloc = true; |
| | | } |
| | | |
| | | RMT.conf_ch[channel].conf1.mem_owner = 1; |
| | | |
| | | RMT.int_clr.val = _INT_RX_END(channel); |
| | | RMT.int_clr.val = _INT_ERROR(channel); |
| | | |
| | | RMT.int_ena.val |= _INT_RX_END(channel); |
| | | RMT.int_ena.val |= _INT_ERROR(channel); |
| | | |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; |
| | | |
| | | RMT.conf_ch[channel].conf1.rx_en = 1; |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | |
| | | if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) { |
| | | return false; |
| | | } |
| | | |
| | | if (eventFlag) { |
| | | xEventGroupClearBits(eventFlag, RMT_FLAGS_ALL); |
| | | rmt->events = eventFlag; |
| | | } |
| | | |
| | | if (data && size>0) { |
| | | rmt->data_ptr = (uint32_t*)data; |
| | | rmt->data_size = size; |
| | | } |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | rmt->intr_mode = E_RX_INTR; |
| | | |
| | | RMT.conf_ch[channel].conf1.mem_owner = 1; |
| | | |
| | | RMT.int_clr.val = _INT_RX_END(channel); |
| | | RMT.int_clr.val = _INT_ERROR(channel); |
| | | |
| | | RMT.int_ena.val |= _INT_RX_END(channel); |
| | | RMT.int_ena.val |= _INT_ERROR(channel); |
| | | |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; |
| | | |
| | | RMT.conf_ch[channel].conf1.rx_en = 1; |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | // wait for data if requested so |
| | | if (waitForData && eventFlag) { |
| | | uint32_t flags = xEventGroupWaitBits(eventFlag, RMT_FLAGS_ALL, |
| | | pdTRUE /* clear on exit */, pdFALSE /* wait for all bits */, timeout); |
| | | if (flags & RMT_FLAG_ERROR) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | float rmtSetTick(rmt_obj_t* rmt, float tick) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | /* |
| | | divider field span from 1 (smallest), 2, 3, ... , 0xFF, 0x00 (highest) |
| | | * rmt tick from 1/80M -> 12.5ns (1x) div_cnt = 0x01 |
| | | 3.2 us (256x) div_cnt = 0x00 |
| | | * rmt tick for 1 MHz -> 1us (1x) div_cnt = 0x01 |
| | | 256us (256x) div_cnt = 0x00 |
| | | */ |
| | | int apb_div = _LIMIT(tick/12.5, 256); |
| | | int ref_div = _LIMIT(tick/1000, 256); |
| | | |
| | | float apb_tick = 12.5 * apb_div; |
| | | float ref_tick = 1000.0 * ref_div; |
| | | |
| | | size_t channel = rmt->channel; |
| | | |
| | | if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) { |
| | | RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF; |
| | | RMT.conf_ch[channel].conf1.ref_always_on = 1; |
| | | return apb_tick; |
| | | } else { |
| | | RMT.conf_ch[channel].conf0.div_cnt = ref_div & 0xFF; |
| | | RMT.conf_ch[channel].conf1.ref_always_on = 0; |
| | | return ref_tick; |
| | | } |
| | | } |
| | | |
| | | rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) |
| | | { |
| | | int buffers = memsize; |
| | | rmt_obj_t* rmt; |
| | | size_t i; |
| | | size_t j; |
| | | |
| | | // create common block mutex for protecting allocs from multiple threads |
| | | if (!g_rmt_block_lock) { |
| | | g_rmt_block_lock = xSemaphoreCreateMutex(); |
| | | } |
| | | // lock |
| | | while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {} |
| | | |
| | | for (i=0; i<MAX_CHANNELS; i++) { |
| | | for (j=0; j<buffers && i+j < MAX_CHANNELS; j++) { |
| | | // if the space is ocupied break and continue on other channel |
| | | if (g_rmt_objects[i+j].allocated) { |
| | | i += j; // continue searching from latter channel |
| | | break; |
| | | } |
| | | } |
| | | if (j == buffers) { |
| | | // found a space in channel descriptors |
| | | break; |
| | | } |
| | | } |
| | | if (i == MAX_CHANNELS || i+j >= MAX_CHANNELS || j != buffers) { |
| | | xSemaphoreGive(g_rmt_block_lock); |
| | | return NULL; |
| | | } |
| | | rmt = _rmtAllocate(pin, i, buffers); |
| | | |
| | | xSemaphoreGive(g_rmt_block_lock); |
| | | |
| | | size_t channel = i; |
| | | |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(g_rmt_objlocks[channel] == NULL) { |
| | | g_rmt_objlocks[channel] = xSemaphoreCreateMutex(); |
| | | if(g_rmt_objlocks[channel] == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | |
| | | rmt->pin = pin; |
| | | rmt->tx_not_rx = tx_not_rx; |
| | | rmt->buffers =buffers; |
| | | rmt->channel = channel; |
| | | _initPin(pin, channel, tx_not_rx); |
| | | |
| | | // Initialize the registers in default mode: |
| | | // - no carrier, filter |
| | | // - timebase tick of 1us |
| | | // - idle threshold set to 0x8000 (max pulse width + 1) |
| | | RMT.conf_ch[channel].conf0.div_cnt = 1; |
| | | RMT.conf_ch[channel].conf0.mem_size = buffers; |
| | | RMT.conf_ch[channel].conf0.carrier_en = 0; |
| | | RMT.conf_ch[channel].conf0.carrier_out_lv = 0; |
| | | RMT.conf_ch[channel].conf0.mem_pd = 0; |
| | | |
| | | RMT.conf_ch[channel].conf0.idle_thres = 0x80; |
| | | RMT.conf_ch[channel].conf1.rx_en = 0; |
| | | RMT.conf_ch[channel].conf1.tx_conti_mode = 0; |
| | | RMT.conf_ch[channel].conf1.ref_cnt_rst = 0; |
| | | RMT.conf_ch[channel].conf1.rx_filter_en = 0; |
| | | RMT.conf_ch[channel].conf1.rx_filter_thres = 0; |
| | | RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle |
| | | RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle |
| | | RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock |
| | | RMT.apb_conf.fifo_mask = 1; |
| | | |
| | | if (tx_not_rx) { |
| | | // RMT.conf_ch[channel].conf1.rx_en = 0; |
| | | RMT.conf_ch[channel].conf1.mem_owner = 0; |
| | | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; |
| | | } else { |
| | | // RMT.conf_ch[channel].conf1.rx_en = 1; |
| | | RMT.conf_ch[channel].conf1.mem_owner = 1; |
| | | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; |
| | | } |
| | | |
| | | // install interrupt if at least one channel is active |
| | | if (!intr_handle) { |
| | | esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); |
| | | } |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return rmt; |
| | | } |
| | | |
| | | /** |
| | | * Private methods definitions |
| | | */ |
| | | bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size) |
| | | { |
| | | if (!rmt) { |
| | | return false; |
| | | } |
| | | int channel = rmt->channel; |
| | | RMT.apb_conf.fifo_mask = 1; |
| | | if (data && size>0) { |
| | | size_t i; |
| | | volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); |
| | | for (i = 0; i < size; i++) { |
| | | *rmt_mem_ptr++ = data[i].val; |
| | | } |
| | | // tx end mark |
| | | RMTMEM.chan[channel].data32[size].val = 0; |
| | | } |
| | | |
| | | RMT_MUTEX_LOCK(channel); |
| | | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; |
| | | RMT.conf_ch[channel].conf1.tx_start = 1; |
| | | RMT_MUTEX_UNLOCK(channel); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | static rmt_obj_t* _rmtAllocate(int pin, int from, int size) |
| | | { |
| | | size_t i; |
| | | // setup how many buffers shall we use |
| | | g_rmt_objects[from].buffers = size; |
| | | |
| | | for (i=0; i<size; i++) { |
| | | // mark the block of channels as used |
| | | g_rmt_objects[i+from].allocated = true; |
| | | } |
| | | return &(g_rmt_objects[from]); |
| | | } |
| | | |
| | | |
| | | static void _initPin(int pin, int channel, bool tx_not_rx) |
| | | { |
| | | if (!periph_enabled) { |
| | | periph_enabled = true; |
| | | periph_module_enable( PERIPH_RMT_MODULE ); |
| | | } |
| | | if (tx_not_rx) { |
| | | pinMode(pin, OUTPUT); |
| | | pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); |
| | | } else { |
| | | pinMode(pin, INPUT); |
| | | pinMatrixInAttach(pin, RMT_SIG_IN0_IDX + channel, 0); |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | static void IRAM_ATTR _rmt_isr(void* arg) |
| | | { |
| | | int intr_val = RMT.int_st.val; |
| | | size_t ch; |
| | | for (ch = 0; ch < MAX_CHANNELS; ch++) { |
| | | |
| | | if (intr_val & _INT_RX_END(ch)) { |
| | | // clear the flag |
| | | RMT.int_clr.val = _INT_RX_END(ch); |
| | | RMT.int_ena.val &= ~_INT_RX_END(ch); |
| | | |
| | | if ((g_rmt_objects[ch].intr_mode) & E_RX_INTR) { |
| | | if (g_rmt_objects[ch].events) { |
| | | xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_RX_DONE); |
| | | } |
| | | if (g_rmt_objects[ch].data_ptr && g_rmt_objects[ch].data_size > 0) { |
| | | size_t i; |
| | | uint32_t * data = g_rmt_objects[ch].data_ptr; |
| | | // in case of callback, provide switching between memories |
| | | if (g_rmt_objects[ch].cb) { |
| | | if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { |
| | | g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; |
| | | } else { |
| | | g_rmt_objects[ch].tx_state |= E_FIRST_HALF; |
| | | data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers); |
| | | } |
| | | } |
| | | uint32_t *data_received = data; |
| | | for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) { |
| | | *data++ = RMTMEM.chan[ch].data32[i].val; |
| | | } |
| | | if (g_rmt_objects[ch].cb) { |
| | | // actually received data ptr |
| | | (g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch)); |
| | | |
| | | // restart the reception |
| | | RMT.conf_ch[ch].conf1.mem_owner = 1; |
| | | RMT.conf_ch[ch].conf1.mem_wr_rst = 1; |
| | | RMT.conf_ch[ch].conf1.rx_en = 1; |
| | | RMT.int_ena.val |= _INT_RX_END(ch); |
| | | } else { |
| | | // if not callback provide, expect only one Rx |
| | | g_rmt_objects[ch].intr_mode &= ~E_RX_INTR; |
| | | } |
| | | } |
| | | } else { |
| | | // Report error and disable Rx interrupt |
| | | log_e("Unexpected Rx interrupt!\n"); // TODO: eplace messages with log_X |
| | | RMT.int_ena.val &= ~_INT_RX_END(ch); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | if (intr_val & _INT_ERROR(ch)) { |
| | | // clear the flag |
| | | RMT.int_clr.val = _INT_ERROR(ch); |
| | | RMT.int_ena.val &= ~_INT_ERROR(ch); |
| | | // report error |
| | | log_e("RMT Error %d!\n", ch); |
| | | if (g_rmt_objects[ch].events) { |
| | | xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR); |
| | | } |
| | | // reset memory |
| | | RMT.conf_ch[ch].conf1.mem_rd_rst = 1; |
| | | RMT.conf_ch[ch].conf1.mem_rd_rst = 0; |
| | | RMT.conf_ch[ch].conf1.mem_wr_rst = 1; |
| | | RMT.conf_ch[ch].conf1.mem_wr_rst = 0; |
| | | } |
| | | |
| | | if (intr_val & _INT_TX_END(ch)) { |
| | | |
| | | RMT.int_clr.val = _INT_TX_END(ch); |
| | | _rmt_tx_mem_second(ch); |
| | | } |
| | | |
| | | if (intr_val & _INT_THR_EVNT(ch)) { |
| | | // clear the flag |
| | | RMT.int_clr.val = _INT_THR_EVNT(ch); |
| | | |
| | | // initial setup of continuous mode |
| | | if (g_rmt_objects[ch].tx_state & E_SET_CONTI) { |
| | | RMT.conf_ch[ch].conf1.tx_conti_mode = 1; |
| | | g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI; |
| | | } |
| | | _rmt_tx_mem_first(ch); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch) |
| | | { |
| | | DEBUG_INTERRUPT_START(4) |
| | | uint32_t* data = g_rmt_objects[ch].data_ptr; |
| | | int half_tx_nr = MAX_DATA_PER_ITTERATION/2; |
| | | int i; |
| | | |
| | | RMT.tx_lim_ch[ch].limit = half_tx_nr+2; |
| | | RMT.int_clr.val = _INT_THR_EVNT(ch); |
| | | RMT.int_ena.val |= _INT_THR_EVNT(ch); |
| | | |
| | | g_rmt_objects[ch].tx_state |= E_FIRST_HALF; |
| | | |
| | | if (data) { |
| | | int remaining_size = g_rmt_objects[ch].data_size; |
| | | // will the remaining data occupy the entire halfbuffer |
| | | if (remaining_size > half_tx_nr) { |
| | | for (i = 0; i < half_tx_nr; i++) { |
| | | RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; |
| | | } |
| | | g_rmt_objects[ch].data_size -= half_tx_nr; |
| | | g_rmt_objects[ch].data_ptr += half_tx_nr; |
| | | } else { |
| | | for (i = 0; i < half_tx_nr; i++) { |
| | | if (i < remaining_size) { |
| | | RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; |
| | | } else { |
| | | RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; |
| | | } |
| | | } |
| | | g_rmt_objects[ch].data_ptr = NULL; |
| | | |
| | | } |
| | | } else if ((!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) && |
| | | (!(g_rmt_objects[ch].tx_state & E_END_TRANS))) { |
| | | for (i = 0; i < half_tx_nr; i++) { |
| | | RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; |
| | | } |
| | | RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0; |
| | | g_rmt_objects[ch].tx_state |= E_LAST_DATA; |
| | | RMT.conf_ch[ch].conf1.tx_conti_mode = 0; |
| | | } else { |
| | | log_d("RMT Tx finished %d!\n", ch); |
| | | RMT.conf_ch[ch].conf1.tx_conti_mode = 0; |
| | | RMT.int_ena.val &= ~_INT_TX_END(ch); |
| | | RMT.int_ena.val &= ~_INT_THR_EVNT(ch); |
| | | g_rmt_objects[ch].intr_mode = E_NO_INTR; |
| | | g_rmt_objects[ch].tx_state = E_INACTIVE; |
| | | } |
| | | DEBUG_INTERRUPT_END(4); |
| | | } |
| | | |
| | | static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch) |
| | | { |
| | | DEBUG_INTERRUPT_START(2); |
| | | uint32_t* data = g_rmt_objects[ch].data_ptr; |
| | | int half_tx_nr = MAX_DATA_PER_ITTERATION/2; |
| | | int i; |
| | | RMT.int_ena.val &= ~_INT_THR_EVNT(ch); |
| | | RMT.tx_lim_ch[ch].limit = 0; |
| | | |
| | | if (data) { |
| | | int remaining_size = g_rmt_objects[ch].data_size; |
| | | |
| | | // will the remaining data occupy the entire halfbuffer |
| | | if (remaining_size > half_tx_nr) { |
| | | RMTMEM.chan[ch].data32[0].val = data[0] - 1; |
| | | for (i = 1; i < half_tx_nr; i++) { |
| | | RMTMEM.chan[ch].data32[i].val = data[i]; |
| | | } |
| | | g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; |
| | | // turn off the treshold interrupt |
| | | RMT.int_ena.val &= ~_INT_THR_EVNT(ch); |
| | | RMT.tx_lim_ch[ch].limit = 0; |
| | | g_rmt_objects[ch].data_size -= half_tx_nr; |
| | | g_rmt_objects[ch].data_ptr += half_tx_nr; |
| | | } else { |
| | | RMTMEM.chan[ch].data32[0].val = data[0] - 1; |
| | | for (i = 1; i < half_tx_nr; i++) { |
| | | if (i < remaining_size) { |
| | | RMTMEM.chan[ch].data32[i].val = data[i]; |
| | | } else { |
| | | RMTMEM.chan[ch].data32[i].val = 0x000F000F; |
| | | } |
| | | } |
| | | |
| | | g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; |
| | | g_rmt_objects[ch].data_ptr = NULL; |
| | | } |
| | | } else { |
| | | for (i = 0; i < half_tx_nr; i++) { |
| | | RMTMEM.chan[ch].data32[i].val = 0x000F000F; |
| | | } |
| | | RMTMEM.chan[ch].data32[i].val = 0; |
| | | |
| | | g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; |
| | | RMT.tx_lim_ch[ch].limit = 0; |
| | | g_rmt_objects[ch].tx_state |= E_LAST_DATA; |
| | | RMT.conf_ch[ch].conf1.tx_conti_mode = 0; |
| | | } |
| | | DEBUG_INTERRUPT_END(2); |
| | | } |
| | | |
| | | static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel) |
| | | { |
| | | int block_num = RMT.conf_ch[channel].conf0.mem_size; |
| | | int item_block_len = block_num * 64; |
| | | volatile rmt_item32_t* data = RMTMEM.chan[channel].data32; |
| | | int idx; |
| | | for(idx = 0; idx < item_block_len; idx++) { |
| | | if(data[idx].duration0 == 0) { |
| | | return idx; |
| | | } else if(data[idx].duration1 == 0) { |
| | | return idx + 1; |
| | | } |
| | | } |
| | | return idx; |
| | | } |
| New file |
| | |
| | | // Copyright 2018 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. |
| | | |
| | | #ifndef MAIN_ESP32_HAL_RMT_H_ |
| | | #define MAIN_ESP32_HAL_RMT_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | // notification flags |
| | | #define RMT_FLAG_TX_DONE (1) |
| | | #define RMT_FLAG_RX_DONE (2) |
| | | #define RMT_FLAG_ERROR (4) |
| | | #define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR) |
| | | |
| | | struct rmt_obj_s; |
| | | |
| | | typedef enum { |
| | | RMT_MEM_64 = 1, |
| | | RMT_MEM_128 = 2, |
| | | RMT_MEM_192 = 3, |
| | | RMT_MEM_256 = 4, |
| | | RMT_MEM_320 = 5, |
| | | RMT_MEM_384 = 6, |
| | | RMT_MEM_448 = 7, |
| | | RMT_MEM_512 = 8, |
| | | } rmt_reserve_memsize_t; |
| | | |
| | | typedef struct rmt_obj_s rmt_obj_t; |
| | | |
| | | typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len); |
| | | |
| | | typedef struct { |
| | | union { |
| | | struct { |
| | | uint32_t duration0 :15; |
| | | uint32_t level0 :1; |
| | | uint32_t duration1 :15; |
| | | uint32_t level1 :1; |
| | | }; |
| | | uint32_t val; |
| | | }; |
| | | } rmt_data_t; |
| | | |
| | | /** |
| | | * Initialize the object |
| | | * |
| | | */ |
| | | rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize); |
| | | |
| | | /** |
| | | * Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds |
| | | * return the real actual tick value in ns |
| | | */ |
| | | float rmtSetTick(rmt_obj_t* rmt, float tick); |
| | | |
| | | /** |
| | | * Sending data in one-go mode or continual mode |
| | | * (more data being send while updating buffers in interrupts) |
| | | * |
| | | */ |
| | | bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size); |
| | | |
| | | /** |
| | | * Initiates async receive, event flag indicates data received |
| | | * |
| | | */ |
| | | bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout); |
| | | |
| | | /** |
| | | * Initiates async receive with automatic buffering |
| | | * and callback with data from ISR |
| | | * |
| | | */ |
| | | bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb); |
| | | |
| | | |
| | | /* Additional interface */ |
| | | |
| | | /** |
| | | * Start reception |
| | | * |
| | | */ |
| | | bool rmtBeginReceive(rmt_obj_t* rmt); |
| | | |
| | | /** |
| | | * Checks if reception completes |
| | | * |
| | | */ |
| | | bool rmtReceiveCompleted(rmt_obj_t* rmt); |
| | | |
| | | /** |
| | | * Reads the data for particular channel |
| | | * |
| | | */ |
| | | bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size); |
| | | |
| | | /** |
| | | * Setting threshold for Rx completed |
| | | */ |
| | | bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value); |
| | | |
| | | /** |
| | | * Setting carrier |
| | | */ |
| | | bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high); |
| | | |
| | | /** |
| | | * Setting input filter |
| | | */ |
| | | bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level); |
| | | |
| | | /** |
| | | * Deinitialize the driver |
| | | */ |
| | | bool rmtDeinit(rmt_obj_t *rmt); |
| | | |
| | | // TODO: |
| | | // * uninstall interrupt when all channels are deinit |
| | | // * send only-conti mode with circular-buffer |
| | | // * put sanity checks to some macro or inlines |
| | | // * doxy comments |
| | | // * error reporting |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_RMT_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/semphr.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp32-hal-matrix.h" |
| | | #include "soc/gpio_sd_reg.h" |
| | | #include "soc/gpio_sd_struct.h" |
| | | |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | #define SD_MUTEX_LOCK() |
| | | #define SD_MUTEX_UNLOCK() |
| | | #else |
| | | #define SD_MUTEX_LOCK() do {} while (xSemaphoreTake(_sd_sys_lock, portMAX_DELAY) != pdPASS) |
| | | #define SD_MUTEX_UNLOCK() xSemaphoreGive(_sd_sys_lock) |
| | | xSemaphoreHandle _sd_sys_lock; |
| | | #endif |
| | | |
| | | static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
| | | if(old_apb == new_apb){ |
| | | return; |
| | | } |
| | | uint32_t iarg = (uint32_t)arg; |
| | | uint8_t channel = iarg; |
| | | if(ev_type == APB_BEFORE_CHANGE){ |
| | | SIGMADELTA.cg.clk_en = 0; |
| | | } else { |
| | | old_apb /= 1000000; |
| | | new_apb /= 1000000; |
| | | SD_MUTEX_LOCK(); |
| | | uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1; |
| | | SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1; |
| | | SIGMADELTA.cg.clk_en = 0; |
| | | SIGMADELTA.cg.clk_en = 1; |
| | | SD_MUTEX_UNLOCK(); |
| | | } |
| | | } |
| | | |
| | | uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500 |
| | | { |
| | | if(channel > 7) { |
| | | return 0; |
| | | } |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | static bool tHasStarted = false; |
| | | if(!tHasStarted) { |
| | | tHasStarted = true; |
| | | _sd_sys_lock = xSemaphoreCreateMutex(); |
| | | } |
| | | #endif |
| | | uint32_t apb_freq = getApbFrequency(); |
| | | uint32_t prescale = (apb_freq/(freq*256)) - 1; |
| | | if(prescale > 0xFF) { |
| | | prescale = 0xFF; |
| | | } |
| | | SD_MUTEX_LOCK(); |
| | | SIGMADELTA.channel[channel].prescale = prescale; |
| | | SIGMADELTA.cg.clk_en = 0; |
| | | SIGMADELTA.cg.clk_en = 1; |
| | | SD_MUTEX_UNLOCK(); |
| | | uint32_t iarg = channel; |
| | | addApbChangeCallback((void*)iarg, _on_apb_change); |
| | | return apb_freq/((prescale + 1) * 256); |
| | | } |
| | | |
| | | void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit |
| | | { |
| | | if(channel > 7) { |
| | | return; |
| | | } |
| | | duty -= 128; |
| | | SD_MUTEX_LOCK(); |
| | | SIGMADELTA.channel[channel].duty = duty; |
| | | SD_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-7 |
| | | { |
| | | if(channel > 7) { |
| | | return 0; |
| | | } |
| | | SD_MUTEX_LOCK(); |
| | | uint8_t duty = SIGMADELTA.channel[channel].duty + 128; |
| | | SD_MUTEX_UNLOCK(); |
| | | return duty; |
| | | } |
| | | |
| | | void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel) //channel 0-7 |
| | | { |
| | | if(channel > 7) { |
| | | return; |
| | | } |
| | | pinMode(pin, OUTPUT); |
| | | pinMatrixOutAttach(pin, GPIO_SD0_OUT_IDX + channel, false, false); |
| | | } |
| | | |
| | | void sigmaDeltaDetachPin(uint8_t pin) |
| | | { |
| | | pinMatrixOutDetach(pin, false, false); |
| | | } |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef _ESP32_HAL_SD_H_ |
| | | #define _ESP32_HAL_SD_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | |
| | | //channel 0-7 freq 1220-312500 duty 0-255 |
| | | uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq); |
| | | void sigmaDeltaWrite(uint8_t channel, uint8_t duty); |
| | | uint8_t sigmaDeltaRead(uint8_t channel); |
| | | void sigmaDeltaAttachPin(uint8_t pin, uint8_t channel); |
| | | void sigmaDeltaDetachPin(uint8_t pin); |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* _ESP32_HAL_SD_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-spi.h" |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/semphr.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "rom/gpio.h" |
| | | #include "soc/spi_reg.h" |
| | | #include "soc/spi_struct.h" |
| | | #include "soc/io_mux_reg.h" |
| | | #include "soc/gpio_sig_map.h" |
| | | #include "soc/dport_reg.h" |
| | | #include "soc/rtc.h" |
| | | |
| | | #define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0)))) |
| | | #define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0)))) |
| | | #define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0)))) |
| | | |
| | | #define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX))) |
| | | #define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX))) |
| | | #define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX))) |
| | | #define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0)))) |
| | | |
| | | #define SPI_INUM(u) (2) |
| | | #define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0)))) |
| | | |
| | | struct spi_struct_t { |
| | | spi_dev_t * dev; |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | xSemaphoreHandle lock; |
| | | #endif |
| | | uint8_t num; |
| | | }; |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | #define SPI_MUTEX_LOCK() |
| | | #define SPI_MUTEX_UNLOCK() |
| | | |
| | | static spi_t _spi_bus_array[4] = { |
| | | {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3} |
| | | }; |
| | | #else |
| | | #define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS) |
| | | #define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock) |
| | | |
| | | static spi_t _spi_bus_array[4] = { |
| | | {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2}, |
| | | {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3} |
| | | }; |
| | | #endif |
| | | |
| | | void spiAttachSCK(spi_t * spi, int8_t sck) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(sck < 0) { |
| | | if(spi->num == HSPI) { |
| | | sck = 14; |
| | | } else if(spi->num == VSPI) { |
| | | sck = 18; |
| | | } else { |
| | | sck = 6; |
| | | } |
| | | } |
| | | pinMode(sck, OUTPUT); |
| | | pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false); |
| | | } |
| | | |
| | | void spiAttachMISO(spi_t * spi, int8_t miso) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(miso < 0) { |
| | | if(spi->num == HSPI) { |
| | | miso = 12; |
| | | } else if(spi->num == VSPI) { |
| | | miso = 19; |
| | | } else { |
| | | miso = 7; |
| | | } |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | pinMode(miso, INPUT); |
| | | pinMatrixInAttach(miso, SPI_MISO_IDX(spi->num), false); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiAttachMOSI(spi_t * spi, int8_t mosi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(mosi < 0) { |
| | | if(spi->num == HSPI) { |
| | | mosi = 13; |
| | | } else if(spi->num == VSPI) { |
| | | mosi = 23; |
| | | } else { |
| | | mosi = 8; |
| | | } |
| | | } |
| | | pinMode(mosi, OUTPUT); |
| | | pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false); |
| | | } |
| | | |
| | | void spiDetachSCK(spi_t * spi, int8_t sck) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(sck < 0) { |
| | | if(spi->num == HSPI) { |
| | | sck = 14; |
| | | } else if(spi->num == VSPI) { |
| | | sck = 18; |
| | | } else { |
| | | sck = 6; |
| | | } |
| | | } |
| | | pinMatrixOutDetach(sck, false, false); |
| | | pinMode(sck, INPUT); |
| | | } |
| | | |
| | | void spiDetachMISO(spi_t * spi, int8_t miso) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(miso < 0) { |
| | | if(spi->num == HSPI) { |
| | | miso = 12; |
| | | } else if(spi->num == VSPI) { |
| | | miso = 19; |
| | | } else { |
| | | miso = 7; |
| | | } |
| | | } |
| | | pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false); |
| | | pinMode(miso, INPUT); |
| | | } |
| | | |
| | | void spiDetachMOSI(spi_t * spi, int8_t mosi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(mosi < 0) { |
| | | if(spi->num == HSPI) { |
| | | mosi = 13; |
| | | } else if(spi->num == VSPI) { |
| | | mosi = 23; |
| | | } else { |
| | | mosi = 8; |
| | | } |
| | | } |
| | | pinMatrixOutDetach(mosi, false, false); |
| | | pinMode(mosi, INPUT); |
| | | } |
| | | |
| | | void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(cs_num > 2) { |
| | | return; |
| | | } |
| | | if(ss < 0) { |
| | | cs_num = 0; |
| | | if(spi->num == HSPI) { |
| | | ss = 15; |
| | | } else if(spi->num == VSPI) { |
| | | ss = 5; |
| | | } else { |
| | | ss = 11; |
| | | } |
| | | } |
| | | pinMode(ss, OUTPUT); |
| | | pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false); |
| | | spiEnableSSPins(spi, (1 << cs_num)); |
| | | } |
| | | |
| | | void spiDetachSS(spi_t * spi, int8_t ss) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(ss < 0) { |
| | | if(spi->num == HSPI) { |
| | | ss = 15; |
| | | } else if(spi->num == VSPI) { |
| | | ss = 5; |
| | | } else { |
| | | ss = 11; |
| | | } |
| | | } |
| | | pinMatrixOutDetach(ss, false, false); |
| | | pinMode(ss, INPUT); |
| | | } |
| | | |
| | | void spiEnableSSPins(spi_t * spi, uint8_t cs_mask) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiDisableSSPins(spi_t * spi, uint8_t cs_mask) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiSSEnable(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->user.cs_setup = 1; |
| | | spi->dev->user.cs_hold = 1; |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiSSDisable(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->user.cs_setup = 0; |
| | | spi->dev->user.cs_hold = 0; |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiSSSet(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->pin.cs_keep_active = 1; |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiSSClear(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->pin.cs_keep_active = 0; |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint32_t spiGetClockDiv(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | return spi->dev->clock.val; |
| | | } |
| | | |
| | | void spiSetClockDiv(spi_t * spi, uint32_t clockDiv) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->clock.val = clockDiv; |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint8_t spiGetDataMode(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | bool idleEdge = spi->dev->pin.ck_idle_edge; |
| | | bool outEdge = spi->dev->user.ck_out_edge; |
| | | if(idleEdge) { |
| | | if(outEdge) { |
| | | return SPI_MODE2; |
| | | } |
| | | return SPI_MODE3; |
| | | } |
| | | if(outEdge) { |
| | | return SPI_MODE1; |
| | | } |
| | | return SPI_MODE0; |
| | | } |
| | | |
| | | void spiSetDataMode(spi_t * spi, uint8_t dataMode) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | switch (dataMode) { |
| | | case SPI_MODE1: |
| | | spi->dev->pin.ck_idle_edge = 0; |
| | | spi->dev->user.ck_out_edge = 1; |
| | | break; |
| | | case SPI_MODE2: |
| | | spi->dev->pin.ck_idle_edge = 1; |
| | | spi->dev->user.ck_out_edge = 1; |
| | | break; |
| | | case SPI_MODE3: |
| | | spi->dev->pin.ck_idle_edge = 1; |
| | | spi->dev->user.ck_out_edge = 0; |
| | | break; |
| | | case SPI_MODE0: |
| | | default: |
| | | spi->dev->pin.ck_idle_edge = 0; |
| | | spi->dev->user.ck_out_edge = 0; |
| | | break; |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint8_t spiGetBitOrder(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | return (spi->dev->ctrl.wr_bit_order | spi->dev->ctrl.rd_bit_order) == 0; |
| | | } |
| | | |
| | | void spiSetBitOrder(spi_t * spi, uint8_t bitOrder) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | if (SPI_MSBFIRST == bitOrder) { |
| | | spi->dev->ctrl.wr_bit_order = 0; |
| | | spi->dev->ctrl.rd_bit_order = 0; |
| | | } else if (SPI_LSBFIRST == bitOrder) { |
| | | spi->dev->ctrl.wr_bit_order = 1; |
| | | spi->dev->ctrl.rd_bit_order = 1; |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) |
| | | { |
| | | spi_t * spi = (spi_t *)arg; |
| | | if(ev_type == APB_BEFORE_CHANGE){ |
| | | SPI_MUTEX_LOCK(); |
| | | while(spi->dev->cmd.usr); |
| | | } else { |
| | | spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1))); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | } |
| | | |
| | | void spiStopBus(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->slave.trans_done = 0; |
| | | spi->dev->slave.slave_mode = 0; |
| | | spi->dev->pin.val = 0; |
| | | spi->dev->user.val = 0; |
| | | spi->dev->user1.val = 0; |
| | | spi->dev->ctrl.val = 0; |
| | | spi->dev->ctrl1.val = 0; |
| | | spi->dev->ctrl2.val = 0; |
| | | spi->dev->clock.val = 0; |
| | | SPI_MUTEX_UNLOCK(); |
| | | removeApbChangeCallback(spi, _on_apb_change); |
| | | } |
| | | |
| | | spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) |
| | | { |
| | | if(spi_num > 3){ |
| | | return NULL; |
| | | } |
| | | |
| | | spi_t * spi = &_spi_bus_array[spi_num]; |
| | | |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(spi->lock == NULL){ |
| | | spi->lock = xSemaphoreCreateMutex(); |
| | | if(spi->lock == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | if(spi_num == HSPI) { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST); |
| | | } else if(spi_num == VSPI) { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2); |
| | | } else { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1); |
| | | } |
| | | |
| | | spiStopBus(spi); |
| | | spiSetDataMode(spi, dataMode); |
| | | spiSetBitOrder(spi, bitOrder); |
| | | spiSetClockDiv(spi, clockDiv); |
| | | |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->user.usr_mosi = 1; |
| | | spi->dev->user.usr_miso = 1; |
| | | spi->dev->user.doutdin = 1; |
| | | |
| | | int i; |
| | | for(i=0; i<16; i++) { |
| | | spi->dev->data_buf[i] = 0x00000000; |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | |
| | | addApbChangeCallback(spi, _on_apb_change); |
| | | return spi; |
| | | } |
| | | |
| | | void spiWaitReady(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | while(spi->dev->cmd.usr); |
| | | } |
| | | |
| | | void spiWrite(spi_t * spi, uint32_t *data, uint8_t len) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | int i; |
| | | if(len > 16) { |
| | | len = 16; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | for(i=0; i<len; i++) { |
| | | spi->dev->data_buf[i] = data[i]; |
| | | } |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiTransfer(spi_t * spi, uint32_t *data, uint8_t len) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | int i; |
| | | if(len > 16) { |
| | | len = 16; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = (len * 32) - 1; |
| | | for(i=0; i<len; i++) { |
| | | spi->dev->data_buf[i] = data[i]; |
| | | } |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | for(i=0; i<len; i++) { |
| | | data[i] = spi->dev->data_buf[i]; |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiWriteByte(spi_t * spi, uint8_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint8_t spiTransferByte(spi_t * spi, uint8_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 7; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0] & 0xFF; |
| | | SPI_MUTEX_UNLOCK(); |
| | | return data; |
| | | } |
| | | |
| | | uint32_t __spiTranslate24(uint32_t data) |
| | | { |
| | | union { |
| | | uint32_t l; |
| | | uint8_t b[4]; |
| | | } out; |
| | | out.l = data; |
| | | return out.b[2] | (out.b[1] << 8) | (out.b[0] << 16); |
| | | } |
| | | |
| | | uint32_t __spiTranslate32(uint32_t data) |
| | | { |
| | | union { |
| | | uint32_t l; |
| | | uint8_t b[4]; |
| | | } out; |
| | | out.l = data; |
| | | return out.b[3] | (out.b[2] << 8) | (out.b[1] << 16) | (out.b[0] << 24); |
| | | } |
| | | |
| | | void spiWriteWord(spi_t * spi, uint16_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | data = (data >> 8) | (data << 8); |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint16_t spiTransferWord(spi_t * spi, uint16_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | data = (data >> 8) | (data << 8); |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 15; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0]; |
| | | SPI_MUTEX_UNLOCK(); |
| | | if(!spi->dev->ctrl.rd_bit_order){ |
| | | data = (data >> 8) | (data << 8); |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | void spiWriteLong(spi_t * spi, uint32_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | data = __spiTranslate32(data); |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | uint32_t spiTransferLong(spi_t * spi, uint32_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | data = __spiTranslate32(data); |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 31; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0]; |
| | | SPI_MUTEX_UNLOCK(); |
| | | if(!spi->dev->ctrl.rd_bit_order){ |
| | | data = __spiTranslate32(data); |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | void __spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t bytes) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | int i; |
| | | |
| | | if(bytes > 64) { |
| | | bytes = 64; |
| | | } |
| | | |
| | | uint32_t words = (bytes + 3) / 4;//16 max |
| | | |
| | | uint32_t wordsBuf[16] = {0,}; |
| | | uint8_t * bytesBuf = (uint8_t *) wordsBuf; |
| | | |
| | | if(data) { |
| | | memcpy(bytesBuf, data, bytes);//copy data to buffer |
| | | } else { |
| | | memset(bytesBuf, 0xFF, bytes); |
| | | } |
| | | |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = ((bytes * 8) - 1); |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = ((bytes * 8) - 1); |
| | | |
| | | for(i=0; i<words; i++) { |
| | | spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo |
| | | } |
| | | |
| | | spi->dev->cmd.usr = 1; |
| | | |
| | | while(spi->dev->cmd.usr); |
| | | |
| | | if(out) { |
| | | for(i=0; i<words; i++) { |
| | | wordsBuf[i] = spi->dev->data_buf[i];//copy spi fifo to buffer |
| | | } |
| | | memcpy(out, bytesBuf, bytes);//copy buffer to output |
| | | } |
| | | } |
| | | |
| | | void spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t size) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | while(size) { |
| | | if(size > 64) { |
| | | __spiTransferBytes(spi, data, out, 64); |
| | | size -= 64; |
| | | if(data) { |
| | | data += 64; |
| | | } |
| | | if(out) { |
| | | out += 64; |
| | | } |
| | | } else { |
| | | __spiTransferBytes(spi, data, out, size); |
| | | size = 0; |
| | | } |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spiTransferBitsNL(spi, data, out, bits); |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | /* |
| | | * Manual Lock Management |
| | | * */ |
| | | |
| | | #define MSB_32_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[3] | (d[2] << 8) | (d[1] << 16) | (d[0] << 24); } |
| | | #define MSB_24_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[2] | (d[1] << 8) | (d[0] << 16); } |
| | | #define MSB_16_SET(var, val) { (var) = (((val) & 0xFF00) >> 8) | (((val) & 0xFF) << 8); } |
| | | #define MSB_PIX_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[1] | (d[0] << 8) | (d[3] << 16) | (d[2] << 24); } |
| | | |
| | | void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | spi->dev->clock.val = clockDiv; |
| | | switch (dataMode) { |
| | | case SPI_MODE1: |
| | | spi->dev->pin.ck_idle_edge = 0; |
| | | spi->dev->user.ck_out_edge = 1; |
| | | break; |
| | | case SPI_MODE2: |
| | | spi->dev->pin.ck_idle_edge = 1; |
| | | spi->dev->user.ck_out_edge = 1; |
| | | break; |
| | | case SPI_MODE3: |
| | | spi->dev->pin.ck_idle_edge = 1; |
| | | spi->dev->user.ck_out_edge = 0; |
| | | break; |
| | | case SPI_MODE0: |
| | | default: |
| | | spi->dev->pin.ck_idle_edge = 0; |
| | | spi->dev->user.ck_out_edge = 0; |
| | | break; |
| | | } |
| | | if (SPI_MSBFIRST == bitOrder) { |
| | | spi->dev->ctrl.wr_bit_order = 0; |
| | | spi->dev->ctrl.rd_bit_order = 0; |
| | | } else if (SPI_LSBFIRST == bitOrder) { |
| | | spi->dev->ctrl.wr_bit_order = 1; |
| | | spi->dev->ctrl.rd_bit_order = 1; |
| | | } |
| | | } |
| | | |
| | | void spiSimpleTransaction(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_LOCK(); |
| | | } |
| | | |
| | | void spiEndTransaction(spi_t * spi) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | SPI_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | } |
| | | |
| | | uint8_t spiTransferByteNL(spi_t * spi, uint8_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 7; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0] & 0xFF; |
| | | return data; |
| | | } |
| | | |
| | | void IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | MSB_16_SET(data, data); |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | } |
| | | |
| | | uint16_t spiTransferShortNL(spi_t * spi, uint16_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | MSB_16_SET(data, data); |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 15; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0] & 0xFFFF; |
| | | if(!spi->dev->ctrl.rd_bit_order){ |
| | | MSB_16_SET(data, data); |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | MSB_32_SET(data, data); |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | } |
| | | |
| | | uint32_t spiTransferLongNL(spi_t * spi, uint32_t data) |
| | | { |
| | | if(!spi) { |
| | | return 0; |
| | | } |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | MSB_32_SET(data, data); |
| | | } |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 31; |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0]; |
| | | if(!spi->dev->ctrl.rd_bit_order){ |
| | | MSB_32_SET(data, data); |
| | | } |
| | | return data; |
| | | } |
| | | |
| | | void spiWriteNL(spi_t * spi, const void * data_in, size_t len){ |
| | | size_t longs = len >> 2; |
| | | if(len & 3){ |
| | | longs++; |
| | | } |
| | | uint32_t * data = (uint32_t*)data_in; |
| | | size_t c_len = 0, c_longs = 0; |
| | | |
| | | while(len){ |
| | | c_len = (len>64)?64:len; |
| | | c_longs = (longs > 16)?16:longs; |
| | | |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | for (int i=0; i<c_longs; i++) { |
| | | spi->dev->data_buf[i] = data[i]; |
| | | } |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | |
| | | data += c_longs; |
| | | longs -= c_longs; |
| | | len -= c_len; |
| | | } |
| | | } |
| | | |
| | | void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, size_t len){ |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | size_t longs = len >> 2; |
| | | if(len & 3){ |
| | | longs++; |
| | | } |
| | | uint32_t * data = (uint32_t*)data_in; |
| | | uint32_t * result = (uint32_t*)data_out; |
| | | size_t c_len = 0, c_longs = 0; |
| | | |
| | | while(len){ |
| | | c_len = (len>64)?64:len; |
| | | c_longs = (longs > 16)?16:longs; |
| | | |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = (c_len*8)-1; |
| | | if(data){ |
| | | for (int i=0; i<c_longs; i++) { |
| | | spi->dev->data_buf[i] = data[i]; |
| | | } |
| | | } else { |
| | | for (int i=0; i<c_longs; i++) { |
| | | spi->dev->data_buf[i] = 0xFFFFFFFF; |
| | | } |
| | | } |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | if(result){ |
| | | for (int i=0; i<c_longs; i++) { |
| | | result[i] = spi->dev->data_buf[i]; |
| | | } |
| | | } |
| | | if(data){ |
| | | data += c_longs; |
| | | } |
| | | if(result){ |
| | | result += c_longs; |
| | | } |
| | | longs -= c_longs; |
| | | len -= c_len; |
| | | } |
| | | } |
| | | |
| | | void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) |
| | | { |
| | | if(!spi) { |
| | | return; |
| | | } |
| | | |
| | | if(bits > 32) { |
| | | bits = 32; |
| | | } |
| | | uint32_t bytes = (bits + 7) / 8;//64 max |
| | | uint32_t mask = (((uint64_t)1 << bits) - 1) & 0xFFFFFFFF; |
| | | data = data & mask; |
| | | if(!spi->dev->ctrl.wr_bit_order){ |
| | | if(bytes == 2) { |
| | | MSB_16_SET(data, data); |
| | | } else if(bytes == 3) { |
| | | MSB_24_SET(data, data); |
| | | } else { |
| | | MSB_32_SET(data, data); |
| | | } |
| | | } |
| | | |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1); |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1); |
| | | spi->dev->data_buf[0] = data; |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | data = spi->dev->data_buf[0]; |
| | | if(out) { |
| | | *out = data; |
| | | if(!spi->dev->ctrl.rd_bit_order){ |
| | | if(bytes == 2) { |
| | | MSB_16_SET(*out, data); |
| | | } else if(bytes == 3) { |
| | | MSB_24_SET(*out, data); |
| | | } else { |
| | | MSB_32_SET(*out, data); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){ |
| | | size_t longs = len >> 2; |
| | | if(len & 3){ |
| | | longs++; |
| | | } |
| | | bool msb = !spi->dev->ctrl.wr_bit_order; |
| | | uint32_t * data = (uint32_t*)data_in; |
| | | size_t c_len = 0, c_longs = 0, l_bytes = 0; |
| | | |
| | | while(len){ |
| | | c_len = (len>64)?64:len; |
| | | c_longs = (longs > 16)?16:longs; |
| | | l_bytes = (c_len & 3); |
| | | |
| | | spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; |
| | | spi->dev->miso_dlen.usr_miso_dbitlen = 0; |
| | | for (int i=0; i<c_longs; i++) { |
| | | if(msb){ |
| | | if(l_bytes && i == (c_longs - 1)){ |
| | | if(l_bytes == 2){ |
| | | MSB_16_SET(spi->dev->data_buf[i], data[i]); |
| | | } else { |
| | | spi->dev->data_buf[i] = data[i] & 0xFF; |
| | | } |
| | | } else { |
| | | MSB_PIX_SET(spi->dev->data_buf[i], data[i]); |
| | | } |
| | | } else { |
| | | spi->dev->data_buf[i] = data[i]; |
| | | } |
| | | } |
| | | spi->dev->cmd.usr = 1; |
| | | while(spi->dev->cmd.usr); |
| | | |
| | | data += c_longs; |
| | | longs -= c_longs; |
| | | len -= c_len; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /* |
| | | * Clock Calculators |
| | | * |
| | | * */ |
| | | |
| | | typedef union { |
| | | uint32_t value; |
| | | struct { |
| | | uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/ |
| | | uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/ |
| | | uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/ |
| | | uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/ |
| | | uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/ |
| | | }; |
| | | } spiClk_t; |
| | | |
| | | #define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1))) |
| | | |
| | | uint32_t spiClockDivToFrequency(uint32_t clockDiv) |
| | | { |
| | | uint32_t apb_freq = getApbFrequency(); |
| | | spiClk_t reg = { clockDiv }; |
| | | return ClkRegToFreq(®); |
| | | } |
| | | |
| | | uint32_t spiFrequencyToClockDiv(uint32_t freq) |
| | | { |
| | | uint32_t apb_freq = getApbFrequency(); |
| | | |
| | | if(freq >= apb_freq) { |
| | | return SPI_CLK_EQU_SYSCLK; |
| | | } |
| | | |
| | | const spiClk_t minFreqReg = { 0x7FFFF000 }; |
| | | uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); |
| | | if(freq < minFreq) { |
| | | return minFreqReg.value; |
| | | } |
| | | |
| | | uint8_t calN = 1; |
| | | spiClk_t bestReg = { 0 }; |
| | | int32_t bestFreq = 0; |
| | | |
| | | while(calN <= 0x3F) { |
| | | spiClk_t reg = { 0 }; |
| | | int32_t calFreq; |
| | | int32_t calPre; |
| | | int8_t calPreVari = -2; |
| | | |
| | | reg.clkcnt_n = calN; |
| | | |
| | | while(calPreVari++ <= 1) { |
| | | calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; |
| | | if(calPre > 0x1FFF) { |
| | | reg.clkdiv_pre = 0x1FFF; |
| | | } else if(calPre <= 0) { |
| | | reg.clkdiv_pre = 0; |
| | | } else { |
| | | reg.clkdiv_pre = calPre; |
| | | } |
| | | reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2); |
| | | calFreq = ClkRegToFreq(®); |
| | | if(calFreq == (int32_t) freq) { |
| | | memcpy(&bestReg, ®, sizeof(bestReg)); |
| | | break; |
| | | } else if(calFreq < (int32_t) freq) { |
| | | if(abs(freq - calFreq) < abs(freq - bestFreq)) { |
| | | bestFreq = calFreq; |
| | | memcpy(&bestReg, ®, sizeof(bestReg)); |
| | | } |
| | | } |
| | | } |
| | | if(calFreq == (int32_t) freq) { |
| | | break; |
| | | } |
| | | calN++; |
| | | } |
| | | return bestReg.value; |
| | | } |
| | | |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef MAIN_ESP32_HAL_SPI_H_ |
| | | #define MAIN_ESP32_HAL_SPI_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | |
| | | #define SPI_HAS_TRANSACTION |
| | | |
| | | #define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS) |
| | | #define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins |
| | | #define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins |
| | | |
| | | // This defines are not representing the real Divider of the ESP32 |
| | | // the Defines match to an AVR Arduino on 16MHz for better compatibility |
| | | #define SPI_CLOCK_DIV2 0x00101001 //8 MHz |
| | | #define SPI_CLOCK_DIV4 0x00241001 //4 MHz |
| | | #define SPI_CLOCK_DIV8 0x004c1001 //2 MHz |
| | | #define SPI_CLOCK_DIV16 0x009c1001 //1 MHz |
| | | #define SPI_CLOCK_DIV32 0x013c1001 //500 KHz |
| | | #define SPI_CLOCK_DIV64 0x027c1001 //250 KHz |
| | | #define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz |
| | | |
| | | #define SPI_MODE0 0 |
| | | #define SPI_MODE1 1 |
| | | #define SPI_MODE2 2 |
| | | #define SPI_MODE3 3 |
| | | |
| | | #define SPI_CS0 0 |
| | | #define SPI_CS1 1 |
| | | #define SPI_CS2 2 |
| | | #define SPI_CS_MASK_ALL 0x7 |
| | | |
| | | #define SPI_LSBFIRST 0 |
| | | #define SPI_MSBFIRST 1 |
| | | |
| | | struct spi_struct_t; |
| | | typedef struct spi_struct_t spi_t; |
| | | |
| | | spi_t * spiStartBus(uint8_t spi_num, uint32_t freq, uint8_t dataMode, uint8_t bitOrder); |
| | | void spiStopBus(spi_t * spi); |
| | | |
| | | //Attach/Detach Signal Pins |
| | | void spiAttachSCK(spi_t * spi, int8_t sck); |
| | | void spiAttachMISO(spi_t * spi, int8_t miso); |
| | | void spiAttachMOSI(spi_t * spi, int8_t mosi); |
| | | void spiDetachSCK(spi_t * spi, int8_t sck); |
| | | void spiDetachMISO(spi_t * spi, int8_t miso); |
| | | void spiDetachMOSI(spi_t * spi, int8_t mosi); |
| | | |
| | | //Attach/Detach SS pin to SPI_CSx signal |
| | | void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss); |
| | | void spiDetachSS(spi_t * spi, int8_t ss); |
| | | |
| | | //Enable/Disable SPI_CSx pins |
| | | void spiEnableSSPins(spi_t * spi, uint8_t cs_mask); |
| | | void spiDisableSSPins(spi_t * spi, uint8_t cs_mask); |
| | | |
| | | //Enable/Disable hardware control of SPI_CSx pins |
| | | void spiSSEnable(spi_t * spi); |
| | | void spiSSDisable(spi_t * spi); |
| | | |
| | | //Activate enabled SPI_CSx pins |
| | | void spiSSSet(spi_t * spi); |
| | | //Deactivate enabled SPI_CSx pins |
| | | void spiSSClear(spi_t * spi); |
| | | |
| | | void spiWaitReady(spi_t * spi); |
| | | |
| | | uint32_t spiGetClockDiv(spi_t * spi); |
| | | uint8_t spiGetDataMode(spi_t * spi); |
| | | uint8_t spiGetBitOrder(spi_t * spi); |
| | | |
| | | |
| | | /* |
| | | * Non transaction based lock methods (each locks and unlocks when called) |
| | | * */ |
| | | void spiSetClockDiv(spi_t * spi, uint32_t clockDiv); |
| | | void spiSetDataMode(spi_t * spi, uint8_t dataMode); |
| | | void spiSetBitOrder(spi_t * spi, uint8_t bitOrder); |
| | | |
| | | void spiWrite(spi_t * spi, uint32_t *data, uint8_t len); |
| | | void spiWriteByte(spi_t * spi, uint8_t data); |
| | | void spiWriteWord(spi_t * spi, uint16_t data); |
| | | void spiWriteLong(spi_t * spi, uint32_t data); |
| | | |
| | | void spiTransfer(spi_t * spi, uint32_t *out, uint8_t len); |
| | | uint8_t spiTransferByte(spi_t * spi, uint8_t data); |
| | | uint16_t spiTransferWord(spi_t * spi, uint16_t data); |
| | | uint32_t spiTransferLong(spi_t * spi, uint32_t data); |
| | | void spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t size); |
| | | void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits); |
| | | |
| | | /* |
| | | * New (EXPERIMENTAL) Transaction lock based API (lock once until endTransaction) |
| | | * */ |
| | | void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder); |
| | | void spiSimpleTransaction(spi_t * spi); |
| | | void spiEndTransaction(spi_t * spi); |
| | | |
| | | void spiWriteNL(spi_t * spi, const void * data, uint32_t len); |
| | | void spiWriteByteNL(spi_t * spi, uint8_t data); |
| | | void spiWriteShortNL(spi_t * spi, uint16_t data); |
| | | void spiWriteLongNL(spi_t * spi, uint32_t data); |
| | | void spiWritePixelsNL(spi_t * spi, const void * data, uint32_t len); |
| | | |
| | | #define spiTransferNL(spi, data, len) spiTransferBytesNL(spi, data, data, len) |
| | | uint8_t spiTransferByteNL(spi_t * spi, uint8_t data); |
| | | uint16_t spiTransferShortNL(spi_t * spi, uint16_t data); |
| | | uint32_t spiTransferLongNL(spi_t * spi, uint32_t data); |
| | | void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, uint32_t len); |
| | | void spiTransferBitsNL(spi_t * spi, uint32_t data_in, uint32_t * data_out, uint8_t bits); |
| | | |
| | | /* |
| | | * Helper functions to translate frequency to clock divider and back |
| | | * */ |
| | | uint32_t spiFrequencyToClockDiv(uint32_t freq); |
| | | uint32_t spiClockDivToFrequency(uint32_t freq); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_SPI_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "lwip/apps/sntp.h" |
| | | |
| | | static void setTimeZone(long offset, int daylight) |
| | | { |
| | | char cst[17] = {0}; |
| | | char cdt[17] = "DST"; |
| | | char tz[33] = {0}; |
| | | |
| | | if(offset % 3600){ |
| | | sprintf(cst, "UTC%ld:%02u:%02u", offset / 3600, abs((offset % 3600) / 60), abs(offset % 60)); |
| | | } else { |
| | | sprintf(cst, "UTC%ld", offset / 3600); |
| | | } |
| | | if(daylight != 3600){ |
| | | long tz_dst = offset - daylight; |
| | | if(tz_dst % 3600){ |
| | | sprintf(cdt, "DST%ld:%02u:%02u", tz_dst / 3600, abs((tz_dst % 3600) / 60), abs(tz_dst % 60)); |
| | | } else { |
| | | sprintf(cdt, "DST%ld", tz_dst / 3600); |
| | | } |
| | | } |
| | | sprintf(tz, "%s%s", cst, cdt); |
| | | setenv("TZ", tz, 1); |
| | | tzset(); |
| | | } |
| | | |
| | | /* |
| | | * configTime |
| | | * Source: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/time.c |
| | | * */ |
| | | void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) |
| | | { |
| | | if(sntp_enabled()){ |
| | | sntp_stop(); |
| | | } |
| | | sntp_setoperatingmode(SNTP_OPMODE_POLL); |
| | | sntp_setservername(0, (char*)server1); |
| | | sntp_setservername(1, (char*)server2); |
| | | sntp_setservername(2, (char*)server3); |
| | | sntp_init(); |
| | | setTimeZone(-gmtOffset_sec, daylightOffset_sec); |
| | | } |
| | | |
| | | /* |
| | | * configTzTime |
| | | * sntp setup using TZ environment variable |
| | | * */ |
| | | void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3) |
| | | { |
| | | if(sntp_enabled()){ |
| | | sntp_stop(); |
| | | } |
| | | sntp_setoperatingmode(SNTP_OPMODE_POLL); |
| | | sntp_setservername(0, (char*)server1); |
| | | sntp_setservername(1, (char*)server2); |
| | | sntp_setservername(2, (char*)server3); |
| | | sntp_init(); |
| | | setenv("TZ", tz, 1); |
| | | tzset(); |
| | | } |
| | | |
| | | bool getLocalTime(struct tm * info, uint32_t ms) |
| | | { |
| | | uint32_t start = millis(); |
| | | time_t now; |
| | | while((millis()-start) <= ms) { |
| | | time(&now); |
| | | localtime_r(&now, info); |
| | | if(info->tm_year > (2016 - 1900)){ |
| | | return true; |
| | | } |
| | | delay(10); |
| | | } |
| | | return false; |
| | | } |
| | | |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-timer.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/xtensa_api.h" |
| | | #include "freertos/task.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "soc/timer_group_struct.h" |
| | | #include "soc/dport_reg.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | |
| | | #define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock) |
| | | #define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock) |
| | | |
| | | typedef struct { |
| | | union { |
| | | struct { |
| | | uint32_t reserved0: 10; |
| | | uint32_t alarm_en: 1; /*When set alarm is enabled*/ |
| | | uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/ |
| | | uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/ |
| | | uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/ |
| | | uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/ |
| | | uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/ |
| | | uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/ |
| | | }; |
| | | uint32_t val; |
| | | } config; |
| | | uint32_t cnt_low; /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/ |
| | | uint32_t cnt_high; /*Register to store timer 0 time-base counter current value higher 32 bits.*/ |
| | | uint32_t update; /*Write any value will trigger a timer 0 time-base counter value update (timer 0 current value will be stored in registers above)*/ |
| | | uint32_t alarm_low; /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/ |
| | | uint32_t alarm_high; /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/ |
| | | uint32_t load_low; /*Lower 32 bits of the value that will load into timer 0 time-base counter*/ |
| | | uint32_t load_high; /*higher 32 bits of the value that will load into timer 0 time-base counter*/ |
| | | uint32_t reload; /*Write any value will trigger timer 0 time-base counter reload*/ |
| | | } hw_timer_reg_t; |
| | | |
| | | typedef struct hw_timer_s { |
| | | hw_timer_reg_t * dev; |
| | | uint8_t num; |
| | | uint8_t group; |
| | | uint8_t timer; |
| | | portMUX_TYPE lock; |
| | | } hw_timer_t; |
| | | |
| | | static hw_timer_t hw_timer[4] = { |
| | | {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE),0,0,0,portMUX_INITIALIZER_UNLOCKED}, |
| | | {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x0024),1,0,1,portMUX_INITIALIZER_UNLOCKED}, |
| | | {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1000),2,1,0,portMUX_INITIALIZER_UNLOCKED}, |
| | | {(hw_timer_reg_t *)(DR_REG_TIMERGROUP0_BASE + 0x1024),3,1,1,portMUX_INITIALIZER_UNLOCKED} |
| | | }; |
| | | |
| | | typedef void (*voidFuncPtr)(void); |
| | | static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0}; |
| | | |
| | | void IRAM_ATTR __timerISR(void * arg){ |
| | | 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; |
| | | uint8_t status = (s1 & 3) << 2 | (s0 & 3); |
| | | uint8_t i = 4; |
| | | //restart the timers that should autoreload |
| | | while(i--){ |
| | | hw_timer_reg_t * dev = hw_timer[i].dev; |
| | | if((status & (1 << i)) && dev->config.autoreload){ |
| | | dev->config.alarm_en = 1; |
| | | } |
| | | } |
| | | i = 4; |
| | | //call callbacks |
| | | while(i--){ |
| | | if(__timerInterruptHandlers[i] && (status & (1 << i))){ |
| | | __timerInterruptHandlers[i](); |
| | | } |
| | | } |
| | | } |
| | | |
| | | uint64_t timerRead(hw_timer_t *timer){ |
| | | timer->dev->update = 1; |
| | | uint64_t h = timer->dev->cnt_high; |
| | | uint64_t l = timer->dev->cnt_low; |
| | | return (h << 32) | l; |
| | | } |
| | | |
| | | uint64_t timerAlarmRead(hw_timer_t *timer){ |
| | | uint64_t h = timer->dev->alarm_high; |
| | | uint64_t l = timer->dev->alarm_low; |
| | | return (h << 32) | l; |
| | | } |
| | | |
| | | void timerWrite(hw_timer_t *timer, uint64_t val){ |
| | | timer->dev->load_high = (uint32_t) (val >> 32); |
| | | timer->dev->load_low = (uint32_t) (val); |
| | | timer->dev->reload = 1; |
| | | } |
| | | |
| | | void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ |
| | | timer->dev->alarm_high = (uint32_t) (alarm_value >> 32); |
| | | timer->dev->alarm_low = (uint32_t) alarm_value; |
| | | timer->dev->config.autoreload = autoreload; |
| | | } |
| | | |
| | | void timerSetConfig(hw_timer_t *timer, uint32_t config){ |
| | | timer->dev->config.val = config; |
| | | } |
| | | |
| | | uint32_t timerGetConfig(hw_timer_t *timer){ |
| | | return timer->dev->config.val; |
| | | } |
| | | |
| | | void timerSetCountUp(hw_timer_t *timer, bool countUp){ |
| | | timer->dev->config.increase = countUp; |
| | | } |
| | | |
| | | bool timerGetCountUp(hw_timer_t *timer){ |
| | | return timer->dev->config.increase; |
| | | } |
| | | |
| | | void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ |
| | | timer->dev->config.autoreload = autoreload; |
| | | } |
| | | |
| | | bool timerGetAutoReload(hw_timer_t *timer){ |
| | | return timer->dev->config.autoreload; |
| | | } |
| | | |
| | | void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536 |
| | | if(!divider){ |
| | | divider = 0xFFFF; |
| | | } else if(divider == 1){ |
| | | divider = 2; |
| | | } |
| | | int timer_en = timer->dev->config.enable; |
| | | timer->dev->config.enable = 0; |
| | | timer->dev->config.divider = divider; |
| | | timer->dev->config.enable = timer_en; |
| | | } |
| | | |
| | | uint16_t timerGetDivider(hw_timer_t *timer){ |
| | | return timer->dev->config.divider; |
| | | } |
| | | |
| | | void timerStart(hw_timer_t *timer){ |
| | | timer->dev->config.enable = 1; |
| | | } |
| | | |
| | | void timerStop(hw_timer_t *timer){ |
| | | timer->dev->config.enable = 0; |
| | | } |
| | | |
| | | void timerRestart(hw_timer_t *timer){ |
| | | timer->dev->config.enable = 0; |
| | | timer->dev->config.enable = 1; |
| | | } |
| | | |
| | | bool timerStarted(hw_timer_t *timer){ |
| | | return timer->dev->config.enable; |
| | | } |
| | | |
| | | void timerAlarmEnable(hw_timer_t *timer){ |
| | | timer->dev->config.alarm_en = 1; |
| | | } |
| | | |
| | | void timerAlarmDisable(hw_timer_t *timer){ |
| | | timer->dev->config.alarm_en = 0; |
| | | } |
| | | |
| | | bool timerAlarmEnabled(hw_timer_t *timer){ |
| | | return timer->dev->config.alarm_en; |
| | | } |
| | | |
| | | static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
| | | hw_timer_t * timer = (hw_timer_t *)arg; |
| | | if(ev_type == APB_BEFORE_CHANGE){ |
| | | timer->dev->config.enable = 0; |
| | | } else { |
| | | old_apb /= 1000000; |
| | | new_apb /= 1000000; |
| | | timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb; |
| | | timer->dev->config.enable = 1; |
| | | } |
| | | } |
| | | |
| | | hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ |
| | | if(num > 3){ |
| | | return NULL; |
| | | } |
| | | hw_timer_t * timer = &hw_timer[num]; |
| | | if(timer->group) { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST); |
| | | TIMERG1.int_ena.val &= ~BIT(timer->timer); |
| | | } else { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST); |
| | | TIMERG0.int_ena.val &= ~BIT(timer->timer); |
| | | } |
| | | timer->dev->config.enable = 0; |
| | | timerSetDivider(timer, divider); |
| | | timerSetCountUp(timer, countUp); |
| | | timerSetAutoReload(timer, false); |
| | | timerAttachInterrupt(timer, NULL, false); |
| | | timerWrite(timer, 0); |
| | | timer->dev->config.enable = 1; |
| | | addApbChangeCallback(timer, _on_apb_change); |
| | | return timer; |
| | | } |
| | | |
| | | void timerEnd(hw_timer_t *timer){ |
| | | timer->dev->config.enable = 0; |
| | | timerAttachInterrupt(timer, NULL, false); |
| | | removeApbChangeCallback(timer, _on_apb_change); |
| | | } |
| | | |
| | | void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ |
| | | static bool initialized = false; |
| | | static intr_handle_t intr_handle = NULL; |
| | | if(intr_handle){ |
| | | esp_intr_disable(intr_handle); |
| | | } |
| | | if(fn == NULL){ |
| | | timer->dev->config.level_int_en = 0; |
| | | timer->dev->config.edge_int_en = 0; |
| | | timer->dev->config.alarm_en = 0; |
| | | if(timer->num & 2){ |
| | | TIMERG1.int_ena.val &= ~BIT(timer->timer); |
| | | } else { |
| | | TIMERG0.int_ena.val &= ~BIT(timer->timer); |
| | | } |
| | | __timerInterruptHandlers[timer->num] = NULL; |
| | | } else { |
| | | __timerInterruptHandlers[timer->num] = fn; |
| | | timer->dev->config.level_int_en = edge?0:1;//When set, an alarm will generate a level type interrupt. |
| | | timer->dev->config.edge_int_en = edge?1:0;//When set, an alarm will generate an edge type interrupt. |
| | | int intr_source = 0; |
| | | if(!edge){ |
| | | if(timer->group){ |
| | | intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer->timer; |
| | | } else { |
| | | intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer->timer; |
| | | } |
| | | } else { |
| | | if(timer->group){ |
| | | intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer->timer; |
| | | } else { |
| | | intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer->timer; |
| | | } |
| | | } |
| | | if(!initialized){ |
| | | initialized = true; |
| | | esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle); |
| | | } else { |
| | | intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle)); |
| | | } |
| | | if(timer->group){ |
| | | TIMERG1.int_ena.val |= BIT(timer->timer); |
| | | } else { |
| | | TIMERG0.int_ena.val |= BIT(timer->timer); |
| | | } |
| | | } |
| | | if(intr_handle){ |
| | | esp_intr_enable(intr_handle); |
| | | } |
| | | } |
| | | |
| | | void timerDetachInterrupt(hw_timer_t *timer){ |
| | | timerAttachInterrupt(timer, NULL, false); |
| | | } |
| | | |
| | | uint64_t timerReadMicros(hw_timer_t *timer){ |
| | | uint64_t timer_val = timerRead(timer); |
| | | uint16_t div = timerGetDivider(timer); |
| | | return timer_val * div / (getApbFrequency() / 1000000); |
| | | } |
| | | |
| | | double timerReadSeconds(hw_timer_t *timer){ |
| | | uint64_t timer_val = timerRead(timer); |
| | | uint16_t div = timerGetDivider(timer); |
| | | return (double)timer_val * div / getApbFrequency(); |
| | | } |
| | | |
| | | uint64_t timerAlarmReadMicros(hw_timer_t *timer){ |
| | | uint64_t timer_val = timerAlarmRead(timer); |
| | | uint16_t div = timerGetDivider(timer); |
| | | return timer_val * div / (getApbFrequency() / 1000000); |
| | | } |
| | | |
| | | double timerAlarmReadSeconds(hw_timer_t *timer){ |
| | | uint64_t timer_val = timerAlarmRead(timer); |
| | | uint16_t div = timerGetDivider(timer); |
| | | return (double)timer_val * div / getApbFrequency(); |
| | | } |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef MAIN_ESP32_HAL_TIMER_H_ |
| | | #define MAIN_ESP32_HAL_TIMER_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | |
| | | struct hw_timer_s; |
| | | typedef struct hw_timer_s hw_timer_t; |
| | | |
| | | hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp); |
| | | void timerEnd(hw_timer_t *timer); |
| | | |
| | | void timerSetConfig(hw_timer_t *timer, uint32_t config); |
| | | uint32_t timerGetConfig(hw_timer_t *timer); |
| | | |
| | | void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge); |
| | | void timerDetachInterrupt(hw_timer_t *timer); |
| | | |
| | | void timerStart(hw_timer_t *timer); |
| | | void timerStop(hw_timer_t *timer); |
| | | void timerRestart(hw_timer_t *timer); |
| | | void timerWrite(hw_timer_t *timer, uint64_t val); |
| | | void timerSetDivider(hw_timer_t *timer, uint16_t divider); |
| | | void timerSetCountUp(hw_timer_t *timer, bool countUp); |
| | | void timerSetAutoReload(hw_timer_t *timer, bool autoreload); |
| | | |
| | | bool timerStarted(hw_timer_t *timer); |
| | | uint64_t timerRead(hw_timer_t *timer); |
| | | uint64_t timerReadMicros(hw_timer_t *timer); |
| | | double timerReadSeconds(hw_timer_t *timer); |
| | | uint16_t timerGetDivider(hw_timer_t *timer); |
| | | bool timerGetCountUp(hw_timer_t *timer); |
| | | bool timerGetAutoReload(hw_timer_t *timer); |
| | | |
| | | void timerAlarmEnable(hw_timer_t *timer); |
| | | void timerAlarmDisable(hw_timer_t *timer); |
| | | void timerAlarmWrite(hw_timer_t *timer, uint64_t interruptAt, bool autoreload); |
| | | |
| | | bool timerAlarmEnabled(hw_timer_t *timer); |
| | | uint64_t timerAlarmRead(hw_timer_t *timer); |
| | | uint64_t timerAlarmReadMicros(hw_timer_t *timer); |
| | | double timerAlarmReadSeconds(hw_timer_t *timer); |
| | | |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_TIMER_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-touch.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "soc/rtc_io_reg.h" |
| | | #include "soc/rtc_cntl_reg.h" |
| | | #include "soc/sens_reg.h" |
| | | |
| | | static uint16_t __touchSleepCycles = 0x1000; |
| | | static uint16_t __touchMeasureCycles = 0x1000; |
| | | |
| | | typedef void (*voidFuncPtr)(void); |
| | | static voidFuncPtr __touchInterruptHandlers[10] = {0,}; |
| | | static intr_handle_t touch_intr_handle = NULL; |
| | | |
| | | void IRAM_ATTR __touchISR(void * arg) |
| | | { |
| | | uint32_t pad_intr = READ_PERI_REG(SENS_SAR_TOUCH_CTRL2_REG) & 0x3ff; |
| | | uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG); |
| | | uint8_t i = 0; |
| | | //clear interrupt |
| | | WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr); |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR); |
| | | |
| | | if (rtc_intr & RTC_CNTL_TOUCH_INT_ST) { |
| | | for (i = 0; i < 10; ++i) { |
| | | if ((pad_intr >> i) & 0x01) { |
| | | if(__touchInterruptHandlers[i]){ |
| | | __touchInterruptHandlers[i](); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void __touchSetCycles(uint16_t measure, uint16_t sleep) |
| | | { |
| | | __touchSleepCycles = sleep; |
| | | __touchMeasureCycles = measure; |
| | | //Touch pad SleepCycle Time |
| | | SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S); |
| | | //Touch Pad Measure Time |
| | | SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S); |
| | | } |
| | | |
| | | void __touchInit() |
| | | { |
| | | static bool initialized = false; |
| | | if(initialized){ |
| | | return; |
| | | } |
| | | initialized = true; |
| | | SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S); |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR); |
| | | //clear touch enable |
| | | WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0); |
| | | SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN); |
| | | |
| | | __touchSetCycles(__touchMeasureCycles, __touchSleepCycles); |
| | | |
| | | esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __touchISR, NULL, &touch_intr_handle); |
| | | } |
| | | |
| | | uint16_t __touchRead(uint8_t pin) |
| | | { |
| | | int8_t pad = digitalPinToTouchChannel(pin); |
| | | if(pad < 0){ |
| | | return 0; |
| | | } |
| | | |
| | | pinMode(pin, ANALOG); |
| | | |
| | | __touchInit(); |
| | | |
| | | uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG); |
| | | //Disable Intr & enable touch pad |
| | | WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, |
| | | (v0 & ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)))) |
| | | | (1 << (pad + SENS_TOUCH_PAD_WORKEN_S))); |
| | | |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (pad + SENS_TOUCH_PAD_WORKEN_S))); |
| | | |
| | | uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4; |
| | | WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg) |
| | | & ~(RTC_IO_TOUCH_PAD0_DAC_M)) |
| | | | (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope |
| | | | RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level |
| | | | RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO |
| | | | RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on |
| | | |
| | | //force oneTime test start |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M); |
| | | |
| | | SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S); |
| | | |
| | | while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {}; |
| | | |
| | | uint16_t touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (pad / 2) * 4) >> ((pad & 1) ? SENS_TOUCH_MEAS_OUT1_S : SENS_TOUCH_MEAS_OUT0_S); |
| | | |
| | | //clear touch force ,select the Touch mode is Timer |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M); |
| | | |
| | | //restore previous value |
| | | WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0); |
| | | return touch_value; |
| | | } |
| | | |
| | | void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold) |
| | | { |
| | | int8_t pad = digitalPinToTouchChannel(pin); |
| | | if(pad < 0){ |
| | | return; |
| | | } |
| | | |
| | | pinMode(pin, ANALOG); |
| | | |
| | | __touchInit(); |
| | | |
| | | __touchInterruptHandlers[pad] = userFunc; |
| | | |
| | | //clear touch force ,select the Touch mode is Timer |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M); |
| | | |
| | | //interrupt when touch value < threshold |
| | | CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_SEL); |
| | | //Intr will give ,when SET0 < threshold |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_1EN); |
| | | //Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable |
| | | SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA); |
| | | |
| | | //set threshold |
| | | uint8_t shift = (pad & 1) ? SENS_TOUCH_OUT_TH1_S : SENS_TOUCH_OUT_TH0_S; |
| | | SET_PERI_REG_BITS((SENS_SAR_TOUCH_THRES1_REG + (pad / 2) * 4), SENS_TOUCH_OUT_TH0, threshold, shift); |
| | | |
| | | uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4; |
| | | WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg) |
| | | & ~(RTC_IO_TOUCH_PAD0_DAC_M)) |
| | | | (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope |
| | | | RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level |
| | | | RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO |
| | | | RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on |
| | | |
| | | //Enable Digital rtc control :work mode and out mode |
| | | SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, |
| | | (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \ |
| | | (1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \ |
| | | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))); |
| | | } |
| | | |
| | | extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead"))); |
| | | extern void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold) __attribute__ ((weak, alias("__touchAttachInterrupt"))); |
| | | extern void touchSetCycles(uint16_t measure, uint16_t sleep) __attribute__ ((weak, alias("__touchSetCycles"))); |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef MAIN_ESP32_HAL_TOUCH_H_ |
| | | #define MAIN_ESP32_HAL_TOUCH_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include "esp32-hal.h" |
| | | |
| | | /* |
| | | * Set cycles that measurement operation takes |
| | | * The result from touchRead, threshold and detection |
| | | * accuracy depend on these values. Defaults are |
| | | * 0x1000 for measure and 0x1000 for sleep. |
| | | * With default values touchRead takes 0.5ms |
| | | * */ |
| | | void touchSetCycles(uint16_t measure, uint16_t sleep); |
| | | |
| | | /* |
| | | * Read touch pad (values close to 0 mean touch detected) |
| | | * You can use this method to chose a good threshold value |
| | | * to use as value for touchAttachInterrupt |
| | | * */ |
| | | uint16_t touchRead(uint8_t pin); |
| | | |
| | | /* |
| | | * Set function to be called if touch pad value falls |
| | | * below the given threshold. Use touchRead to determine |
| | | * a proper threshold between touched and untouched state |
| | | * */ |
| | | void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_TOUCH_H_ */ |
| New file |
| | |
| | | // 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. |
| | | |
| | | #include "esp32-hal-uart.h" |
| | | #include "esp32-hal.h" |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "freertos/queue.h" |
| | | #include "freertos/semphr.h" |
| | | #include "rom/ets_sys.h" |
| | | #include "esp_attr.h" |
| | | #include "esp_intr.h" |
| | | #include "rom/uart.h" |
| | | #include "soc/uart_reg.h" |
| | | #include "soc/uart_struct.h" |
| | | #include "soc/io_mux_reg.h" |
| | | #include "soc/gpio_sig_map.h" |
| | | #include "soc/dport_reg.h" |
| | | #include "soc/rtc.h" |
| | | #include "esp_intr_alloc.h" |
| | | |
| | | #define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0))) |
| | | #define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0))) |
| | | #define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0))) |
| | | #define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0))) |
| | | |
| | | static int s_uart_debug_nr = 0; |
| | | |
| | | struct uart_struct_t { |
| | | uart_dev_t * dev; |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | xSemaphoreHandle lock; |
| | | #endif |
| | | uint8_t num; |
| | | xQueueHandle queue; |
| | | intr_handle_t intr_handle; |
| | | }; |
| | | |
| | | #if CONFIG_DISABLE_HAL_LOCKS |
| | | #define UART_MUTEX_LOCK() |
| | | #define UART_MUTEX_UNLOCK() |
| | | |
| | | static uart_t _uart_bus_array[3] = { |
| | | {(volatile uart_dev_t *)(DR_REG_UART_BASE), 0, NULL, NULL}, |
| | | {(volatile uart_dev_t *)(DR_REG_UART1_BASE), 1, NULL, NULL}, |
| | | {(volatile uart_dev_t *)(DR_REG_UART2_BASE), 2, NULL, NULL} |
| | | }; |
| | | #else |
| | | #define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) |
| | | #define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock) |
| | | |
| | | static uart_t _uart_bus_array[3] = { |
| | | {(volatile uart_dev_t *)(DR_REG_UART_BASE), NULL, 0, NULL, NULL}, |
| | | {(volatile uart_dev_t *)(DR_REG_UART1_BASE), NULL, 1, NULL, NULL}, |
| | | {(volatile uart_dev_t *)(DR_REG_UART2_BASE), NULL, 2, NULL, NULL} |
| | | }; |
| | | #endif |
| | | |
| | | static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb); |
| | | |
| | | static void IRAM_ATTR _uart_isr(void *arg) |
| | | { |
| | | uint8_t i, c; |
| | | BaseType_t xHigherPriorityTaskWoken; |
| | | uart_t* uart; |
| | | |
| | | for(i=0;i<3;i++){ |
| | | uart = &_uart_bus_array[i]; |
| | | if(uart->intr_handle == NULL){ |
| | | continue; |
| | | } |
| | | uart->dev->int_clr.rxfifo_full = 1; |
| | | uart->dev->int_clr.frm_err = 1; |
| | | uart->dev->int_clr.rxfifo_tout = 1; |
| | | while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) { |
| | | c = uart->dev->fifo.rw_byte; |
| | | if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) { |
| | | xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (xHigherPriorityTaskWoken) { |
| | | portYIELD_FROM_ISR(); |
| | | } |
| | | } |
| | | |
| | | void uartEnableInterrupt(uart_t* uart) |
| | | { |
| | | UART_MUTEX_LOCK(); |
| | | uart->dev->conf1.rxfifo_full_thrhd = 112; |
| | | uart->dev->conf1.rx_tout_thrhd = 2; |
| | | uart->dev->conf1.rx_tout_en = 1; |
| | | uart->dev->int_ena.rxfifo_full = 1; |
| | | uart->dev->int_ena.frm_err = 1; |
| | | uart->dev->int_ena.rxfifo_tout = 1; |
| | | uart->dev->int_clr.val = 0xffffffff; |
| | | |
| | | esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ESP_INTR_FLAG_IRAM, _uart_isr, NULL, &uart->intr_handle); |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void uartDisableInterrupt(uart_t* uart) |
| | | { |
| | | UART_MUTEX_LOCK(); |
| | | uart->dev->conf1.val = 0; |
| | | uart->dev->int_ena.val = 0; |
| | | uart->dev->int_clr.val = 0xffffffff; |
| | | |
| | | esp_intr_free(uart->intr_handle); |
| | | uart->intr_handle = NULL; |
| | | |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void uartDetachRx(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false); |
| | | uartDisableInterrupt(uart); |
| | | } |
| | | |
| | | void uartDetachTx(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | pinMatrixOutDetach(UART_TXD_IDX(uart->num), false, false); |
| | | } |
| | | |
| | | void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted) |
| | | { |
| | | if(uart == NULL || rxPin > 39) { |
| | | return; |
| | | } |
| | | pinMode(rxPin, INPUT); |
| | | pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted); |
| | | uartEnableInterrupt(uart); |
| | | } |
| | | |
| | | void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted) |
| | | { |
| | | if(uart == NULL || txPin > 39) { |
| | | return; |
| | | } |
| | | pinMode(txPin, OUTPUT); |
| | | pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false); |
| | | } |
| | | |
| | | uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted) |
| | | { |
| | | if(uart_nr > 2) { |
| | | return NULL; |
| | | } |
| | | |
| | | if(rxPin == -1 && txPin == -1) { |
| | | return NULL; |
| | | } |
| | | |
| | | uart_t* uart = &_uart_bus_array[uart_nr]; |
| | | |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(uart->lock == NULL) { |
| | | uart->lock = xSemaphoreCreateMutex(); |
| | | if(uart->lock == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | if(queueLen && uart->queue == NULL) { |
| | | uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue |
| | | if(uart->queue == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | if(uart_nr == 1){ |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST); |
| | | } else if(uart_nr == 2){ |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST); |
| | | } else { |
| | | DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN); |
| | | DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST); |
| | | } |
| | | uartFlush(uart); |
| | | uartSetBaudRate(uart, baudrate); |
| | | UART_MUTEX_LOCK(); |
| | | uart->dev->conf0.val = config; |
| | | #define TWO_STOP_BITS_CONF 0x3 |
| | | #define ONE_STOP_BITS_CONF 0x1 |
| | | |
| | | if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) { |
| | | uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF; |
| | | uart->dev->rs485_conf.dl1_en = 1; |
| | | } |
| | | UART_MUTEX_UNLOCK(); |
| | | |
| | | if(rxPin != -1) { |
| | | uartAttachRx(uart, rxPin, inverted); |
| | | } |
| | | |
| | | if(txPin != -1) { |
| | | uartAttachTx(uart, txPin, inverted); |
| | | } |
| | | |
| | | addApbChangeCallback(uart, uart_on_apb_change); |
| | | return uart; |
| | | } |
| | | |
| | | void uartEnd(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | removeApbChangeCallback(uart, uart_on_apb_change); |
| | | |
| | | UART_MUTEX_LOCK(); |
| | | if(uart->queue != NULL) { |
| | | vQueueDelete(uart->queue); |
| | | uart->queue = NULL; |
| | | } |
| | | |
| | | uart->dev->conf0.val = 0; |
| | | |
| | | UART_MUTEX_UNLOCK(); |
| | | |
| | | uartDetachRx(uart); |
| | | uartDetachTx(uart); |
| | | } |
| | | |
| | | size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) { |
| | | if(uart == NULL) { |
| | | return 0; |
| | | } |
| | | |
| | | UART_MUTEX_LOCK(); |
| | | if(uart->queue != NULL) { |
| | | vQueueDelete(uart->queue); |
| | | uart->queue = xQueueCreate(new_size, sizeof(uint8_t)); |
| | | if(uart->queue == NULL) { |
| | | return NULL; |
| | | } |
| | | } |
| | | UART_MUTEX_UNLOCK(); |
| | | |
| | | return new_size; |
| | | } |
| | | |
| | | uint32_t uartAvailable(uart_t* uart) |
| | | { |
| | | if(uart == NULL || uart->queue == NULL) { |
| | | return 0; |
| | | } |
| | | return uxQueueMessagesWaiting(uart->queue); |
| | | } |
| | | |
| | | uint32_t uartAvailableForWrite(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return 0; |
| | | } |
| | | return 0x7f - uart->dev->status.txfifo_cnt; |
| | | } |
| | | |
| | | uint8_t uartRead(uart_t* uart) |
| | | { |
| | | if(uart == NULL || uart->queue == NULL) { |
| | | return 0; |
| | | } |
| | | uint8_t c; |
| | | if(xQueueReceive(uart->queue, &c, 0)) { |
| | | return c; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | uint8_t uartPeek(uart_t* uart) |
| | | { |
| | | if(uart == NULL || uart->queue == NULL) { |
| | | return 0; |
| | | } |
| | | uint8_t c; |
| | | if(xQueuePeek(uart->queue, &c, 0)) { |
| | | return c; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | void uartWrite(uart_t* uart, uint8_t c) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | UART_MUTEX_LOCK(); |
| | | while(uart->dev->status.txfifo_cnt == 0x7F); |
| | | uart->dev->fifo.rw_byte = c; |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | UART_MUTEX_LOCK(); |
| | | while(len) { |
| | | while(uart->dev->status.txfifo_cnt == 0x7F); |
| | | uart->dev->fifo.rw_byte = *data++; |
| | | len--; |
| | | } |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void uartFlush(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | |
| | | UART_MUTEX_LOCK(); |
| | | while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out); |
| | | |
| | | //Due to hardware issue, we can not use fifo_rst to reset uart fifo. |
| | | //See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later. |
| | | |
| | | // we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`. |
| | | while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) { |
| | | READ_PERI_REG(UART_FIFO_REG(uart->num)); |
| | | } |
| | | |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | void uartSetBaudRate(uart_t* uart, uint32_t baud_rate) |
| | | { |
| | | if(uart == NULL) { |
| | | return; |
| | | } |
| | | UART_MUTEX_LOCK(); |
| | | uint32_t clk_div = ((getApbFrequency()<<4)/baud_rate); |
| | | uart->dev->clk_div.div_int = clk_div>>4 ; |
| | | uart->dev->clk_div.div_frag = clk_div & 0xf; |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) |
| | | { |
| | | uart_t* uart = (uart_t*)arg; |
| | | if(ev_type == APB_BEFORE_CHANGE){ |
| | | UART_MUTEX_LOCK(); |
| | | //disabple interrupt |
| | | uart->dev->int_ena.val = 0; |
| | | uart->dev->int_clr.val = 0xffffffff; |
| | | // read RX fifo |
| | | uint8_t c; |
| | | BaseType_t xHigherPriorityTaskWoken; |
| | | while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) { |
| | | c = uart->dev->fifo.rw_byte; |
| | | if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) { |
| | | xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken); |
| | | } |
| | | } |
| | | // wait TX empty |
| | | while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out); |
| | | } else { |
| | | //todo: |
| | | // set baudrate |
| | | uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F); |
| | | uint32_t baud_rate = ((old_apb<<4)/clk_div); |
| | | clk_div = ((new_apb<<4)/baud_rate); |
| | | uart->dev->clk_div.div_int = clk_div>>4 ; |
| | | uart->dev->clk_div.div_frag = clk_div & 0xf; |
| | | //enable interrupts |
| | | uart->dev->int_ena.rxfifo_full = 1; |
| | | uart->dev->int_ena.frm_err = 1; |
| | | uart->dev->int_ena.rxfifo_tout = 1; |
| | | uart->dev->int_clr.val = 0xffffffff; |
| | | UART_MUTEX_UNLOCK(); |
| | | } |
| | | } |
| | | |
| | | uint32_t uartGetBaudRate(uart_t* uart) |
| | | { |
| | | if(uart == NULL) { |
| | | return 0; |
| | | } |
| | | uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F); |
| | | return ((getApbFrequency()<<4)/clk_div); |
| | | } |
| | | |
| | | static void IRAM_ATTR uart0_write_char(char c) |
| | | { |
| | | while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F); |
| | | ESP_REG(DR_REG_UART_BASE) = c; |
| | | } |
| | | |
| | | static void IRAM_ATTR uart1_write_char(char c) |
| | | { |
| | | while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F); |
| | | ESP_REG(DR_REG_UART1_BASE) = c; |
| | | } |
| | | |
| | | static void IRAM_ATTR uart2_write_char(char c) |
| | | { |
| | | while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F); |
| | | ESP_REG(DR_REG_UART2_BASE) = c; |
| | | } |
| | | |
| | | void uart_install_putc() |
| | | { |
| | | switch(s_uart_debug_nr) { |
| | | case 0: |
| | | ets_install_putc1((void (*)(char)) &uart0_write_char); |
| | | break; |
| | | case 1: |
| | | ets_install_putc1((void (*)(char)) &uart1_write_char); |
| | | break; |
| | | case 2: |
| | | ets_install_putc1((void (*)(char)) &uart2_write_char); |
| | | break; |
| | | default: |
| | | ets_install_putc1(NULL); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | void uartSetDebug(uart_t* uart) |
| | | { |
| | | if(uart == NULL || uart->num > 2) { |
| | | 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; |
| | | uart_install_putc(); |
| | | } |
| | | |
| | | int uartGetDebug() |
| | | { |
| | | return s_uart_debug_nr; |
| | | } |
| | | |
| | | int log_printf(const char *format, ...) |
| | | { |
| | | if(s_uart_debug_nr < 0){ |
| | | return 0; |
| | | } |
| | | static char loc_buf[64]; |
| | | char * temp = loc_buf; |
| | | int len; |
| | | va_list arg; |
| | | va_list copy; |
| | | va_start(arg, format); |
| | | va_copy(copy, arg); |
| | | len = vsnprintf(NULL, 0, format, arg); |
| | | va_end(copy); |
| | | if(len >= sizeof(loc_buf)){ |
| | | temp = (char*)malloc(len+1); |
| | | if(temp == NULL) { |
| | | return 0; |
| | | } |
| | | } |
| | | vsnprintf(temp, len+1, format, arg); |
| | | #if !CONFIG_DISABLE_HAL_LOCKS |
| | | if(_uart_bus_array[s_uart_debug_nr].lock){ |
| | | xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY); |
| | | ets_printf("%s", temp); |
| | | xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock); |
| | | } else { |
| | | ets_printf("%s", temp); |
| | | } |
| | | #else |
| | | ets_printf("%s", temp); |
| | | #endif |
| | | va_end(arg); |
| | | if(len >= sizeof(loc_buf)){ |
| | | free(temp); |
| | | } |
| | | return len; |
| | | } |
| | | |
| | | /* |
| | | * if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two. |
| | | * This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses. |
| | | */ |
| | | unsigned long uartBaudrateDetect(uart_t *uart, bool flg) |
| | | { |
| | | while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num) |
| | | if(flg) return 0; |
| | | ets_delay_us(1000); |
| | | } |
| | | |
| | | UART_MUTEX_LOCK(); |
| | | unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12; |
| | | UART_MUTEX_UNLOCK(); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | /* |
| | | * To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is |
| | | * detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is |
| | | * rounded to the closed real baudrate. |
| | | */ |
| | | unsigned long |
| | | uartDetectBaudrate(uart_t *uart) |
| | | { |
| | | static bool uartStateDetectingBaudrate = false; |
| | | |
| | | if(!uartStateDetectingBaudrate) { |
| | | uart->dev->auto_baud.glitch_filt = 0x08; |
| | | uart->dev->auto_baud.en = 0; |
| | | uart->dev->auto_baud.en = 1; |
| | | uartStateDetectingBaudrate = true; |
| | | } |
| | | |
| | | unsigned long divisor = uartBaudrateDetect(uart, true); |
| | | if (!divisor) { |
| | | return 0; |
| | | } |
| | | |
| | | uart->dev->auto_baud.en = 0; |
| | | uartStateDetectingBaudrate = false; // Initialize for the next round |
| | | |
| | | unsigned long baudrate = getApbFrequency() / divisor; |
| | | |
| | | static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; |
| | | |
| | | size_t i; |
| | | for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate |
| | | { |
| | | if (baudrate <= default_rates[i]) |
| | | { |
| | | if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) { |
| | | i--; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return default_rates[i]; |
| | | } |
| | | |
| | | /* |
| | | * Returns the status of the RX state machine, if the value is non-zero the state machine is active. |
| | | */ |
| | | bool uartRxActive(uart_t* uart) { |
| | | return uart->dev->status.st_urx_out != 0; |
| | | } |
| New file |
| | |
| | | // 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. |
| | | |
| | | #ifndef MAIN_ESP32_HAL_UART_H_ |
| | | #define MAIN_ESP32_HAL_UART_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | #include <stdlib.h> |
| | | |
| | | #define SERIAL_5N1 0x8000010 |
| | | #define SERIAL_6N1 0x8000014 |
| | | #define SERIAL_7N1 0x8000018 |
| | | #define SERIAL_8N1 0x800001c |
| | | #define SERIAL_5N2 0x8000030 |
| | | #define SERIAL_6N2 0x8000034 |
| | | #define SERIAL_7N2 0x8000038 |
| | | #define SERIAL_8N2 0x800003c |
| | | #define SERIAL_5E1 0x8000012 |
| | | #define SERIAL_6E1 0x8000016 |
| | | #define SERIAL_7E1 0x800001a |
| | | #define SERIAL_8E1 0x800001e |
| | | #define SERIAL_5E2 0x8000032 |
| | | #define SERIAL_6E2 0x8000036 |
| | | #define SERIAL_7E2 0x800003a |
| | | #define SERIAL_8E2 0x800003e |
| | | #define SERIAL_5O1 0x8000013 |
| | | #define SERIAL_6O1 0x8000017 |
| | | #define SERIAL_7O1 0x800001b |
| | | #define SERIAL_8O1 0x800001f |
| | | #define SERIAL_5O2 0x8000033 |
| | | #define SERIAL_6O2 0x8000037 |
| | | #define SERIAL_7O2 0x800003b |
| | | #define SERIAL_8O2 0x800003f |
| | | |
| | | struct uart_struct_t; |
| | | typedef struct uart_struct_t uart_t; |
| | | |
| | | uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted); |
| | | void uartEnd(uart_t* uart); |
| | | |
| | | uint32_t uartAvailable(uart_t* uart); |
| | | uint32_t uartAvailableForWrite(uart_t* uart); |
| | | uint8_t uartRead(uart_t* uart); |
| | | uint8_t uartPeek(uart_t* uart); |
| | | |
| | | void uartWrite(uart_t* uart, uint8_t c); |
| | | void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len); |
| | | |
| | | void uartFlush(uart_t* uart); |
| | | |
| | | void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); |
| | | uint32_t uartGetBaudRate(uart_t* uart); |
| | | |
| | | size_t uartResizeRxBuffer(uart_t* uart, size_t new_size); |
| | | |
| | | void uartSetDebug(uart_t* uart); |
| | | int uartGetDebug(); |
| | | |
| | | unsigned long uartDetectBaudrate(uart_t *uart); |
| | | |
| | | bool uartRxActive(uart_t* uart); |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* MAIN_ESP32_HAL_UART_H_ */ |
| New file |
| | |
| | | /* |
| | | Arduino.h - Main include file for the Arduino SDK |
| | | Copyright (c) 2005-2013 Arduino Team. All right reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef HAL_ESP32_HAL_H_ |
| | | #define HAL_ESP32_HAL_H_ |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | #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_system.h" |
| | | |
| | | #ifndef F_CPU |
| | | #define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U) |
| | | #endif |
| | | |
| | | //forward declaration from freertos/portmacro.h |
| | | void vPortYield(void); |
| | | void yield(void); |
| | | #define optimistic_yield(u) |
| | | |
| | | #define ESP_REG(addr) *((volatile uint32_t *)(addr)) |
| | | #define NOP() asm volatile ("nop") |
| | | |
| | | #include "esp32-hal-log.h" |
| | | #include "esp32-hal-matrix.h" |
| | | #include "esp32-hal-uart.h" |
| | | #include "esp32-hal-gpio.h" |
| | | #include "esp32-hal-touch.h" |
| | | #include "esp32-hal-dac.h" |
| | | #include "esp32-hal-adc.h" |
| | | #include "esp32-hal-spi.h" |
| | | #include "esp32-hal-i2c.h" |
| | | #include "esp32-hal-ledc.h" |
| | | #include "esp32-hal-rmt.h" |
| | | #include "esp32-hal-sigmadelta.h" |
| | | #include "esp32-hal-timer.h" |
| | | #include "esp32-hal-bt.h" |
| | | #include "esp32-hal-psram.h" |
| | | #include "esp32-hal-cpu.h" |
| | | |
| | | #ifndef BOARD_HAS_PSRAM |
| | | #ifdef CONFIG_SPIRAM_SUPPORT |
| | | #undef CONFIG_SPIRAM_SUPPORT |
| | | #endif |
| | | #endif |
| | | |
| | | //returns chip temperature in Celsius |
| | | float temperatureRead(); |
| | | |
| | | #if CONFIG_AUTOSTART_ARDUINO |
| | | //enable/disable WDT for Arduino's setup and loop functions |
| | | void enableLoopWDT(); |
| | | void disableLoopWDT(); |
| | | //feed WDT for the loop task |
| | | void feedLoopWDT(); |
| | | #endif |
| | | |
| | | //enable/disable WDT for the IDLE task on Core 0 (SYSTEM) |
| | | void enableCore0WDT(); |
| | | void disableCore0WDT(); |
| | | #ifndef CONFIG_FREERTOS_UNICORE |
| | | //enable/disable WDT for the IDLE task on Core 1 (Arduino) |
| | | void enableCore1WDT(); |
| | | void disableCore1WDT(); |
| | | #endif |
| | | |
| | | //if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore |
| | | //allows to easily handle all possible situations without repetitive code |
| | | BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode, |
| | | const char * const pcName, |
| | | const uint32_t usStackDepth, |
| | | void * const pvParameters, |
| | | UBaseType_t uxPriority, |
| | | TaskHandle_t * const pxCreatedTask, |
| | | const BaseType_t xCoreID ); |
| | | |
| | | unsigned long micros(); |
| | | unsigned long millis(); |
| | | void delay(uint32_t); |
| | | void delayMicroseconds(uint32_t us); |
| | | |
| | | #if !CONFIG_ESP32_PHY_AUTO_INIT |
| | | void arduino_phy_init(); |
| | | #endif |
| | | |
| | | #if !CONFIG_AUTOSTART_ARDUINO |
| | | void initArduino(); |
| | | #endif |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | #endif /* HAL_ESP32_HAL_H_ */ |
| New file |
| | |
| | | // esp8266-compat.h - Compatibility functions to help ESP8266 libraries and user code run on ESP32 |
| | | |
| | | // Copyright (c) 2017 Evandro Luis Copercini. All rights reserved. |
| | | // |
| | | // 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 _ESP8266_COMPAT_H_ |
| | | #define _ESP8266_COMPAT_H_ |
| | | |
| | | #define ICACHE_FLASH_ATTR |
| | | #define ICACHE_RAM_ATTR IRAM_ATTR |
| | | |
| | | |
| | | #endif /* _ESP8266_COMPAT_H_ */ |
| New file |
| | |
| | | libb64: Base64 Encoding/Decoding Routines |
| | | ====================================== |
| | | |
| | | Authors: |
| | | ------- |
| | | |
| | | Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com |
| New file |
| | |
| | | Copyright-Only Dedication (based on United States law) |
| | | or Public Domain Certification |
| | | |
| | | The person or persons who have associated work with this document (the |
| | | "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of |
| | | his knowledge, the work of authorship identified is in the public domain of the |
| | | country from which the work is published, or (b) hereby dedicates whatever |
| | | copyright the dedicators holds in the work of authorship identified below (the |
| | | "Work") to the public domain. A certifier, moreover, dedicates any copyright |
| | | interest he may have in the associated work, and for these purposes, is |
| | | described as a "dedicator" below. |
| | | |
| | | A certifier has taken reasonable steps to verify the copyright status of this |
| | | work. Certifier recognizes that his good faith efforts may not shield him from |
| | | liability if in fact the work certified is not in the public domain. |
| | | |
| | | Dedicator makes this dedication for the benefit of the public at large and to |
| | | the detriment of the Dedicator's heirs and successors. Dedicator intends this |
| | | dedication to be an overt act of relinquishment in perpetuity of all present |
| | | and future rights under copyright law, whether vested or contingent, in the |
| | | Work. Dedicator understands that such relinquishment of all rights includes |
| | | the relinquishment of all rights to enforce (by lawsuit or otherwise) those |
| | | copyrights in the Work. |
| | | |
| | | Dedicator recognizes that, once placed in the public domain, the Work may be |
| | | freely reproduced, distributed, transmitted, used, modified, built upon, or |
| | | otherwise exploited by anyone for any purpose, commercial or non-commercial, |
| | | and in any way, including by methods that have not yet been invented or |
| | | conceived. |
| New file |
| | |
| | | /* |
| | | cdecoder.c - c source to a base64 decoding algorithm implementation |
| | | |
| | | This is part of the libb64 project, and has been placed in the public domain. |
| | | For details, see http://sourceforge.net/projects/libb64 |
| | | */ |
| | | |
| | | #include "cdecode.h" |
| | | #include <stdint.h> |
| | | |
| | | 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; |
| | | return decoding[(int)value_in]; |
| | | } |
| | | |
| | | void base64_init_decodestate(base64_decodestate* state_in){ |
| | | state_in->step = step_a; |
| | | state_in->plainchar = 0; |
| | | } |
| | | |
| | | static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in){ |
| | | const int8_t* codechar = code_in; |
| | | int8_t* plainchar = plaintext_out; |
| | | int8_t fragment; |
| | | |
| | | *plainchar = state_in->plainchar; |
| | | |
| | | switch (state_in->step){ |
| | | while (1){ |
| | | case step_a: |
| | | do { |
| | | if (codechar == code_in+length_in){ |
| | | state_in->step = step_a; |
| | | state_in->plainchar = *plainchar; |
| | | return plainchar - plaintext_out; |
| | | } |
| | | fragment = (int8_t)base64_decode_value_signed(*codechar++); |
| | | } while (fragment < 0); |
| | | *plainchar = (fragment & 0x03f) << 2; |
| | | case step_b: |
| | | do { |
| | | if (codechar == code_in+length_in){ |
| | | state_in->step = step_b; |
| | | state_in->plainchar = *plainchar; |
| | | return plainchar - plaintext_out; |
| | | } |
| | | fragment = (int8_t)base64_decode_value_signed(*codechar++); |
| | | } while (fragment < 0); |
| | | *plainchar++ |= (fragment & 0x030) >> 4; |
| | | *plainchar = (fragment & 0x00f) << 4; |
| | | case step_c: |
| | | do { |
| | | if (codechar == code_in+length_in){ |
| | | state_in->step = step_c; |
| | | state_in->plainchar = *plainchar; |
| | | return plainchar - plaintext_out; |
| | | } |
| | | fragment = (int8_t)base64_decode_value_signed(*codechar++); |
| | | } while (fragment < 0); |
| | | *plainchar++ |= (fragment & 0x03c) >> 2; |
| | | *plainchar = (fragment & 0x003) << 6; |
| | | case step_d: |
| | | do { |
| | | if (codechar == code_in+length_in){ |
| | | state_in->step = step_d; |
| | | state_in->plainchar = *plainchar; |
| | | return plainchar - plaintext_out; |
| | | } |
| | | fragment = (int8_t)base64_decode_value_signed(*codechar++); |
| | | } while (fragment < 0); |
| | | *plainchar++ |= (fragment & 0x03f); |
| | | } |
| | | } |
| | | /* control should not reach here */ |
| | | return plainchar - plaintext_out; |
| | | } |
| | | |
| | | static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){ |
| | | base64_decodestate _state; |
| | | base64_init_decodestate(&_state); |
| | | int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state); |
| | | if(len > 0) plaintext_out[len] = 0; |
| | | return len; |
| | | } |
| | | |
| | | int base64_decode_value(char value_in){ |
| | | return base64_decode_value_signed(*((int8_t *) &value_in)); |
| | | } |
| | | |
| | | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){ |
| | | return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); |
| | | } |
| | | |
| | | int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){ |
| | | return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out); |
| | | } |
| New file |
| | |
| | | /* |
| | | cdecode.h - c header for a base64 decoding algorithm |
| | | |
| | | This is part of the libb64 project, and has been placed in the public domain. |
| | | For details, see http://sourceforge.net/projects/libb64 |
| | | */ |
| | | |
| | | #ifndef BASE64_CDECODE_H |
| | | #define BASE64_CDECODE_H |
| | | |
| | | #define base64_decode_expected_len(n) ((n * 3) / 4) |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | typedef enum { |
| | | step_a, step_b, step_c, step_d |
| | | } base64_decodestep; |
| | | |
| | | typedef struct { |
| | | base64_decodestep step; |
| | | char plainchar; |
| | | } base64_decodestate; |
| | | |
| | | void base64_init_decodestate(base64_decodestate* state_in); |
| | | |
| | | int base64_decode_value(char value_in); |
| | | |
| | | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); |
| | | |
| | | int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out); |
| | | |
| | | #ifdef __cplusplus |
| | | } // extern "C" |
| | | #endif |
| | | |
| | | #endif /* BASE64_CDECODE_H */ |
| New file |
| | |
| | | /* |
| | | cencoder.c - c source to a base64 encoding algorithm implementation |
| | | |
| | | This is part of the libb64 project, and has been placed in the public domain. |
| | | For details, see http://sourceforge.net/projects/libb64 |
| | | */ |
| | | |
| | | #include "cencode.h" |
| | | |
| | | void base64_init_encodestate(base64_encodestate* state_in) |
| | | { |
| | | state_in->step = step_A; |
| | | state_in->result = 0; |
| | | } |
| | | |
| | | char base64_encode_value(char value_in) |
| | | { |
| | | static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| | | if (value_in > 63) { |
| | | return '='; |
| | | } |
| | | return encoding[(int)value_in]; |
| | | } |
| | | |
| | | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) |
| | | { |
| | | const char* plainchar = plaintext_in; |
| | | const char* const plaintextend = plaintext_in + length_in; |
| | | char* codechar = code_out; |
| | | char result; |
| | | char fragment; |
| | | |
| | | result = state_in->result; |
| | | |
| | | switch (state_in->step) { |
| | | while (1) { |
| | | case step_A: |
| | | if (plainchar == plaintextend) { |
| | | state_in->result = result; |
| | | state_in->step = step_A; |
| | | return codechar - code_out; |
| | | } |
| | | fragment = *plainchar++; |
| | | result = (fragment & 0x0fc) >> 2; |
| | | *codechar++ = base64_encode_value(result); |
| | | result = (fragment & 0x003) << 4; |
| | | case step_B: |
| | | if (plainchar == plaintextend) { |
| | | state_in->result = result; |
| | | state_in->step = step_B; |
| | | return codechar - code_out; |
| | | } |
| | | fragment = *plainchar++; |
| | | result |= (fragment & 0x0f0) >> 4; |
| | | *codechar++ = base64_encode_value(result); |
| | | result = (fragment & 0x00f) << 2; |
| | | case step_C: |
| | | if (plainchar == plaintextend) { |
| | | state_in->result = result; |
| | | state_in->step = step_C; |
| | | return codechar - code_out; |
| | | } |
| | | fragment = *plainchar++; |
| | | result |= (fragment & 0x0c0) >> 6; |
| | | *codechar++ = base64_encode_value(result); |
| | | result = (fragment & 0x03f) >> 0; |
| | | *codechar++ = base64_encode_value(result); |
| | | } |
| | | } |
| | | /* control should not reach here */ |
| | | return codechar - code_out; |
| | | } |
| | | |
| | | int base64_encode_blockend(char* code_out, base64_encodestate* state_in) |
| | | { |
| | | char* codechar = code_out; |
| | | |
| | | switch (state_in->step) { |
| | | case step_B: |
| | | *codechar++ = base64_encode_value(state_in->result); |
| | | *codechar++ = '='; |
| | | *codechar++ = '='; |
| | | break; |
| | | case step_C: |
| | | *codechar++ = base64_encode_value(state_in->result); |
| | | *codechar++ = '='; |
| | | break; |
| | | case step_A: |
| | | break; |
| | | } |
| | | *codechar = 0x00; |
| | | |
| | | return codechar - code_out; |
| | | } |
| | | |
| | | int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) |
| | | { |
| | | base64_encodestate _state; |
| | | base64_init_encodestate(&_state); |
| | | int len = base64_encode_block(plaintext_in, length_in, code_out, &_state); |
| | | return len + base64_encode_blockend((code_out + len), &_state); |
| | | } |
| New file |
| | |
| | | /* |
| | | cencode.h - c header for a base64 encoding algorithm |
| | | |
| | | This is part of the libb64 project, and has been placed in the public domain. |
| | | For details, see http://sourceforge.net/projects/libb64 |
| | | */ |
| | | |
| | | #ifndef BASE64_CENCODE_H |
| | | #define BASE64_CENCODE_H |
| | | |
| | | #define base64_encode_expected_len(n) ((((4 * n) / 3) + 3) & ~3) |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | typedef enum { |
| | | step_A, step_B, step_C |
| | | } base64_encodestep; |
| | | |
| | | typedef struct { |
| | | base64_encodestep step; |
| | | char result; |
| | | int stepcount; |
| | | } base64_encodestate; |
| | | |
| | | void base64_init_encodestate(base64_encodestate* state_in); |
| | | |
| | | char base64_encode_value(char value_in); |
| | | |
| | | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); |
| | | |
| | | int base64_encode_blockend(char* code_out, base64_encodestate* state_in); |
| | | |
| | | int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out); |
| | | |
| | | #ifdef __cplusplus |
| | | } // extern "C" |
| | | #endif |
| | | |
| | | #endif /* BASE64_CENCODE_H */ |
| New file |
| | |
| | | #include "freertos/FreeRTOS.h" |
| | | #include "freertos/task.h" |
| | | #include "esp_task_wdt.h" |
| | | #include "Arduino.h" |
| | | |
| | | TaskHandle_t loopTaskHandle = NULL; |
| | | |
| | | #if CONFIG_AUTOSTART_ARDUINO |
| | | |
| | | bool loopTaskWDTEnabled; |
| | | |
| | | void loopTask(void *pvParameters) |
| | | { |
| | | setup(); |
| | | for(;;) { |
| | | if(loopTaskWDTEnabled){ |
| | | esp_task_wdt_reset(); |
| | | } |
| | | loop(); |
| | | } |
| | | } |
| | | |
| | | extern "C" void app_main() |
| | | { |
| | | loopTaskWDTEnabled = false; |
| | | initArduino(); |
| | | xTaskCreateUniversal(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE); |
| | | } |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | Copyright (c) 2015 Hristo Gochkov. All rights reserved. |
| | | This file is part of the RaspberryPi core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | #ifndef PGMSPACE_INCLUDE |
| | | #define PGMSPACE_INCLUDE |
| | | |
| | | typedef void prog_void; |
| | | typedef char prog_char; |
| | | typedef unsigned char prog_uchar; |
| | | typedef char prog_int8_t; |
| | | typedef unsigned char prog_uint8_t; |
| | | typedef short prog_int16_t; |
| | | typedef unsigned short prog_uint16_t; |
| | | typedef long prog_int32_t; |
| | | typedef unsigned long prog_uint32_t; |
| | | |
| | | #define PROGMEM |
| | | #define PGM_P const char * |
| | | #define PGM_VOID_P const void * |
| | | #define FPSTR(p) ((const char *)(p)) |
| | | #define PSTR(s) (s) |
| | | #define _SFR_BYTE(n) (n) |
| | | |
| | | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) |
| | | #define pgm_read_word(addr) ({ \ |
| | | typeof(addr) _addr = (addr); \ |
| | | *(const unsigned short *)(_addr); \ |
| | | }) |
| | | #define pgm_read_dword(addr) ({ \ |
| | | typeof(addr) _addr = (addr); \ |
| | | *(const unsigned long *)(_addr); \ |
| | | }) |
| | | #define pgm_read_float(addr) ({ \ |
| | | typeof(addr) _addr = (addr); \ |
| | | *(const float *)(_addr); \ |
| | | }) |
| | | #define pgm_read_ptr(addr) ({ \ |
| | | typeof(addr) _addr = (addr); \ |
| | | *(void * const *)(_addr); \ |
| | | }) |
| | | |
| | | #define pgm_read_byte_near(addr) pgm_read_byte(addr) |
| | | #define pgm_read_word_near(addr) pgm_read_word(addr) |
| | | #define pgm_read_dword_near(addr) pgm_read_dword(addr) |
| | | #define pgm_read_float_near(addr) pgm_read_float(addr) |
| | | #define pgm_read_ptr_near(addr) pgm_read_ptr(addr) |
| | | #define pgm_read_byte_far(addr) pgm_read_byte(addr) |
| | | #define pgm_read_word_far(addr) pgm_read_word(addr) |
| | | #define pgm_read_dword_far(addr) pgm_read_dword(addr) |
| | | #define pgm_read_float_far(addr) pgm_read_float(addr) |
| | | #define pgm_read_ptr_far(addr) pgm_read_ptr(addr) |
| | | |
| | | #define memcmp_P memcmp |
| | | #define memccpy_P memccpy |
| | | #define memmem_P memmem |
| | | #define memcpy_P memcpy |
| | | #define strcpy_P strcpy |
| | | #define strncpy_P strncpy |
| | | #define strcat_P strcat |
| | | #define strncat_P strncat |
| | | #define strcmp_P strcmp |
| | | #define strncmp_P strncmp |
| | | #define strcasecmp_P strcasecmp |
| | | #define strncasecmp_P strncasecmp |
| | | #define strlen_P strlen |
| | | #define strnlen_P strnlen |
| | | #define strstr_P strstr |
| | | #define printf_P printf |
| | | #define sprintf_P sprintf |
| | | #define snprintf_P snprintf |
| | | #define vsnprintf_P vsnprintf |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | core_esp8266_noniso.c - nonstandard (but usefull) conversion functions |
| | | |
| | | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | |
| | | Modified 03 April 2015 by Markus Sattler |
| | | |
| | | */ |
| | | |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <math.h> |
| | | #include "stdlib_noniso.h" |
| | | |
| | | void reverse(char* begin, char* end) { |
| | | char *is = begin; |
| | | char *ie = end - 1; |
| | | while(is < ie) { |
| | | char tmp = *ie; |
| | | *ie = *is; |
| | | *is = tmp; |
| | | ++is; |
| | | --ie; |
| | | } |
| | | } |
| | | |
| | | char* ltoa(long value, char* result, int base) { |
| | | if(base < 2 || base > 16) { |
| | | *result = 0; |
| | | return result; |
| | | } |
| | | |
| | | char* out = result; |
| | | long quotient = abs(value); |
| | | |
| | | do { |
| | | const long tmp = quotient / base; |
| | | *out = "0123456789abcdef"[quotient - (tmp * base)]; |
| | | ++out; |
| | | quotient = tmp; |
| | | } while(quotient); |
| | | |
| | | // Apply negative sign |
| | | if(value < 0) |
| | | *out++ = '-'; |
| | | |
| | | reverse(result, out); |
| | | *out = 0; |
| | | return result; |
| | | } |
| | | |
| | | char* ultoa(unsigned long value, char* result, int base) { |
| | | if(base < 2 || base > 16) { |
| | | *result = 0; |
| | | return result; |
| | | } |
| | | |
| | | char* out = result; |
| | | unsigned long quotient = value; |
| | | |
| | | do { |
| | | const unsigned long tmp = quotient / base; |
| | | *out = "0123456789abcdef"[quotient - (tmp * base)]; |
| | | ++out; |
| | | quotient = tmp; |
| | | } while(quotient); |
| | | |
| | | reverse(result, out); |
| | | *out = 0; |
| | | return result; |
| | | } |
| | | |
| | | char * dtostrf(double number, signed char width, unsigned char prec, char *s) { |
| | | bool negative = false; |
| | | |
| | | if (isnan(number)) { |
| | | strcpy(s, "nan"); |
| | | return s; |
| | | } |
| | | if (isinf(number)) { |
| | | strcpy(s, "inf"); |
| | | return s; |
| | | } |
| | | |
| | | char* out = s; |
| | | |
| | | int fillme = width; // how many cells to fill for the integer part |
| | | if (prec > 0) { |
| | | fillme -= (prec+1); |
| | | } |
| | | |
| | | // Handle negative numbers |
| | | if (number < 0.0) { |
| | | negative = true; |
| | | fillme--; |
| | | number = -number; |
| | | } |
| | | |
| | | // Round correctly so that print(1.999, 2) prints as "2.00" |
| | | // I optimized out most of the divisions |
| | | double rounding = 2.0; |
| | | for (uint8_t i = 0; i < prec; ++i) |
| | | rounding *= 10.0; |
| | | rounding = 1.0 / rounding; |
| | | |
| | | number += rounding; |
| | | |
| | | // Figure out how big our number really is |
| | | double tenpow = 1.0; |
| | | int digitcount = 1; |
| | | while (number >= 10.0 * tenpow) { |
| | | tenpow *= 10.0; |
| | | digitcount++; |
| | | } |
| | | |
| | | number /= tenpow; |
| | | fillme -= digitcount; |
| | | |
| | | // Pad unused cells with spaces |
| | | while (fillme-- > 0) { |
| | | *out++ = ' '; |
| | | } |
| | | |
| | | // Handle negative sign |
| | | if (negative) *out++ = '-'; |
| | | |
| | | // Print the digits, and if necessary, the decimal point |
| | | digitcount += prec; |
| | | int8_t digit = 0; |
| | | while (digitcount-- > 0) { |
| | | digit = (int8_t)number; |
| | | if (digit > 9) digit = 9; // insurance |
| | | *out++ = (char)('0' | digit); |
| | | if ((digitcount == prec) && (prec > 0)) { |
| | | *out++ = '.'; |
| | | } |
| | | number -= digit; |
| | | number *= 10.0; |
| | | } |
| | | |
| | | // make sure the string is terminated |
| | | *out = 0; |
| | | return s; |
| | | } |
| New file |
| | |
| | | /* |
| | | stdlib_noniso.h - nonstandard (but usefull) conversion functions |
| | | |
| | | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | |
| | | #ifndef STDLIB_NONISO_H |
| | | #define STDLIB_NONISO_H |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | int atoi(const char *s); |
| | | |
| | | long atol(const char* s); |
| | | |
| | | double atof(const char* s); |
| | | |
| | | char* itoa (int val, char *s, int radix); |
| | | |
| | | char* ltoa (long val, char *s, int radix); |
| | | |
| | | char* utoa (unsigned int val, char *s, int radix); |
| | | |
| | | char* ultoa (unsigned long val, char *s, int radix); |
| | | |
| | | char* dtostrf (double val, signed char width, unsigned char prec, char *s); |
| | | |
| | | #ifdef __cplusplus |
| | | } // extern "C" |
| | | #endif |
| | | |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | wiring_private.h - Internal header file. |
| | | Part of Arduino - http://www.arduino.cc/ |
| | | |
| | | Copyright (c) 2005-2006 David A. Mellis |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General |
| | | Public License along with this library; if not, write to the |
| | | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
| | | Boston, MA 02111-1307 USA |
| | | |
| | | $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ |
| | | */ |
| | | |
| | | #ifndef WiringPrivate_h |
| | | #define WiringPrivate_h |
| | | |
| | | #include <stdio.h> |
| | | #include <stdarg.h> |
| | | |
| | | #include "Arduino.h" |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | typedef void (*voidFuncPtr)(void); |
| | | |
| | | void initPins(); |
| | | |
| | | #ifdef __cplusplus |
| | | } // extern "C" |
| | | #endif |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | pulse.c - wiring pulseIn implementation for esp8266 |
| | | Copyright (c) 2015 Hristo Gochkov. All rights reserved. |
| | | This file is part of the esp8266 core for Arduino environment. |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| | | */ |
| | | //#include <limits.h> |
| | | #include "wiring_private.h" |
| | | #include "pins_arduino.h" |
| | | |
| | | |
| | | extern uint32_t xthal_get_ccount(); |
| | | |
| | | #define WAIT_FOR_PIN_STATE(state) \ |
| | | while (digitalRead(pin) != (state)) { \ |
| | | if (xthal_get_ccount() - start_cycle_count > timeout_cycles) { \ |
| | | return 0; \ |
| | | } \ |
| | | } |
| | | |
| | | // max timeout is 27 seconds at 160MHz clock and 54 seconds at 80MHz clock |
| | | unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) |
| | | { |
| | | const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX); |
| | | if (timeout > max_timeout_us) { |
| | | timeout = max_timeout_us; |
| | | } |
| | | const uint32_t timeout_cycles = microsecondsToClockCycles(timeout); |
| | | const uint32_t start_cycle_count = xthal_get_ccount(); |
| | | WAIT_FOR_PIN_STATE(!state); |
| | | WAIT_FOR_PIN_STATE(state); |
| | | const uint32_t pulse_start_cycle_count = xthal_get_ccount(); |
| | | WAIT_FOR_PIN_STATE(!state); |
| | | return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count); |
| | | } |
| | | |
| | | unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) |
| | | { |
| | | return pulseIn(pin, state, timeout); |
| | | } |
| New file |
| | |
| | | /* |
| | | wiring_shift.c - shiftOut() function |
| | | Part of Arduino - http://www.arduino.cc/ |
| | | Copyright (c) 2005-2006 David A. Mellis |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | This library is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | | Lesser General Public License for more details. |
| | | You should have received a copy of the GNU Lesser General |
| | | Public License along with this library; if not, write to the |
| | | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
| | | Boston, MA 02111-1307 USA |
| | | $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ |
| | | */ |
| | | |
| | | #include "esp32-hal.h" |
| | | #include "wiring_private.h" |
| | | |
| | | uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { |
| | | uint8_t value = 0; |
| | | uint8_t i; |
| | | |
| | | for(i = 0; i < 8; ++i) { |
| | | //digitalWrite(clockPin, HIGH); |
| | | if(bitOrder == LSBFIRST) |
| | | value |= digitalRead(dataPin) << i; |
| | | else |
| | | value |= digitalRead(dataPin) << (7 - i); |
| | | digitalWrite(clockPin, HIGH); |
| | | digitalWrite(clockPin, LOW); |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) { |
| | | uint8_t i; |
| | | |
| | | for(i = 0; i < 8; i++) { |
| | | if(bitOrder == LSBFIRST) |
| | | digitalWrite(dataPin, !!(val & (1 << i))); |
| | | else |
| | | digitalWrite(dataPin, !!(val & (1 << (7 - i)))); |
| | | |
| | | digitalWrite(clockPin, HIGH); |
| | | digitalWrite(clockPin, LOW); |
| | | } |
| | | } |
| New file |
| | |
| | | Make your question, not a Statement, inclusive. Include all pertinent information: |
| | | |
| | | What you are trying to do. |
| | | Describe your system( Hardware, computer, O/S, core version, environment) |
| | | Describe what is failing |
| | | Show the shortest possible code that will duplicate the error |
| | | Show the EXACT error message(it doesn't work is not enough) |
| | | Then if someone is interested and knowledgeable you might get a answer. All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you. |
| | | |
| | | If you have a Guru Meditation Error or Backtrace, ***please decode it***: |
| | | https://github.com/me-no-dev/EspExceptionDecoder |
| | | |
| | | ----------------------------- Remove above ----------------------------- |
| | | |
| | | |
| | | ### Hardware: |
| | | Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora? |
| | | Core Installation/update date: ?11/jul/2017? |
| | | IDE name: ?Arduino IDE? ?Platform.io? ?IDF component? |
| | | Flash Frequency: ?40Mhz? |
| | | PSRAM enabled: ?no? |
| | | Upload Speed: ?115200? |
| | | Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu? |
| | | |
| | | ### Description: |
| | | Describe your problem here |
| | | |
| | | |
| | | ### Sketch: (leave the backquotes for [code formatting](https://help.github.com/articles/creating-and-highlighting-code-blocks/)) |
| | | ```cpp |
| | | |
| | | //Change the code below by your sketch |
| | | #include <Arduino.h> |
| | | |
| | | void setup() { |
| | | } |
| | | |
| | | void loop() { |
| | | } |
| | | ``` |
| | | |
| | | ### Debug Messages: |
| | | ``` |
| | | Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here |
| | | ``` |
| New file |
| | |
| | | # Over the Air through Web browser |
| | | OTAWebUpdate is done with a web browser that can be useful in the following typical scenarios: |
| | | - Once the application developed and loading directly from Arduino IDE is inconvenient or not possible |
| | | - after deployment if user is unable to expose Firmware for OTA from external update server |
| | | - provide updates after deployment to small quantity of modules when setting an update server is not practicable |
| | | |
| | | ## Requirements |
| | | - The ESP and the computer must be connected to the same network |
| | | |
| | | ## Implementation |
| | | The sample implementation has been done using: |
| | | - example sketch OTAWebUpdater.ino |
| | | - ESP32 (Dev Module) |
| | | |
| | | You can use another module also if it meets Flash chip size of the sketch |
| | | |
| | | 1-Before you begin, please make sure that you have the following software installed: |
| | | - Arduino IDE |
| | | - Host software depending on O/S you use: |
| | | - Avahi http://avahi.org/ for Linux |
| | | - Bonjour http://www.apple.com/support/bonjour/ for Windows |
| | | - Mac OSX and iOS - support is already built in / no any extra s/w is required |
| | | |
| | | Prepare the sketch and configuration for initial upload with a serial port |
| | | - Start Arduino IDE and load sketch OTAWebUpdater.ino available under File > Examples > OTAWebUpdater.ino |
| | | - Update ssid and pass in the sketch so the module can join your Wi-Fi network |
| | | - Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option |
| | | |
| | |  |
| | | |
| | | - Upload sketch (Ctrl+U) |
| | | - Now open web browser and enter the url, i.e. http://esp32.local. Once entered, browser should display a form |
| | | |
| | |  |
| | | |
| | | > username= admin |
| | | |
| | | > password= admin |
| | | |
| | | **Note**-*If entering “http://ESP32.local” does not work, try replacing “ESP32” with module’s IP address.This workaround is useful in case the host software installed does not work*. |
| | | |
| | | Now click on Login button and browser will display a upload form |
| | | |
| | |  |
| | | |
| | | For Uploading the New Firmware you need to provide the Binary File of your Code. |
| | | |
| | | Exporting Binary file of the Firmware (Code) |
| | | - Open up the Arduino IDE |
| | | - Open up the Code, for Exporting up Binary file |
| | | - Now go to Sketch > export compiled Binary |
| | |  |
| | | |
| | | - Binary file is exported to the same Directory where your code is present |
| | | |
| | | Once you are comfortable with this procedure go ahead and modify OTAWebUpdater.ino sketch to print some additional messages, compile it, Export new binary file and upload it using web browser to see entered changes on a Serial Monitor |
| | | |
| | | |
| | | |
| New file |
| | |
| | | Installation instructions using Arduino IDE Boards Manager |
| | | ========================================================== |
| | | |
| | | Starting with 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, Mac OS, and Linux (32 and 64 bit). |
| | | |
| | | - Install the current upstream Arduino IDE at the 1.8 level or later. The current version is at the [Arduino website](http://www.arduino.cc/en/main/software). |
| | | - Start Arduino and open Preferences window. |
| | | - Enter ```https://dl.espressif.com/dl/package_esp32_index.json``` into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas. |
| | | - Open Boards Manager from Tools > Board menu and install *esp32* platform (and don't forget to select your ESP32 board from Tools > Board menu after installation). |
| | | |
| | | Stable release link: `https://dl.espressif.com/dl/package_esp32_index.json` |
| | | |
| | | Development release link: `https://dl.espressif.com/dl/package_esp32_dev_index.json` |
| New file |
| | |
| | | Installation instructions for Debian / Ubuntu OS |
| | | ================================================= |
| | | |
| | | - Install latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software) |
| | | - Open Terminal and execute the following command (copy->paste and hit enter): |
| | | |
| | | ```bash |
| | | sudo usermod -a -G dialout $USER && \ |
| | | sudo apt-get install git && \ |
| | | wget https://bootstrap.pypa.io/get-pip.py && \ |
| | | sudo python get-pip.py && \ |
| | | sudo pip install pyserial && \ |
| | | 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 && \ |
| | | python3 get.py |
| | | ``` |
| | | - Restart Arduino IDE |
| | | |
| | | |
| | | |
| | | - If you have Arduino installed to ~/, modify the installation as follows, beginning at `mkdir -p ~/Arduino/hardware`: |
| | | |
| | | ```bash |
| | | cd ~/Arduino/hardware |
| | | mkdir -p espressif && \ |
| | | cd espressif && \ |
| | | git clone https://github.com/espressif/arduino-esp32.git esp32 && \ |
| | | cd esp32 && \ |
| | | git submodule update --init --recursive && \ |
| | | cd tools && \ |
| | | python3 get.py |
| | | ``` |
| New file |
| | |
| | | Installation instructions for Fedora |
| | | ===================================== |
| | | |
| | | - Install the latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software). `$ sudo dnf -y install arduino` will most likely install an older release. |
| | | - Open Terminal and execute the following command (copy->paste and hit enter): |
| | | |
| | | ```bash |
| | | sudo usermod -a -G dialout $USER && \ |
| | | sudo dnf install git python3-pip python3-pyserial && \ |
| | | 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 && \ |
| | | python get.py |
| | | ``` |
| | | - Restart Arduino IDE |
| New file |
| | |
| | | Installation instructions for Mac OS |
| | | ===================================== |
| | | |
| | | - Install latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software) |
| | | - Open Terminal and execute the following command (copy->paste and hit enter): |
| | | |
| | | ```bash |
| | | mkdir -p ~/Documents/Arduino/hardware/espressif && \ |
| | | cd ~/Documents/Arduino/hardware/espressif && \ |
| | | git clone https://github.com/espressif/arduino-esp32.git esp32 && \ |
| | | cd esp32 && \ |
| | | git submodule update --init --recursive && \ |
| | | cd 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 if necessary! |
| | | |
| | | - If you get the error below. Install the command line dev tools with xcode-select --install and try the command above again: |
| | | |
| | | ```xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun``` |
| | | |
| | | ```xcode-select --install``` |
| | | |
| | | - Try `python3` instead of `python` if you get the error: `IOError: [Errno socket error] [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590)` when running `python get.py` |
| | | |
| | | - If you get the following error when running `python get.py` urllib.error.URLError: <urlopen error SSL: CERTIFICATE_VERIFY_FAILED, go to Macintosh HD > Applications > Python3.6 folder (or any other python version), and run the following scripts: Install Certificates.command and Update Shell Profile.command |
| | | |
| | | - Restart Arduino IDE |
| | | |
| New file |
| | |
| | | Installation instructions for openSUSE |
| | | ====================================== |
| | | |
| | | - Install the latest Arduino IDE from [arduino.cc](https://www.arduino.cc/en/Main/Software). |
| | | - Open Terminal and execute the following command (copy->paste and hit enter): |
| | | |
| | | ```bash |
| | | sudo usermod -a -G dialout $USER && \ |
| | | if [ `python --version 2>&1 | grep '2.7' | wc -l` = "1" ]; then \ |
| | | sudo zypper install git python-pip python-pyserial; \ |
| | | else \ |
| | | sudo zypper install git python3-pip python3-pyserial; \ |
| | | fi && \ |
| | | 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 && \ |
| | | python get.py |
| | | ``` |
| | | - Restart Arduino IDE |
| New file |
| | |
| | | ## Steps to install Arduino ESP32 support on Windows |
| | | ### Tested on 32 and 64 bit Windows 10 machines |
| | | |
| | | 1. Download and install the latest Arduino IDE ```Windows Installer``` from [arduino.cc](https://www.arduino.cc/en/Main/Software) |
| | | 2. Download and install Git from [git-scm.com](https://git-scm.com/download/win) |
| | | 3. Start ```Git GUI``` and run through the following steps: |
| | | - Select ```Clone Existing Repository``` |
| | | |
| | |  |
| | | |
| | | - Select source and destination |
| | | - Sketchbook Directory: Usually ```C:/Users/[YOUR_USER_NAME]/Documents/Arduino``` and is listed underneath the "Sketchbook location" in Arduino preferences. |
| | | - Source Location: ```https://github.com/espressif/arduino-esp32.git``` |
| | | - Target Directory: ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32``` |
| | | - Click ```Clone``` to start cloning the repository |
| | | |
| | |  |
| | |  |
| | | - open a `Git Bash` session pointing to ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32``` and execute ```git submodule update --init --recursive``` |
| | | - Open ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32/tools``` and double-click ```get.exe``` |
| | | |
| | |  |
| | | |
| | | - When ```get.exe``` finishes, you should see the following files in the directory |
| | | |
| | |  |
| | | |
| | | 4. Plug your ESP32 board and wait for the drivers to install (or install manually any that might be required) |
| | | 5. Start Arduino IDE |
| | | 6. Select your board in ```Tools > Board``` menu |
| | | 7. Select the COM port that the board is attached to |
| | | 8. Compile and upload (You might need to hold the boot button while uploading) |
| | | |
| | |  |
| | | |
| | | ### How to update to the latest code |
| | | |
| | | 1. Start ```Git GUI``` and you should see the repository under ```Open Recent Repository```. Click on it! |
| | | |
| | |  |
| | | |
| | | 2. From menu ```Remote``` select ```Fetch from``` > ```origin``` |
| | | |
| | |  |
| | | |
| | | 3. Wait for git to pull any changes and close ```Git GUI``` |
| | | 4. Open ```[ARDUINO_SKETCHBOOK_DIR]/hardware/espressif/esp32/tools``` and double-click ```get.exe``` |
| | | |
| | |  |
| New file |
| | |
| | | To use as a component of ESP-IDF |
| | | ================================================= |
| | | |
| | | ## Installation |
| | | |
| | | - Download and install [esp-idf](https://github.com/espressif/esp-idf) |
| | | - Create blank idf project (from one of the examples) |
| | | - in the project folder, create a folder called components and clone this repository inside |
| | | |
| | | ```bash |
| | | mkdir -p components && \ |
| | | cd components && \ |
| | | git clone https://github.com/espressif/arduino-esp32.git arduino && \ |
| | | cd arduino && \ |
| | | git submodule update --init --recursive && \ |
| | | cd ../.. && \ |
| | | make menuconfig |
| | | ``` |
| | | - ```make menuconfig``` has some Arduino options |
| | | - "Autostart Arduino setup and loop on boot" |
| | | - If you enable this options, your main.cpp should be formated like any other sketch |
| | | |
| | | ```arduino |
| | | //file: main.cpp |
| | | #include "Arduino.h" |
| | | |
| | | void setup(){ |
| | | Serial.begin(115200); |
| | | } |
| | | |
| | | void loop(){ |
| | | Serial.println("loop"); |
| | | delay(1000); |
| | | } |
| | | ``` |
| | | |
| | | - Else you need to implement ```app_main()``` and call ```initArduino();``` in it. |
| | | |
| | | Keep in mind that setup() and loop() will not be called in this case. |
| | | If you plan to base your code on examples provided in [esp-idf](https://github.com/espressif/esp-idf/tree/master/examples), please make sure move the app_main() function in main.cpp from the files in the example. |
| | | |
| | | ```arduino |
| | | //file: main.cpp |
| | | #include "Arduino.h" |
| | | |
| | | extern "C" void app_main() |
| | | { |
| | | initArduino(); |
| | | pinMode(4, OUTPUT); |
| | | digitalWrite(4, HIGH); |
| | | //do your own thing |
| | | } |
| | | ``` |
| | | - "Disable mutex locks for HAL" |
| | | - If enabled, there will be no protection on the drivers from concurently accessing them from another thread/interrupt/core |
| | | - "Autoconnect WiFi on boot" |
| | | - If enabled, WiFi will start with the last known configuration |
| | | - Else it will wait for WiFi.begin |
| | | - ```make flash monitor``` will build, upload and open serial monitor to your board |
| | | |
| | | ## Logging To Serial |
| | | |
| | | If you are writing code that does not require Arduino to compile and you want your `ESP_LOGx` macros to work in Arduino IDE, you can enable the compatibility by adding the following lines after your includes: |
| | | |
| | | ```cpp |
| | | #ifdef ARDUINO_ARCH_ESP32 |
| | | #include "esp32-hal-log.h" |
| | | #endif |
| | | ``` |
| | | |
| | | ## Compilation Errors |
| | | |
| | | As commits are made to esp-idf and submodules, the codebases can develop incompatibilities which cause compilation errors. If you have problems compiling, follow the instructions in [Issue #1142](https://github.com/espressif/arduino-esp32/issues/1142) to roll esp-idf back to a known good version. |
| New file |
| | |
| | | To use make |
| | | ============ |
| | | |
| | | [makeEspArduino](https://github.com/plerup/makeEspArduino) is a generic makefile for any ESP8266/ESP32 Arduino project.Using make instead of the Arduino IDE makes it easier to do automated and production builds. |
| New file |
| | |
| | | Installation instructions for using PlatformIO |
| | | ================================================= |
| | | |
| | | - [What is PlatformIO?](http://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=arduino-esp32) |
| | | - [PlatformIO IDE](http://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp32) |
| | | - [PlatformIO Core](http://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp32) (command line tool) |
| | | - [Advanced usage](http://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32) - |
| | | custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version |
| | | - [Integration with Cloud and Standalone IDEs](http://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=arduino-esp32) - |
| | | Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode |
| | | - [Project Examples](http://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32#examples) |
| New file |
| | |
| | | #include <WiFi.h> |
| | | #include <ESPmDNS.h> |
| | | #include <WiFiUdp.h> |
| | | #include <ArduinoOTA.h> |
| | | |
| | | const char* ssid = ".........."; |
| | | const char* password = ".........."; |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | Serial.println("Booting"); |
| | | WiFi.mode(WIFI_STA); |
| | | WiFi.begin(ssid, password); |
| | | while (WiFi.waitForConnectResult() != WL_CONNECTED) { |
| | | Serial.println("Connection Failed! Rebooting..."); |
| | | delay(5000); |
| | | ESP.restart(); |
| | | } |
| | | |
| | | // Port defaults to 3232 |
| | | // ArduinoOTA.setPort(3232); |
| | | |
| | | // Hostname defaults to esp3232-[MAC] |
| | | // ArduinoOTA.setHostname("myesp32"); |
| | | |
| | | // No authentication by default |
| | | // ArduinoOTA.setPassword("admin"); |
| | | |
| | | // Password can be set with it's md5 value as well |
| | | // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 |
| | | // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); |
| | | |
| | | ArduinoOTA |
| | | .onStart([]() { |
| | | String type; |
| | | if (ArduinoOTA.getCommand() == U_FLASH) |
| | | type = "sketch"; |
| | | else // U_SPIFFS |
| | | type = "filesystem"; |
| | | |
| | | // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() |
| | | Serial.println("Start updating " + type); |
| | | }) |
| | | .onEnd([]() { |
| | | Serial.println("\nEnd"); |
| | | }) |
| | | .onProgress([](unsigned int progress, unsigned int total) { |
| | | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); |
| | | }) |
| | | .onError([](ota_error_t error) { |
| | | Serial.printf("Error[%u]: ", error); |
| | | if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); |
| | | else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); |
| | | else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); |
| | | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); |
| | | else if (error == OTA_END_ERROR) Serial.println("End Failed"); |
| | | }); |
| | | |
| | | ArduinoOTA.begin(); |
| | | |
| | | Serial.println("Ready"); |
| | | Serial.print("IP address: "); |
| | | Serial.println(WiFi.localIP()); |
| | | } |
| | | |
| | | void loop() { |
| | | ArduinoOTA.handle(); |
| | | } |
| New file |
| | |
| | | #include <WiFi.h> |
| | | #include <WiFiClient.h> |
| | | #include <WebServer.h> |
| | | #include <ESPmDNS.h> |
| | | #include <Update.h> |
| | | |
| | | const char* host = "esp32"; |
| | | const char* ssid = "xxx"; |
| | | const char* password = "xxxx"; |
| | | |
| | | WebServer server(80); |
| | | |
| | | /* |
| | | * Login page |
| | | */ |
| | | |
| | | const char* loginIndex = |
| | | "<form name='loginForm'>" |
| | | "<table width='20%' bgcolor='A09F9F' align='center'>" |
| | | "<tr>" |
| | | "<td colspan=2>" |
| | | "<center><font size=4><b>ESP32 Login Page</b></font></center>" |
| | | "<br>" |
| | | "</td>" |
| | | "<br>" |
| | | "<br>" |
| | | "</tr>" |
| | | "<td>Username:</td>" |
| | | "<td><input type='text' size=25 name='userid'><br></td>" |
| | | "</tr>" |
| | | "<br>" |
| | | "<br>" |
| | | "<tr>" |
| | | "<td>Password:</td>" |
| | | "<td><input type='Password' size=25 name='pwd'><br></td>" |
| | | "<br>" |
| | | "<br>" |
| | | "</tr>" |
| | | "<tr>" |
| | | "<td><input type='submit' onclick='check(this.form)' value='Login'></td>" |
| | | "</tr>" |
| | | "</table>" |
| | | "</form>" |
| | | "<script>" |
| | | "function check(form)" |
| | | "{" |
| | | "if(form.userid.value=='admin' && form.pwd.value=='admin')" |
| | | "{" |
| | | "window.open('/serverIndex')" |
| | | "}" |
| | | "else" |
| | | "{" |
| | | " alert('Error Password or Username')/*displays error message*/" |
| | | "}" |
| | | "}" |
| | | "</script>"; |
| | | |
| | | /* |
| | | * Server Index Page |
| | | */ |
| | | |
| | | const char* serverIndex = |
| | | "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>" |
| | | "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>" |
| | | "<input type='file' name='update'>" |
| | | "<input type='submit' value='Update'>" |
| | | "</form>" |
| | | "<div id='prg'>progress: 0%</div>" |
| | | "<script>" |
| | | "$('form').submit(function(e){" |
| | | "e.preventDefault();" |
| | | "var form = $('#upload_form')[0];" |
| | | "var data = new FormData(form);" |
| | | " $.ajax({" |
| | | "url: '/update'," |
| | | "type: 'POST'," |
| | | "data: data," |
| | | "contentType: false," |
| | | "processData:false," |
| | | "xhr: function() {" |
| | | "var xhr = new window.XMLHttpRequest();" |
| | | "xhr.upload.addEventListener('progress', function(evt) {" |
| | | "if (evt.lengthComputable) {" |
| | | "var per = evt.loaded / evt.total;" |
| | | "$('#prg').html('progress: ' + Math.round(per*100) + '%');" |
| | | "}" |
| | | "}, false);" |
| | | "return xhr;" |
| | | "}," |
| | | "success:function(d, s) {" |
| | | "console.log('success!')" |
| | | "}," |
| | | "error: function (a, b, c) {" |
| | | "}" |
| | | "});" |
| | | "});" |
| | | "</script>"; |
| | | |
| | | /* |
| | | * setup function |
| | | */ |
| | | void setup(void) { |
| | | Serial.begin(115200); |
| | | |
| | | // Connect to WiFi network |
| | | WiFi.begin(ssid, password); |
| | | Serial.println(""); |
| | | |
| | | // Wait for connection |
| | | while (WiFi.status() != WL_CONNECTED) { |
| | | delay(500); |
| | | Serial.print("."); |
| | | } |
| | | Serial.println(""); |
| | | Serial.print("Connected to "); |
| | | Serial.println(ssid); |
| | | Serial.print("IP address: "); |
| | | Serial.println(WiFi.localIP()); |
| | | |
| | | /*use mdns for host name resolution*/ |
| | | if (!MDNS.begin(host)) { //http://esp32.local |
| | | Serial.println("Error setting up MDNS responder!"); |
| | | while (1) { |
| | | delay(1000); |
| | | } |
| | | } |
| | | Serial.println("mDNS responder started"); |
| | | /*return index page which is stored in serverIndex */ |
| | | server.on("/", HTTP_GET, []() { |
| | | server.sendHeader("Connection", "close"); |
| | | server.send(200, "text/html", loginIndex); |
| | | }); |
| | | server.on("/serverIndex", HTTP_GET, []() { |
| | | server.sendHeader("Connection", "close"); |
| | | server.send(200, "text/html", serverIndex); |
| | | }); |
| | | /*handling uploading firmware file */ |
| | | server.on("/update", HTTP_POST, []() { |
| | | server.sendHeader("Connection", "close"); |
| | | server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); |
| | | ESP.restart(); |
| | | }, []() { |
| | | HTTPUpload& upload = server.upload(); |
| | | if (upload.status == UPLOAD_FILE_START) { |
| | | Serial.printf("Update: %s\n", upload.filename.c_str()); |
| | | if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size |
| | | Update.printError(Serial); |
| | | } |
| | | } else if (upload.status == UPLOAD_FILE_WRITE) { |
| | | /* flashing firmware to ESP*/ |
| | | if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { |
| | | Update.printError(Serial); |
| | | } |
| | | } else if (upload.status == UPLOAD_FILE_END) { |
| | | if (Update.end(true)) { //true to set the size to the current progress |
| | | Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); |
| | | } else { |
| | | Update.printError(Serial); |
| | | } |
| | | } |
| | | }); |
| | | server.begin(); |
| | | } |
| | | |
| | | void loop(void) { |
| | | server.handleClient(); |
| | | delay(1); |
| | | } |
| New file |
| | |
| | | ####################################### |
| | | # Syntax Coloring Map For Ultrasound |
| | | ####################################### |
| | | |
| | | ####################################### |
| | | # Datatypes (KEYWORD1) |
| | | ####################################### |
| | | |
| | | ArduinoOTA KEYWORD1 |
| | | |
| | | ####################################### |
| | | # Methods and Functions (KEYWORD2) |
| | | ####################################### |
| | | |
| | | begin KEYWORD2 |
| | | setup KEYWORD2 |
| | | handle KEYWORD2 |
| | | onStart KEYWORD2 |
| | | onEnd KEYWORD2 |
| | | onError KEYWORD2 |
| | | onProgress KEYWORD2 |
| | | |
| | | ####################################### |
| | | # Constants (LITERAL1) |
| | | ####################################### |
| | | |
| New file |
| | |
| | | name=ArduinoOTA |
| | | version=1.0 |
| | | author=Ivan Grokhotkov and Hristo Gochkov |
| | | maintainer=Hristo Gochkov <hristo@espressif.com> |
| | | sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. |
| | | paragraph=With this library you can enable your sketch to be upgraded over network. Includes mdns anounces to get discovered by the arduino IDE. |
| | | category=Communication |
| | | url= |
| | | architectures=esp32 |
| New file |
| | |
| | | #ifndef LWIP_OPEN_SRC |
| | | #define LWIP_OPEN_SRC |
| | | #endif |
| | | #include <functional> |
| | | #include <WiFiUdp.h> |
| | | #include "ArduinoOTA.h" |
| | | #include "ESPmDNS.h" |
| | | #include "MD5Builder.h" |
| | | #include "Update.h" |
| | | |
| | | |
| | | // #define OTA_DEBUG Serial |
| | | |
| | | ArduinoOTAClass::ArduinoOTAClass() |
| | | : _port(0) |
| | | , _initialized(false) |
| | | , _rebootOnSuccess(true) |
| | | , _mdnsEnabled(true) |
| | | , _state(OTA_IDLE) |
| | | , _size(0) |
| | | , _cmd(0) |
| | | , _ota_port(0) |
| | | , _ota_timeout(1000) |
| | | , _start_callback(NULL) |
| | | , _end_callback(NULL) |
| | | , _error_callback(NULL) |
| | | , _progress_callback(NULL) |
| | | { |
| | | } |
| | | |
| | | ArduinoOTAClass::~ArduinoOTAClass(){ |
| | | _udp_ota.stop(); |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::onStart(THandlerFunction fn) { |
| | | _start_callback = fn; |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::onEnd(THandlerFunction fn) { |
| | | _end_callback = fn; |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) { |
| | | _progress_callback = fn; |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::onError(THandlerFunction_Error fn) { |
| | | _error_callback = fn; |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setPort(uint16_t port) { |
| | | if (!_initialized && !_port && port) { |
| | | _port = port; |
| | | } |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setHostname(const char * hostname) { |
| | | if (!_initialized && !_hostname.length() && hostname) { |
| | | _hostname = hostname; |
| | | } |
| | | return *this; |
| | | } |
| | | |
| | | String ArduinoOTAClass::getHostname() { |
| | | return _hostname; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setPassword(const char * password) { |
| | | if (!_initialized && !_password.length() && password) { |
| | | MD5Builder passmd5; |
| | | passmd5.begin(); |
| | | passmd5.add(password); |
| | | passmd5.calculate(); |
| | | _password = passmd5.toString(); |
| | | } |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setPasswordHash(const char * password) { |
| | | if (!_initialized && !_password.length() && password) { |
| | | _password = password; |
| | | } |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setRebootOnSuccess(bool reboot){ |
| | | _rebootOnSuccess = reboot; |
| | | return *this; |
| | | } |
| | | |
| | | ArduinoOTAClass& ArduinoOTAClass::setMdnsEnabled(bool enabled){ |
| | | _mdnsEnabled = enabled; |
| | | return *this; |
| | | } |
| | | |
| | | void ArduinoOTAClass::begin() { |
| | | if (_initialized){ |
| | | log_w("already initialized"); |
| | | return; |
| | | } |
| | | |
| | | if (!_port) { |
| | | _port = 3232; |
| | | } |
| | | |
| | | if(!_udp_ota.begin(_port)){ |
| | | log_e("udp bind failed"); |
| | | return; |
| | | } |
| | | |
| | | |
| | | if (!_hostname.length()) { |
| | | char tmp[20]; |
| | | uint8_t mac[6]; |
| | | WiFi.macAddress(mac); |
| | | sprintf(tmp, "esp32-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
| | | _hostname = tmp; |
| | | } |
| | | if(_mdnsEnabled){ |
| | | MDNS.begin(_hostname.c_str()); |
| | | MDNS.enableArduino(_port, (_password.length() > 0)); |
| | | } |
| | | _initialized = true; |
| | | _state = OTA_IDLE; |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port); |
| | | #endif |
| | | } |
| | | |
| | | int ArduinoOTAClass::parseInt(){ |
| | | char data[INT_BUFFER_SIZE]; |
| | | uint8_t index = 0; |
| | | char value; |
| | | while(_udp_ota.peek() == ' ') _udp_ota.read(); |
| | | while(index < INT_BUFFER_SIZE - 1){ |
| | | value = _udp_ota.peek(); |
| | | if(value < '0' || value > '9'){ |
| | | data[index++] = '\0'; |
| | | return atoi(data); |
| | | } |
| | | data[index++] = _udp_ota.read(); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | String ArduinoOTAClass::readStringUntil(char end){ |
| | | String res = ""; |
| | | int value; |
| | | while(true){ |
| | | value = _udp_ota.read(); |
| | | if(value <= 0 || value == end){ |
| | | return res; |
| | | } |
| | | res += (char)value; |
| | | } |
| | | return res; |
| | | } |
| | | |
| | | void ArduinoOTAClass::_onRx(){ |
| | | if (_state == OTA_IDLE) { |
| | | int cmd = parseInt(); |
| | | if (cmd != U_FLASH && cmd != U_SPIFFS) |
| | | return; |
| | | _cmd = cmd; |
| | | _ota_port = parseInt(); |
| | | _size = parseInt(); |
| | | _udp_ota.read(); |
| | | _md5 = readStringUntil('\n'); |
| | | _md5.trim(); |
| | | if(_md5.length() != 32){ |
| | | return; |
| | | } |
| | | |
| | | if (_password.length()){ |
| | | MD5Builder nonce_md5; |
| | | nonce_md5.begin(); |
| | | nonce_md5.add(String(micros())); |
| | | nonce_md5.calculate(); |
| | | _nonce = nonce_md5.toString(); |
| | | |
| | | _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); |
| | | _udp_ota.printf("AUTH %s", _nonce.c_str()); |
| | | _udp_ota.endPacket(); |
| | | _state = OTA_WAITAUTH; |
| | | return; |
| | | } else { |
| | | _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); |
| | | _udp_ota.print("OK"); |
| | | _udp_ota.endPacket(); |
| | | _ota_ip = _udp_ota.remoteIP(); |
| | | _state = OTA_RUNUPDATE; |
| | | } |
| | | } else if (_state == OTA_WAITAUTH) { |
| | | int cmd = parseInt(); |
| | | if (cmd != U_AUTH) { |
| | | _state = OTA_IDLE; |
| | | return; |
| | | } |
| | | _udp_ota.read(); |
| | | String cnonce = readStringUntil(' '); |
| | | String response = readStringUntil('\n'); |
| | | if (cnonce.length() != 32 || response.length() != 32) { |
| | | _state = OTA_IDLE; |
| | | return; |
| | | } |
| | | |
| | | String challenge = _password + ":" + String(_nonce) + ":" + cnonce; |
| | | MD5Builder _challengemd5; |
| | | _challengemd5.begin(); |
| | | _challengemd5.add(challenge); |
| | | _challengemd5.calculate(); |
| | | String result = _challengemd5.toString(); |
| | | |
| | | if(result.equals(response)){ |
| | | _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); |
| | | _udp_ota.print("OK"); |
| | | _udp_ota.endPacket(); |
| | | _ota_ip = _udp_ota.remoteIP(); |
| | | _state = OTA_RUNUPDATE; |
| | | } else { |
| | | _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); |
| | | _udp_ota.print("Authentication Failed"); |
| | | _udp_ota.endPacket(); |
| | | if (_error_callback) _error_callback(OTA_AUTH_ERROR); |
| | | _state = OTA_IDLE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void ArduinoOTAClass::_runUpdate() { |
| | | if (!Update.begin(_size, _cmd)) { |
| | | #ifdef OTA_DEBUG |
| | | Update.printError(OTA_DEBUG); |
| | | #endif |
| | | if (_error_callback) { |
| | | _error_callback(OTA_BEGIN_ERROR); |
| | | } |
| | | _state = OTA_IDLE; |
| | | return; |
| | | } |
| | | Update.setMD5(_md5.c_str()); |
| | | |
| | | if (_start_callback) { |
| | | _start_callback(); |
| | | } |
| | | if (_progress_callback) { |
| | | _progress_callback(0, _size); |
| | | } |
| | | |
| | | WiFiClient client; |
| | | if (!client.connect(_ota_ip, _ota_port)) { |
| | | if (_error_callback) { |
| | | _error_callback(OTA_CONNECT_ERROR); |
| | | } |
| | | _state = OTA_IDLE; |
| | | } |
| | | |
| | | uint32_t written = 0, total = 0, tried = 0; |
| | | |
| | | while (!Update.isFinished() && client.connected()) { |
| | | size_t waited = _ota_timeout; |
| | | size_t available = client.available(); |
| | | while (!available && waited){ |
| | | delay(1); |
| | | waited -=1 ; |
| | | available = client.available(); |
| | | } |
| | | if (!waited){ |
| | | if(written && tried++ < 3){ |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("Try[%u]: %u\n", tried, written); |
| | | #endif |
| | | if(!client.printf("%u", written)){ |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("failed to respond\n"); |
| | | #endif |
| | | _state = OTA_IDLE; |
| | | break; |
| | | } |
| | | continue; |
| | | } |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("Receive Failed\n"); |
| | | #endif |
| | | if (_error_callback) { |
| | | _error_callback(OTA_RECEIVE_ERROR); |
| | | } |
| | | _state = OTA_IDLE; |
| | | Update.abort(); |
| | | return; |
| | | } |
| | | if(!available){ |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("No Data: %u\n", waited); |
| | | #endif |
| | | _state = OTA_IDLE; |
| | | break; |
| | | } |
| | | tried = 0; |
| | | static uint8_t buf[1460]; |
| | | if(available > 1460){ |
| | | available = 1460; |
| | | } |
| | | size_t r = client.read(buf, available); |
| | | if(r != available){ |
| | | log_w("didn't read enough! %u != %u", r, available); |
| | | } |
| | | |
| | | written = Update.write(buf, r); |
| | | if (written > 0) { |
| | | if(written != r){ |
| | | log_w("didn't write enough! %u != %u", written, r); |
| | | } |
| | | if(!client.printf("%u", written)){ |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.printf("failed to respond\n"); |
| | | #endif |
| | | } |
| | | total += written; |
| | | if(_progress_callback) { |
| | | _progress_callback(total, _size); |
| | | } |
| | | } else { |
| | | #ifdef OTA_DEBUG |
| | | Update.printError(OTA_DEBUG); |
| | | #endif |
| | | } |
| | | } |
| | | |
| | | if (Update.end()) { |
| | | client.print("OK"); |
| | | client.stop(); |
| | | delay(10); |
| | | if (_end_callback) { |
| | | _end_callback(); |
| | | } |
| | | if(_rebootOnSuccess){ |
| | | //let serial/network finish tasks that might be given in _end_callback |
| | | delay(100); |
| | | ESP.restart(); |
| | | } |
| | | } else { |
| | | if (_error_callback) { |
| | | _error_callback(OTA_END_ERROR); |
| | | } |
| | | Update.printError(client); |
| | | client.stop(); |
| | | delay(10); |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.print("Update ERROR: "); |
| | | Update.printError(OTA_DEBUG); |
| | | #endif |
| | | _state = OTA_IDLE; |
| | | } |
| | | } |
| | | |
| | | void ArduinoOTAClass::end() { |
| | | _initialized = false; |
| | | _udp_ota.stop(); |
| | | if(_mdnsEnabled){ |
| | | MDNS.end(); |
| | | } |
| | | _state = OTA_IDLE; |
| | | #ifdef OTA_DEBUG |
| | | OTA_DEBUG.println("OTA server stopped."); |
| | | #endif |
| | | } |
| | | |
| | | void ArduinoOTAClass::handle() { |
| | | if (!_initialized) { |
| | | return; |
| | | } |
| | | if (_state == OTA_RUNUPDATE) { |
| | | _runUpdate(); |
| | | _state = OTA_IDLE; |
| | | } |
| | | if(_udp_ota.parsePacket()){ |
| | | _onRx(); |
| | | } |
| | | _udp_ota.flush(); // always flush, even zero length packets must be flushed. |
| | | } |
| | | |
| | | int ArduinoOTAClass::getCommand() { |
| | | return _cmd; |
| | | } |
| | | |
| | | void ArduinoOTAClass::setTimeout(int timeoutInMillis) { |
| | | _ota_timeout = timeoutInMillis; |
| | | } |
| | | |
| | | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) |
| | | ArduinoOTAClass ArduinoOTA; |
| | | #endif |
| New file |
| | |
| | | #ifndef __ARDUINO_OTA_H |
| | | #define __ARDUINO_OTA_H |
| | | |
| | | #include <WiFi.h> |
| | | #include <functional> |
| | | #include "Update.h" |
| | | |
| | | #define INT_BUFFER_SIZE 16 |
| | | |
| | | typedef enum { |
| | | OTA_IDLE, |
| | | OTA_WAITAUTH, |
| | | OTA_RUNUPDATE |
| | | } ota_state_t; |
| | | |
| | | typedef enum { |
| | | OTA_AUTH_ERROR, |
| | | OTA_BEGIN_ERROR, |
| | | OTA_CONNECT_ERROR, |
| | | OTA_RECEIVE_ERROR, |
| | | OTA_END_ERROR |
| | | } ota_error_t; |
| | | |
| | | class ArduinoOTAClass |
| | | { |
| | | public: |
| | | typedef std::function<void(void)> THandlerFunction; |
| | | typedef std::function<void(ota_error_t)> THandlerFunction_Error; |
| | | typedef std::function<void(unsigned int, unsigned int)> THandlerFunction_Progress; |
| | | |
| | | ArduinoOTAClass(); |
| | | ~ArduinoOTAClass(); |
| | | |
| | | //Sets the service port. Default 3232 |
| | | ArduinoOTAClass& setPort(uint16_t port); |
| | | |
| | | //Sets the device hostname. Default esp32-xxxxxx |
| | | ArduinoOTAClass& setHostname(const char *hostname); |
| | | String getHostname(); |
| | | |
| | | //Sets the password that will be required for OTA. Default NULL |
| | | ArduinoOTAClass& setPassword(const char *password); |
| | | |
| | | //Sets the password as above but in the form MD5(password). Default NULL |
| | | ArduinoOTAClass& setPasswordHash(const char *password); |
| | | |
| | | //Sets if the device should be rebooted after successful update. Default true |
| | | ArduinoOTAClass& setRebootOnSuccess(bool reboot); |
| | | |
| | | //Sets if the device should advertise itself to Arduino IDE. Default true |
| | | ArduinoOTAClass& setMdnsEnabled(bool enabled); |
| | | |
| | | //This callback will be called when OTA connection has begun |
| | | ArduinoOTAClass& onStart(THandlerFunction fn); |
| | | |
| | | //This callback will be called when OTA has finished |
| | | ArduinoOTAClass& onEnd(THandlerFunction fn); |
| | | |
| | | //This callback will be called when OTA encountered Error |
| | | ArduinoOTAClass& onError(THandlerFunction_Error fn); |
| | | |
| | | //This callback will be called when OTA is receiving data |
| | | ArduinoOTAClass& onProgress(THandlerFunction_Progress fn); |
| | | |
| | | //Starts the ArduinoOTA service |
| | | void begin(); |
| | | |
| | | //Ends the ArduinoOTA service |
| | | void end(); |
| | | |
| | | //Call this in loop() to run the service |
| | | void handle(); |
| | | |
| | | //Gets update command type after OTA has started. Either U_FLASH or U_SPIFFS |
| | | int getCommand(); |
| | | |
| | | void setTimeout(int timeoutInMillis); |
| | | |
| | | private: |
| | | int _port; |
| | | String _password; |
| | | String _hostname; |
| | | String _nonce; |
| | | WiFiUDP _udp_ota; |
| | | bool _initialized; |
| | | bool _rebootOnSuccess; |
| | | bool _mdnsEnabled; |
| | | ota_state_t _state; |
| | | int _size; |
| | | int _cmd; |
| | | int _ota_port; |
| | | int _ota_timeout; |
| | | IPAddress _ota_ip; |
| | | String _md5; |
| | | |
| | | THandlerFunction _start_callback; |
| | | THandlerFunction _end_callback; |
| | | THandlerFunction_Error _error_callback; |
| | | THandlerFunction_Progress _progress_callback; |
| | | |
| | | void _runUpdate(void); |
| | | void _onRx(void); |
| | | int parseInt(void); |
| | | String readStringUntil(char end); |
| | | }; |
| | | |
| | | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) |
| | | extern ArduinoOTAClass ArduinoOTA; |
| | | #endif |
| | | |
| | | #endif /* __ARDUINO_OTA_H */ |
| New file |
| | |
| | | #include "WiFi.h" |
| | | #include "AsyncUDP.h" |
| | | |
| | | const char * ssid = "***********"; |
| | | const char * password = "***********"; |
| | | |
| | | AsyncUDP udp; |
| | | |
| | | void setup() |
| | | { |
| | | Serial.begin(115200); |
| | | WiFi.mode(WIFI_STA); |
| | | WiFi.begin(ssid, password); |
| | | if (WiFi.waitForConnectResult() != WL_CONNECTED) { |
| | | Serial.println("WiFi Failed"); |
| | | while(1) { |
| | | delay(1000); |
| | | } |
| | | } |
| | | if(udp.connect(IPAddress(192,168,1,100), 1234)) { |
| | | Serial.println("UDP connected"); |
| | | udp.onPacket([](AsyncUDPPacket packet) { |
| | | Serial.print("UDP Packet Type: "); |
| | | Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); |
| | | Serial.print(", From: "); |
| | | Serial.print(packet.remoteIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.remotePort()); |
| | | Serial.print(", To: "); |
| | | Serial.print(packet.localIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.localPort()); |
| | | Serial.print(", Length: "); |
| | | Serial.print(packet.length()); |
| | | Serial.print(", Data: "); |
| | | Serial.write(packet.data(), packet.length()); |
| | | Serial.println(); |
| | | //reply to the client |
| | | packet.printf("Got %u bytes of data", packet.length()); |
| | | }); |
| | | //Send unicast |
| | | udp.print("Hello Server!"); |
| | | } |
| | | } |
| | | |
| | | void loop() |
| | | { |
| | | delay(1000); |
| | | //Send broadcast on port 1234 |
| | | udp.broadcastTo("Anyone here?", 1234); |
| | | } |
| New file |
| | |
| | | #include "WiFi.h" |
| | | #include "AsyncUDP.h" |
| | | |
| | | const char * ssid = "***********"; |
| | | const char * password = "***********"; |
| | | |
| | | AsyncUDP udp; |
| | | |
| | | void setup() |
| | | { |
| | | Serial.begin(115200); |
| | | WiFi.mode(WIFI_STA); |
| | | WiFi.begin(ssid, password); |
| | | if (WiFi.waitForConnectResult() != WL_CONNECTED) { |
| | | Serial.println("WiFi Failed"); |
| | | while(1) { |
| | | delay(1000); |
| | | } |
| | | } |
| | | if(udp.listenMulticast(IPAddress(239,1,2,3), 1234)) { |
| | | Serial.print("UDP Listening on IP: "); |
| | | Serial.println(WiFi.localIP()); |
| | | udp.onPacket([](AsyncUDPPacket packet) { |
| | | Serial.print("UDP Packet Type: "); |
| | | Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); |
| | | Serial.print(", From: "); |
| | | Serial.print(packet.remoteIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.remotePort()); |
| | | Serial.print(", To: "); |
| | | Serial.print(packet.localIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.localPort()); |
| | | Serial.print(", Length: "); |
| | | Serial.print(packet.length()); |
| | | Serial.print(", Data: "); |
| | | Serial.write(packet.data(), packet.length()); |
| | | Serial.println(); |
| | | //reply to the client |
| | | packet.printf("Got %u bytes of data", packet.length()); |
| | | }); |
| | | //Send multicast |
| | | udp.print("Hello!"); |
| | | } |
| | | } |
| | | |
| | | void loop() |
| | | { |
| | | delay(1000); |
| | | //Send multicast |
| | | udp.print("Anyone here?"); |
| | | } |
| New file |
| | |
| | | #include "WiFi.h" |
| | | #include "AsyncUDP.h" |
| | | |
| | | const char * ssid = "***********"; |
| | | const char * password = "***********"; |
| | | |
| | | AsyncUDP udp; |
| | | |
| | | void setup() |
| | | { |
| | | Serial.begin(115200); |
| | | WiFi.mode(WIFI_STA); |
| | | WiFi.begin(ssid, password); |
| | | if (WiFi.waitForConnectResult() != WL_CONNECTED) { |
| | | Serial.println("WiFi Failed"); |
| | | while(1) { |
| | | delay(1000); |
| | | } |
| | | } |
| | | if(udp.listen(1234)) { |
| | | Serial.print("UDP Listening on IP: "); |
| | | Serial.println(WiFi.localIP()); |
| | | udp.onPacket([](AsyncUDPPacket packet) { |
| | | Serial.print("UDP Packet Type: "); |
| | | Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); |
| | | Serial.print(", From: "); |
| | | Serial.print(packet.remoteIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.remotePort()); |
| | | Serial.print(", To: "); |
| | | Serial.print(packet.localIP()); |
| | | Serial.print(":"); |
| | | Serial.print(packet.localPort()); |
| | | Serial.print(", Length: "); |
| | | Serial.print(packet.length()); |
| | | Serial.print(", Data: "); |
| | | Serial.write(packet.data(), packet.length()); |
| | | Serial.println(); |
| | | //reply to the client |
| | | packet.printf("Got %u bytes of data", packet.length()); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | void loop() |
| | | { |
| | | delay(1000); |
| | | //Send broadcast |
| | | udp.broadcast("Anyone here?"); |
| | | } |
| New file |
| | |
| | | ####################################### |
| | | # Syntax Coloring Map For Ultrasound |
| | | ####################################### |
| | | |
| | | ####################################### |
| | | # Datatypes (KEYWORD1) |
| | | ####################################### |
| | | |
| | | AsyncUDP KEYWORD1 |
| | | AsyncUDPPacket KEYWORD1 |
| | | |
| | | ####################################### |
| | | # Methods and Functions (KEYWORD2) |
| | | ####################################### |
| | | |
| | | connect KEYWORD2 |
| | | connected KEYWORD2 |
| | | listen KEYWORD2 |
| | | listenMulticast KEYWORD2 |
| | | close KEYWORD2 |
| | | write KEYWORD2 |
| | | broadcast KEYWORD2 |
| | | onPacket KEYWORD2 |
| | | data KEYWORD2 |
| | | length KEYWORD2 |
| | | localIP KEYWORD2 |
| | | localPort KEYWORD2 |
| | | remoteIP KEYWORD2 |
| | | remotePort KEYWORD2 |
| | | |
| | | ####################################### |
| | | # Constants (LITERAL1) |
| | | ####################################### |
| New file |
| | |
| | | name=ESP32 Async UDP |
| | | version=1.0.0 |
| | | author=Me-No-Dev |
| | | maintainer=Me-No-Dev |
| | | sentence=Async UDP Library for ESP32 |
| | | paragraph=Async UDP Library for ESP32 |
| | | category=Other |
| | | url=https://github.com/me-no-dev/ESPAsyncUDP |
| | | architectures=* |
| New file |
| | |
| | | #include "Arduino.h" |
| | | #include "AsyncUDP.h" |
| | | |
| | | extern "C" { |
| | | #include "lwip/opt.h" |
| | | #include "lwip/inet.h" |
| | | #include "lwip/udp.h" |
| | | #include "lwip/igmp.h" |
| | | #include "lwip/ip_addr.h" |
| | | #include "lwip/mld6.h" |
| | | #include "lwip/prot/ethernet.h" |
| | | #include <esp_err.h> |
| | | #include <esp_wifi.h> |
| | | } |
| | | |
| | | #include "lwip/priv/tcpip_priv.h" |
| | | |
| | | typedef struct { |
| | | struct tcpip_api_call_data call; |
| | | udp_pcb * pcb; |
| | | const ip_addr_t *addr; |
| | | uint16_t port; |
| | | struct pbuf *pb; |
| | | struct netif *netif; |
| | | err_t err; |
| | | } udp_api_call_t; |
| | | |
| | | static err_t _udp_connect_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = udp_connect(msg->pcb, msg->addr, msg->port); |
| | | return msg->err; |
| | | } |
| | | |
| | | static err_t _udp_connect(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | msg.addr = addr; |
| | | msg.port = port; |
| | | tcpip_api_call(_udp_connect_api, (struct tcpip_api_call_data*)&msg); |
| | | return msg.err; |
| | | } |
| | | |
| | | static err_t _udp_disconnect_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = 0; |
| | | udp_disconnect(msg->pcb); |
| | | return msg->err; |
| | | } |
| | | |
| | | static void _udp_disconnect(struct udp_pcb *pcb){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call_data*)&msg); |
| | | } |
| | | |
| | | static err_t _udp_remove_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = 0; |
| | | udp_remove(msg->pcb); |
| | | return msg->err; |
| | | } |
| | | |
| | | static void _udp_remove(struct udp_pcb *pcb){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | tcpip_api_call(_udp_remove_api, (struct tcpip_api_call_data*)&msg); |
| | | } |
| | | |
| | | static err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = udp_bind(msg->pcb, msg->addr, msg->port); |
| | | return msg->err; |
| | | } |
| | | |
| | | static err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | msg.addr = addr; |
| | | msg.port = port; |
| | | tcpip_api_call(_udp_bind_api, (struct tcpip_api_call_data*)&msg); |
| | | return msg.err; |
| | | } |
| | | |
| | | static err_t _udp_sendto_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = udp_sendto(msg->pcb, msg->pb, msg->addr, msg->port); |
| | | return msg->err; |
| | | } |
| | | |
| | | static err_t _udp_sendto(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | msg.addr = addr; |
| | | msg.port = port; |
| | | msg.pb = pb; |
| | | tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call_data*)&msg); |
| | | return msg.err; |
| | | } |
| | | |
| | | static err_t _udp_sendto_if_api(struct tcpip_api_call_data *api_call_msg){ |
| | | udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; |
| | | msg->err = udp_sendto_if(msg->pcb, msg->pb, msg->addr, msg->port, msg->netif); |
| | | return msg->err; |
| | | } |
| | | |
| | | static err_t _udp_sendto_if(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port, struct netif *netif){ |
| | | udp_api_call_t msg; |
| | | msg.pcb = pcb; |
| | | msg.addr = addr; |
| | | msg.port = port; |
| | | msg.pb = pb; |
| | | msg.netif = netif; |
| | | tcpip_api_call(_udp_sendto_if_api, (struct tcpip_api_call_data*)&msg); |
| | | return msg.err; |
| | | } |
| | | |
| | | typedef struct { |
| | | void *arg; |
| | | udp_pcb *pcb; |
| | | pbuf *pb; |
| | | const ip_addr_t *addr; |
| | | uint16_t port; |
| | | struct netif * netif; |
| | | } lwip_event_packet_t; |
| | | |
| | | static xQueueHandle _udp_queue; |
| | | static volatile TaskHandle_t _udp_task_handle = NULL; |
| | | |
| | | static void _udp_task(void *pvParameters){ |
| | | lwip_event_packet_t * e = NULL; |
| | | for (;;) { |
| | | if(xQueueReceive(_udp_queue, &e, portMAX_DELAY) == pdTRUE){ |
| | | if(!e->pb){ |
| | | free((void*)(e)); |
| | | continue; |
| | | } |
| | | AsyncUDP::_s_recv(e->arg, e->pcb, e->pb, e->addr, e->port, e->netif); |
| | | free((void*)(e)); |
| | | } |
| | | } |
| | | _udp_task_handle = NULL; |
| | | vTaskDelete(NULL); |
| | | } |
| | | |
| | | static bool _udp_task_start(){ |
| | | if(!_udp_queue){ |
| | | _udp_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); |
| | | if(!_udp_queue){ |
| | | return false; |
| | | } |
| | | } |
| | | if(!_udp_task_handle){ |
| | | xTaskCreateUniversal(_udp_task, "async_udp", 4096, NULL, 3, (TaskHandle_t*)&_udp_task_handle, CONFIG_ARDUINO_UDP_RUNNING_CORE); |
| | | if(!_udp_task_handle){ |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | static bool _udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif) |
| | | { |
| | | if(!_udp_task_handle || !_udp_queue){ |
| | | return false; |
| | | } |
| | | lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); |
| | | if(!e){ |
| | | return false; |
| | | } |
| | | e->arg = arg; |
| | | e->pcb = pcb; |
| | | e->pb = pb; |
| | | e->addr = addr; |
| | | e->port = port; |
| | | e->netif = netif; |
| | | if (xQueueSend(_udp_queue, &e, portMAX_DELAY) != pdPASS) { |
| | | free((void*)(e)); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | static void _udp_recv(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) |
| | | { |
| | | while(pb != NULL) { |
| | | pbuf * this_pb = pb; |
| | | pb = pb->next; |
| | | this_pb->next = NULL; |
| | | if(!_udp_task_post(arg, pcb, this_pb, addr, port, ip_current_input_netif())){ |
| | | pbuf_free(this_pb); |
| | | } |
| | | } |
| | | } |
| | | /* |
| | | static bool _udp_task_stop(){ |
| | | if(!_udp_task_post(NULL, NULL, NULL, NULL, 0, NULL)){ |
| | | return false; |
| | | } |
| | | while(_udp_task_handle){ |
| | | vTaskDelay(10); |
| | | } |
| | | |
| | | lwip_event_packet_t * e; |
| | | while (xQueueReceive(_udp_queue, &e, 0) == pdTRUE) { |
| | | if(e->pb){ |
| | | pbuf_free(e->pb); |
| | | } |
| | | free((void*)(e)); |
| | | } |
| | | vQueueDelete(_udp_queue); |
| | | _udp_queue = NULL; |
| | | } |
| | | */ |
| | | |
| | | |
| | | |
| | | #define UDP_MUTEX_LOCK() //xSemaphoreTake(_lock, portMAX_DELAY) |
| | | #define UDP_MUTEX_UNLOCK() //xSemaphoreGive(_lock) |
| | | |
| | | |
| | | AsyncUDPMessage::AsyncUDPMessage(size_t size) |
| | | { |
| | | _index = 0; |
| | | if(size > CONFIG_TCP_MSS) { |
| | | size = CONFIG_TCP_MSS; |
| | | } |
| | | _size = size; |
| | | _buffer = (uint8_t *)malloc(size); |
| | | } |
| | | |
| | | AsyncUDPMessage::~AsyncUDPMessage() |
| | | { |
| | | if(_buffer) { |
| | | free(_buffer); |
| | | } |
| | | } |
| | | |
| | | size_t AsyncUDPMessage::write(const uint8_t *data, size_t len) |
| | | { |
| | | if(_buffer == NULL) { |
| | | return 0; |
| | | } |
| | | size_t s = space(); |
| | | if(len > s) { |
| | | len = s; |
| | | } |
| | | memcpy(_buffer + _index, data, len); |
| | | _index += len; |
| | | return len; |
| | | } |
| | | |
| | | size_t AsyncUDPMessage::write(uint8_t data) |
| | | { |
| | | return write(&data, 1); |
| | | } |
| | | |
| | | size_t AsyncUDPMessage::space() |
| | | { |
| | | if(_buffer == NULL) { |
| | | return 0; |
| | | } |
| | | return _size - _index; |
| | | } |
| | | |
| | | uint8_t * AsyncUDPMessage::data() |
| | | { |
| | | return _buffer; |
| | | } |
| | | |
| | | size_t AsyncUDPMessage::length() |
| | | { |
| | | return _index; |
| | | } |
| | | |
| | | void AsyncUDPMessage::flush() |
| | | { |
| | | _index = 0; |
| | | } |
| | | |
| | | |
| | | AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, uint16_t rport, struct netif * ntif) |
| | | { |
| | | _udp = udp; |
| | | _pb = pb; |
| | | _if = TCPIP_ADAPTER_IF_MAX; |
| | | _data = (uint8_t*)(pb->payload); |
| | | _len = pb->len; |
| | | _index = 0; |
| | | |
| | | pbuf_ref(_pb); |
| | | |
| | | //memcpy(&_remoteIp, raddr, sizeof(ip_addr_t)); |
| | | _remoteIp.type = raddr->type; |
| | | _localIp.type = _remoteIp.type; |
| | | |
| | | eth_hdr* eth = NULL; |
| | | udp_hdr* udphdr = reinterpret_cast<udp_hdr*>(_data - UDP_HLEN); |
| | | _localPort = ntohs(udphdr->dest); |
| | | _remotePort = ntohs(udphdr->src); |
| | | |
| | | if (_remoteIp.type == IPADDR_TYPE_V4) { |
| | | eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR); |
| | | struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN); |
| | | _localIp.u_addr.ip4.addr = iphdr->dest.addr; |
| | | _remoteIp.u_addr.ip4.addr = iphdr->src.addr; |
| | | } else { |
| | | eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR); |
| | | struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN); |
| | | memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); |
| | | memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16); |
| | | } |
| | | memcpy(_remoteMac, eth->src.addr, 6); |
| | | |
| | | struct netif * netif = NULL; |
| | | void * nif = NULL; |
| | | int i; |
| | | for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) { |
| | | tcpip_adapter_get_netif ((tcpip_adapter_if_t)i, &nif); |
| | | netif = (struct netif *)nif; |
| | | if (netif && netif == ntif) { |
| | | _if = (tcpip_adapter_if_t)i; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | AsyncUDPPacket::~AsyncUDPPacket() |
| | | { |
| | | pbuf_free(_pb); |
| | | } |
| | | |
| | | uint8_t * AsyncUDPPacket::data() |
| | | { |
| | | return _data; |
| | | } |
| | | |
| | | size_t AsyncUDPPacket::length() |
| | | { |
| | | return _len; |
| | | } |
| | | |
| | | int AsyncUDPPacket::available(){ |
| | | return _len - _index; |
| | | } |
| | | |
| | | size_t AsyncUDPPacket::read(uint8_t *data, size_t len){ |
| | | size_t i; |
| | | size_t a = _len - _index; |
| | | if(len > a){ |
| | | len = a; |
| | | } |
| | | for(i=0;i<len;i++){ |
| | | data[i] = read(); |
| | | } |
| | | return len; |
| | | } |
| | | |
| | | int AsyncUDPPacket::read(){ |
| | | if(_index < _len){ |
| | | return _data[_index++]; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | int AsyncUDPPacket::peek(){ |
| | | if(_index < _len){ |
| | | return _data[_index]; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | void AsyncUDPPacket::flush(){ |
| | | _index = _len; |
| | | } |
| | | |
| | | tcpip_adapter_if_t AsyncUDPPacket::interface() |
| | | { |
| | | return _if; |
| | | } |
| | | |
| | | IPAddress AsyncUDPPacket::localIP() |
| | | { |
| | | if(_localIp.type != IPADDR_TYPE_V4){ |
| | | return IPAddress(); |
| | | } |
| | | return IPAddress(_localIp.u_addr.ip4.addr); |
| | | } |
| | | |
| | | IPv6Address AsyncUDPPacket::localIPv6() |
| | | { |
| | | if(_localIp.type != IPADDR_TYPE_V6){ |
| | | return IPv6Address(); |
| | | } |
| | | return IPv6Address(_localIp.u_addr.ip6.addr); |
| | | } |
| | | |
| | | uint16_t AsyncUDPPacket::localPort() |
| | | { |
| | | return _localPort; |
| | | } |
| | | |
| | | IPAddress AsyncUDPPacket::remoteIP() |
| | | { |
| | | if(_remoteIp.type != IPADDR_TYPE_V4){ |
| | | return IPAddress(); |
| | | } |
| | | return IPAddress(_remoteIp.u_addr.ip4.addr); |
| | | } |
| | | |
| | | IPv6Address AsyncUDPPacket::remoteIPv6() |
| | | { |
| | | if(_remoteIp.type != IPADDR_TYPE_V6){ |
| | | return IPv6Address(); |
| | | } |
| | | return IPv6Address(_remoteIp.u_addr.ip6.addr); |
| | | } |
| | | |
| | | uint16_t AsyncUDPPacket::remotePort() |
| | | { |
| | | return _remotePort; |
| | | } |
| | | |
| | | void AsyncUDPPacket::remoteMac(uint8_t * mac) |
| | | { |
| | | memcpy(mac, _remoteMac, 6); |
| | | } |
| | | |
| | | bool AsyncUDPPacket::isIPv6() |
| | | { |
| | | return _localIp.type == IPADDR_TYPE_V6; |
| | | } |
| | | |
| | | bool AsyncUDPPacket::isBroadcast() |
| | | { |
| | | if(_localIp.type == IPADDR_TYPE_V6){ |
| | | return false; |
| | | } |
| | | uint32_t ip = _localIp.u_addr.ip4.addr; |
| | | return ip == 0xFFFFFFFF || ip == 0 || (ip & 0xFF000000) == 0xFF000000; |
| | | } |
| | | |
| | | bool AsyncUDPPacket::isMulticast() |
| | | { |
| | | return ip_addr_ismulticast(&(_localIp)); |
| | | } |
| | | |
| | | size_t AsyncUDPPacket::write(const uint8_t *data, size_t len) |
| | | { |
| | | if(!data){ |
| | | return 0; |
| | | } |
| | | return _udp->writeTo(data, len, &_remoteIp, _remotePort, _if); |
| | | } |
| | | |
| | | size_t AsyncUDPPacket::write(uint8_t data) |
| | | { |
| | | return write(&data, 1); |
| | | } |
| | | |
| | | size_t AsyncUDPPacket::send(AsyncUDPMessage &message) |
| | | { |
| | | return write(message.data(), message.length()); |
| | | } |
| | | |
| | | bool AsyncUDP::_init(){ |
| | | if(_pcb){ |
| | | return true; |
| | | } |
| | | _pcb = udp_new(); |
| | | if(!_pcb){ |
| | | return false; |
| | | } |
| | | //_lock = xSemaphoreCreateMutex(); |
| | | udp_recv(_pcb, &_udp_recv, (void *) this); |
| | | return true; |
| | | } |
| | | |
| | | AsyncUDP::AsyncUDP() |
| | | { |
| | | _pcb = NULL; |
| | | _connected = false; |
| | | _handler = NULL; |
| | | } |
| | | |
| | | AsyncUDP::~AsyncUDP() |
| | | { |
| | | close(); |
| | | UDP_MUTEX_LOCK(); |
| | | udp_recv(_pcb, NULL, NULL); |
| | | _udp_remove(_pcb); |
| | | _pcb = NULL; |
| | | UDP_MUTEX_UNLOCK(); |
| | | //vSemaphoreDelete(_lock); |
| | | } |
| | | |
| | | void AsyncUDP::close() |
| | | { |
| | | UDP_MUTEX_LOCK(); |
| | | if(_pcb != NULL) { |
| | | if(_connected) { |
| | | _udp_disconnect(_pcb); |
| | | } |
| | | _connected = false; |
| | | //todo: unjoin multicast group |
| | | } |
| | | UDP_MUTEX_UNLOCK(); |
| | | } |
| | | |
| | | bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port) |
| | | { |
| | | if(!_udp_task_start()){ |
| | | log_e("failed to start task"); |
| | | return false; |
| | | } |
| | | if(!_init()) { |
| | | return false; |
| | | } |
| | | close(); |
| | | UDP_MUTEX_LOCK(); |
| | | err_t err = _udp_connect(_pcb, addr, port); |
| | | if(err != ERR_OK) { |
| | | UDP_MUTEX_UNLOCK(); |
| | | return false; |
| | | } |
| | | _connected = true; |
| | | UDP_MUTEX_UNLOCK(); |
| | | return true; |
| | | } |
| | | |
| | | bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port) |
| | | { |
| | | if(!_udp_task_start()){ |
| | | log_e("failed to start task"); |
| | | return false; |
| | | } |
| | | if(!_init()) { |
| | | return false; |
| | | } |
| | | close(); |
| | | if(addr){ |
| | | IP_SET_TYPE_VAL(_pcb->local_ip, addr->type); |
| | | IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type); |
| | | } |
| | | UDP_MUTEX_LOCK(); |
| | | if(_udp_bind(_pcb, addr, port) != ERR_OK) { |
| | | UDP_MUTEX_UNLOCK(); |
| | | return false; |
| | | } |
| | | _connected = true; |
| | | UDP_MUTEX_UNLOCK(); |
| | | return true; |
| | | } |
| | | |
| | | static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX) |
| | | { |
| | | struct netif * netif = NULL; |
| | | if(tcpip_if < TCPIP_ADAPTER_IF_MAX){ |
| | | void * nif = NULL; |
| | | esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif); |
| | | if (err) { |
| | | return ESP_ERR_INVALID_ARG; |
| | | } |
| | | netif = (struct netif *)nif; |
| | | |
| | | if (addr->type == IPADDR_TYPE_V4) { |
| | | if(join){ |
| | | if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } else { |
| | | if (igmp_leavegroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } |
| | | } else { |
| | | if(join){ |
| | | if (mld6_joingroup_netif(netif, &(addr->u_addr.ip6))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } else { |
| | | if (mld6_leavegroup_netif(netif, &(addr->u_addr.ip6))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | if (addr->type == IPADDR_TYPE_V4) { |
| | | if(join){ |
| | | if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } else { |
| | | if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } |
| | | } else { |
| | | if(join){ |
| | | if (mld6_joingroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } else { |
| | | if (mld6_leavegroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) { |
| | | return ESP_ERR_INVALID_STATE; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return ESP_OK; |
| | | } |
| | | |
| | | bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!ip_addr_ismulticast(addr)) { |
| | | return false; |
| | | } |
| | | |
| | | if (joinMulticastGroup(addr, true, tcpip_if)!= ERR_OK) { |
| | | return false; |
| | | } |
| | | |
| | | if(!listen(NULL, port)) { |
| | | return false; |
| | | } |
| | | |
| | | UDP_MUTEX_LOCK(); |
| | | _pcb->mcast_ttl = ttl; |
| | | _pcb->remote_port = port; |
| | | ip_addr_copy(_pcb->remote_ip, *addr); |
| | | //ip_addr_copy(_pcb->remote_ip, ip_addr_any_type); |
| | | UDP_MUTEX_UNLOCK(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!_pcb) { |
| | | UDP_MUTEX_LOCK(); |
| | | _pcb = udp_new(); |
| | | UDP_MUTEX_UNLOCK(); |
| | | if(_pcb == NULL) { |
| | | return 0; |
| | | } |
| | | } |
| | | if(len > CONFIG_TCP_MSS) { |
| | | len = CONFIG_TCP_MSS; |
| | | } |
| | | err_t err = ERR_OK; |
| | | pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); |
| | | if(pbt != NULL) { |
| | | uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload); |
| | | memcpy(dst, data, len); |
| | | UDP_MUTEX_LOCK(); |
| | | if(tcpip_if < TCPIP_ADAPTER_IF_MAX){ |
| | | void * nif = NULL; |
| | | tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif); |
| | | if(!nif){ |
| | | err = _udp_sendto(_pcb, pbt, addr, port); |
| | | } else { |
| | | err = _udp_sendto_if(_pcb, pbt, addr, port, (struct netif *)nif); |
| | | } |
| | | } else { |
| | | err = _udp_sendto(_pcb, pbt, addr, port); |
| | | } |
| | | UDP_MUTEX_UNLOCK(); |
| | | pbuf_free(pbt); |
| | | if(err < ERR_OK) { |
| | | return 0; |
| | | } |
| | | return len; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif) |
| | | { |
| | | while(pb != NULL) { |
| | | pbuf * this_pb = pb; |
| | | pb = pb->next; |
| | | this_pb->next = NULL; |
| | | if(_handler) { |
| | | AsyncUDPPacket packet(this, this_pb, addr, port, netif); |
| | | _handler(packet); |
| | | } else { |
| | | pbuf_free(this_pb); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif) |
| | | { |
| | | reinterpret_cast<AsyncUDP*>(arg)->_recv(upcb, p, addr, port, netif); |
| | | } |
| | | |
| | | bool AsyncUDP::listen(uint16_t port) |
| | | { |
| | | return listen(IP_ANY_TYPE, port); |
| | | } |
| | | |
| | | bool AsyncUDP::listen(const IPAddress addr, uint16_t port) |
| | | { |
| | | ip_addr_t laddr; |
| | | laddr.type = IPADDR_TYPE_V4; |
| | | laddr.u_addr.ip4.addr = addr; |
| | | return listen(&laddr, port); |
| | | } |
| | | |
| | | bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | ip_addr_t laddr; |
| | | laddr.type = IPADDR_TYPE_V4; |
| | | laddr.u_addr.ip4.addr = addr; |
| | | return listenMulticast(&laddr, port, ttl, tcpip_if); |
| | | } |
| | | |
| | | bool AsyncUDP::connect(const IPAddress addr, uint16_t port) |
| | | { |
| | | ip_addr_t daddr; |
| | | daddr.type = IPADDR_TYPE_V4; |
| | | daddr.u_addr.ip4.addr = addr; |
| | | return connect(&daddr, port); |
| | | } |
| | | |
| | | size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | ip_addr_t daddr; |
| | | daddr.type = IPADDR_TYPE_V4; |
| | | daddr.u_addr.ip4.addr = addr; |
| | | return writeTo(data, len, &daddr, port, tcpip_if); |
| | | } |
| | | |
| | | IPAddress AsyncUDP::listenIP() |
| | | { |
| | | if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V4){ |
| | | return IPAddress(); |
| | | } |
| | | return IPAddress(_pcb->remote_ip.u_addr.ip4.addr); |
| | | } |
| | | |
| | | bool AsyncUDP::listen(const IPv6Address addr, uint16_t port) |
| | | { |
| | | ip_addr_t laddr; |
| | | laddr.type = IPADDR_TYPE_V6; |
| | | memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); |
| | | return listen(&laddr, port); |
| | | } |
| | | |
| | | bool AsyncUDP::listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | ip_addr_t laddr; |
| | | laddr.type = IPADDR_TYPE_V6; |
| | | memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); |
| | | return listenMulticast(&laddr, port, ttl, tcpip_if); |
| | | } |
| | | |
| | | bool AsyncUDP::connect(const IPv6Address addr, uint16_t port) |
| | | { |
| | | ip_addr_t daddr; |
| | | daddr.type = IPADDR_TYPE_V6; |
| | | memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); |
| | | return connect(&daddr, port); |
| | | } |
| | | |
| | | size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | ip_addr_t daddr; |
| | | daddr.type = IPADDR_TYPE_V6; |
| | | memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); |
| | | return writeTo(data, len, &daddr, port, tcpip_if); |
| | | } |
| | | |
| | | IPv6Address AsyncUDP::listenIPv6() |
| | | { |
| | | if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6){ |
| | | return IPv6Address(); |
| | | } |
| | | return IPv6Address(_pcb->remote_ip.u_addr.ip6.addr); |
| | | } |
| | | |
| | | size_t AsyncUDP::write(const uint8_t *data, size_t len) |
| | | { |
| | | return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port); |
| | | } |
| | | |
| | | size_t AsyncUDP::write(uint8_t data) |
| | | { |
| | | return write(&data, 1); |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | return writeTo(data, len, IP_ADDR_BROADCAST, port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | return broadcastTo((uint8_t *)data, strlen(data), port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcast(uint8_t *data, size_t len) |
| | | { |
| | | if(_pcb->local_port != 0) { |
| | | return broadcastTo(data, len, _pcb->local_port); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcast(const char * data) |
| | | { |
| | | return broadcast((uint8_t *)data, strlen(data)); |
| | | } |
| | | |
| | | |
| | | size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return writeTo(message.data(), message.length(), addr, port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return writeTo(message.data(), message.length(), addr, port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return writeTo(message.data(), message.length(), addr, port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::send(AsyncUDPMessage &message) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return writeTo(message.data(), message.length(), &(_pcb->remote_ip), _pcb->remote_port); |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return broadcastTo(message.data(), message.length(), port, tcpip_if); |
| | | } |
| | | |
| | | size_t AsyncUDP::broadcast(AsyncUDPMessage &message) |
| | | { |
| | | if(!message) { |
| | | return 0; |
| | | } |
| | | return broadcast(message.data(), message.length()); |
| | | } |
| | | |
| | | AsyncUDP::operator bool() |
| | | { |
| | | return _connected; |
| | | } |
| | | |
| | | bool AsyncUDP::connected() |
| | | { |
| | | return _connected; |
| | | } |
| | | |
| | | void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg) |
| | | { |
| | | onPacket(std::bind(cb, arg, std::placeholders::_1)); |
| | | } |
| | | |
| | | void AsyncUDP::onPacket(AuPacketHandlerFunction cb) |
| | | { |
| | | _handler = cb; |
| | | } |
| New file |
| | |
| | | #ifndef ESPASYNCUDP_H |
| | | #define ESPASYNCUDP_H |
| | | |
| | | #include "IPAddress.h" |
| | | #include "IPv6Address.h" |
| | | #include "Print.h" |
| | | #include <functional> |
| | | extern "C" { |
| | | #include "lwip/ip_addr.h" |
| | | #include <tcpip_adapter.h> |
| | | #include "freertos/queue.h" |
| | | #include "freertos/semphr.h" |
| | | } |
| | | |
| | | class AsyncUDP; |
| | | class AsyncUDPPacket; |
| | | class AsyncUDPMessage; |
| | | struct udp_pcb; |
| | | struct pbuf; |
| | | struct netif; |
| | | |
| | | typedef std::function<void(AsyncUDPPacket& packet)> AuPacketHandlerFunction; |
| | | typedef std::function<void(void * arg, AsyncUDPPacket& packet)> AuPacketHandlerFunctionWithArg; |
| | | |
| | | class AsyncUDPMessage : public Print |
| | | { |
| | | protected: |
| | | uint8_t *_buffer; |
| | | size_t _index; |
| | | size_t _size; |
| | | public: |
| | | AsyncUDPMessage(size_t size=CONFIG_TCP_MSS); |
| | | virtual ~AsyncUDPMessage(); |
| | | size_t write(const uint8_t *data, size_t len); |
| | | size_t write(uint8_t data); |
| | | size_t space(); |
| | | uint8_t * data(); |
| | | size_t length(); |
| | | void flush(); |
| | | operator bool() |
| | | { |
| | | return _buffer != NULL; |
| | | } |
| | | }; |
| | | |
| | | class AsyncUDPPacket : public Stream |
| | | { |
| | | protected: |
| | | AsyncUDP *_udp; |
| | | pbuf *_pb; |
| | | tcpip_adapter_if_t _if; |
| | | ip_addr_t _localIp; |
| | | uint16_t _localPort; |
| | | ip_addr_t _remoteIp; |
| | | uint16_t _remotePort; |
| | | uint8_t _remoteMac[6]; |
| | | uint8_t *_data; |
| | | size_t _len; |
| | | size_t _index; |
| | | public: |
| | | AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif); |
| | | virtual ~AsyncUDPPacket(); |
| | | |
| | | uint8_t * data(); |
| | | size_t length(); |
| | | bool isBroadcast(); |
| | | bool isMulticast(); |
| | | bool isIPv6(); |
| | | |
| | | tcpip_adapter_if_t interface(); |
| | | |
| | | IPAddress localIP(); |
| | | IPv6Address localIPv6(); |
| | | uint16_t localPort(); |
| | | IPAddress remoteIP(); |
| | | IPv6Address remoteIPv6(); |
| | | uint16_t remotePort(); |
| | | void remoteMac(uint8_t * mac); |
| | | |
| | | size_t send(AsyncUDPMessage &message); |
| | | |
| | | int available(); |
| | | size_t read(uint8_t *data, size_t len); |
| | | int read(); |
| | | int peek(); |
| | | void flush(); |
| | | |
| | | size_t write(const uint8_t *data, size_t len); |
| | | size_t write(uint8_t data); |
| | | }; |
| | | |
| | | class AsyncUDP : public Print |
| | | { |
| | | protected: |
| | | udp_pcb *_pcb; |
| | | //xSemaphoreHandle _lock; |
| | | bool _connected; |
| | | AuPacketHandlerFunction _handler; |
| | | |
| | | bool _init(); |
| | | void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif); |
| | | |
| | | public: |
| | | AsyncUDP(); |
| | | virtual ~AsyncUDP(); |
| | | |
| | | void onPacket(AuPacketHandlerFunctionWithArg cb, void * arg=NULL); |
| | | void onPacket(AuPacketHandlerFunction cb); |
| | | |
| | | bool listen(const ip_addr_t *addr, uint16_t port); |
| | | bool listen(const IPAddress addr, uint16_t port); |
| | | bool listen(const IPv6Address addr, uint16_t port); |
| | | bool listen(uint16_t port); |
| | | |
| | | bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | |
| | | bool connect(const ip_addr_t *addr, uint16_t port); |
| | | bool connect(const IPAddress addr, uint16_t port); |
| | | bool connect(const IPv6Address addr, uint16_t port); |
| | | |
| | | void close(); |
| | | |
| | | size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t write(const uint8_t *data, size_t len); |
| | | size_t write(uint8_t data); |
| | | |
| | | size_t broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t broadcast(uint8_t *data, size_t len); |
| | | size_t broadcast(const char * data); |
| | | |
| | | size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t send(AsyncUDPMessage &message); |
| | | |
| | | size_t broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); |
| | | size_t broadcast(AsyncUDPMessage &message); |
| | | |
| | | IPAddress listenIP(); |
| | | IPv6Address listenIPv6(); |
| | | bool connected(); |
| | | operator bool(); |
| | | |
| | | static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif); |
| | | }; |
| | | |
| | | #endif |
| New file |
| | |
| | | # ESP32 BLE for Arduino |
| | | The Arduino IDE provides an excellent library package manager where versions of libraries can be downloaded and installed. This Github project provides the repository for the ESP32 BLE support for Arduino. |
| | | |
| | | The actual source of the project which is being maintained can be found here: |
| | | |
| | | https://github.com/nkolban/esp32-snippets |
| | | |
| | | Issues and questions should be raised here: |
| | | |
| | | https://github.com/nkolban/esp32-snippets/issues |
| | | |
| | | |
| | | Documentation for using the library can be found here: |
| | | |
| | | https://github.com/nkolban/esp32-snippets/tree/master/Documentation |
| New file |
| | |
| | | /** |
| | | * A BLE client example that is rich in capabilities. |
| | | * There is a lot new capabilities implemented. |
| | | * author unknown |
| | | * updated by chegewara |
| | | */ |
| | | |
| | | #include "BLEDevice.h" |
| | | //#include "BLEScan.h" |
| | | |
| | | // The remote service we wish to connect to. |
| | | static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); |
| | | // The characteristic of the remote service we are interested in. |
| | | static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); |
| | | |
| | | static boolean doConnect = false; |
| | | static boolean connected = false; |
| | | static boolean doScan = false; |
| | | static BLERemoteCharacteristic* pRemoteCharacteristic; |
| | | static BLEAdvertisedDevice* myDevice; |
| | | |
| | | static void notifyCallback( |
| | | BLERemoteCharacteristic* pBLERemoteCharacteristic, |
| | | uint8_t* pData, |
| | | size_t length, |
| | | bool isNotify) { |
| | | Serial.print("Notify callback for characteristic "); |
| | | Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); |
| | | Serial.print(" of data length "); |
| | | Serial.println(length); |
| | | Serial.print("data: "); |
| | | Serial.println((char*)pData); |
| | | } |
| | | |
| | | class MyClientCallback : public BLEClientCallbacks { |
| | | void onConnect(BLEClient* pclient) { |
| | | } |
| | | |
| | | void onDisconnect(BLEClient* pclient) { |
| | | connected = false; |
| | | Serial.println("onDisconnect"); |
| | | } |
| | | }; |
| | | |
| | | bool connectToServer() { |
| | | Serial.print("Forming a connection to "); |
| | | Serial.println(myDevice->getAddress().toString().c_str()); |
| | | |
| | | BLEClient* pClient = BLEDevice::createClient(); |
| | | Serial.println(" - Created client"); |
| | | |
| | | pClient->setClientCallbacks(new MyClientCallback()); |
| | | |
| | | // Connect to the remove BLE Server. |
| | | pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private) |
| | | Serial.println(" - Connected to server"); |
| | | |
| | | // Obtain a reference to the service we are after in the remote BLE server. |
| | | BLERemoteService* pRemoteService = pClient->getService(serviceUUID); |
| | | if (pRemoteService == nullptr) { |
| | | Serial.print("Failed to find our service UUID: "); |
| | | Serial.println(serviceUUID.toString().c_str()); |
| | | pClient->disconnect(); |
| | | return false; |
| | | } |
| | | Serial.println(" - Found our service"); |
| | | |
| | | |
| | | // Obtain a reference to the characteristic in the service of the remote BLE server. |
| | | pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); |
| | | if (pRemoteCharacteristic == nullptr) { |
| | | Serial.print("Failed to find our characteristic UUID: "); |
| | | Serial.println(charUUID.toString().c_str()); |
| | | pClient->disconnect(); |
| | | return false; |
| | | } |
| | | Serial.println(" - Found our characteristic"); |
| | | |
| | | // Read the value of the characteristic. |
| | | if(pRemoteCharacteristic->canRead()) { |
| | | std::string value = pRemoteCharacteristic->readValue(); |
| | | Serial.print("The characteristic value was: "); |
| | | Serial.println(value.c_str()); |
| | | } |
| | | |
| | | if(pRemoteCharacteristic->canNotify()) |
| | | pRemoteCharacteristic->registerForNotify(notifyCallback); |
| | | |
| | | connected = true; |
| | | } |
| | | /** |
| | | * Scan for BLE servers and find the first one that advertises the service we are looking for. |
| | | */ |
| | | class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { |
| | | /** |
| | | * Called for each advertising BLE server. |
| | | */ |
| | | void onResult(BLEAdvertisedDevice advertisedDevice) { |
| | | Serial.print("BLE Advertised Device found: "); |
| | | Serial.println(advertisedDevice.toString().c_str()); |
| | | |
| | | // We have found a device, let us now see if it contains the service we are looking for. |
| | | if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) { |
| | | |
| | | BLEDevice::getScan()->stop(); |
| | | myDevice = new BLEAdvertisedDevice(advertisedDevice); |
| | | doConnect = true; |
| | | doScan = true; |
| | | |
| | | } // Found our server |
| | | } // onResult |
| | | }; // MyAdvertisedDeviceCallbacks |
| | | |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | Serial.println("Starting Arduino BLE Client application..."); |
| | | BLEDevice::init(""); |
| | | |
| | | // Retrieve a Scanner and set the callback we want to use to be informed when we |
| | | // have detected a new device. Specify that we want active scanning and start the |
| | | // scan to run for 5 seconds. |
| | | BLEScan* pBLEScan = BLEDevice::getScan(); |
| | | pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); |
| | | pBLEScan->setInterval(1349); |
| | | pBLEScan->setWindow(449); |
| | | pBLEScan->setActiveScan(true); |
| | | pBLEScan->start(5, false); |
| | | } // End of setup. |
| | | |
| | | |
| | | // This is the Arduino main loop function. |
| | | void loop() { |
| | | |
| | | // If the flag "doConnect" is true then we have scanned for and found the desired |
| | | // BLE Server with which we wish to connect. Now we connect to it. Once we are |
| | | // connected we set the connected flag to be true. |
| | | if (doConnect == true) { |
| | | if (connectToServer()) { |
| | | Serial.println("We are now connected to the BLE Server."); |
| | | } else { |
| | | Serial.println("We have failed to connect to the server; there is nothin more we will do."); |
| | | } |
| | | doConnect = false; |
| | | } |
| | | |
| | | // If we are connected to a peer BLE Server, update the characteristic each time we are reached |
| | | // with the current time since boot. |
| | | if (connected) { |
| | | String newValue = "Time since boot: " + String(millis()/1000); |
| | | Serial.println("Setting new characteristic value to \"" + newValue + "\""); |
| | | |
| | | // Set the characteristic's value to be the array of bytes that is actually a string. |
| | | pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); |
| | | }else if(doScan){ |
| | | BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino |
| | | } |
| | | |
| | | delay(1000); // Delay a second between loops. |
| | | } // End of loop |
| New file |
| | |
| | | /* |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp |
| | | Ported to Arduino ESP32 by pcbreflux |
| | | */ |
| | | |
| | | |
| | | /* |
| | | Create a BLE server that will send periodic iBeacon frames. |
| | | The design of creating the BLE server is: |
| | | 1. Create a BLE Server |
| | | 2. Create advertising data |
| | | 3. Start advertising. |
| | | 4. wait |
| | | 5. Stop advertising. |
| | | 6. deep sleep |
| | | |
| | | */ |
| | | #include "sys/time.h" |
| | | |
| | | #include "BLEDevice.h" |
| | | #include "BLEUtils.h" |
| | | #include "BLEBeacon.h" |
| | | #include "esp_sleep.h" |
| | | |
| | | #define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up |
| | | RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory |
| | | RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory |
| | | |
| | | #ifdef __cplusplus |
| | | extern "C" { |
| | | #endif |
| | | |
| | | uint8_t temprature_sens_read(); |
| | | //uint8_t g_phyFuns; |
| | | |
| | | #ifdef __cplusplus |
| | | } |
| | | #endif |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | BLEAdvertising *pAdvertising; |
| | | struct timeval now; |
| | | |
| | | #define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) |
| | | |
| | | void setBeacon() { |
| | | |
| | | BLEBeacon oBeacon = BLEBeacon(); |
| | | oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) |
| | | oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); |
| | | oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); |
| | | oBeacon.setMinor(bootcount&0xFFFF); |
| | | BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); |
| | | BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); |
| | | |
| | | oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 |
| | | |
| | | std::string strServiceData = ""; |
| | | |
| | | strServiceData += (char)26; // Len |
| | | strServiceData += (char)0xFF; // Type |
| | | strServiceData += oBeacon.getData(); |
| | | oAdvertisementData.addData(strServiceData); |
| | | |
| | | pAdvertising->setAdvertisementData(oAdvertisementData); |
| | | pAdvertising->setScanResponseData(oScanResponseData); |
| | | |
| | | } |
| | | |
| | | void setup() { |
| | | |
| | | |
| | | Serial.begin(115200); |
| | | gettimeofday(&now, NULL); |
| | | |
| | | Serial.printf("start ESP32 %d\n",bootcount++); |
| | | |
| | | Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last); |
| | | |
| | | last = now.tv_sec; |
| | | |
| | | // Create the BLE Device |
| | | BLEDevice::init(""); |
| | | |
| | | // Create the BLE Server |
| | | // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage |
| | | |
| | | pAdvertising = BLEDevice::getAdvertising(); |
| | | |
| | | setBeacon(); |
| | | // Start advertising |
| | | pAdvertising->start(); |
| | | Serial.println("Advertizing started..."); |
| | | delay(100); |
| | | pAdvertising->stop(); |
| | | Serial.printf("enter deep sleep\n"); |
| | | esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); |
| | | Serial.printf("in deep sleep\n"); |
| | | } |
| | | |
| | | void loop() { |
| | | } |
| New file |
| | |
| | | /* |
| | | Video: https://www.youtube.com/watch?v=oCMOYS71NIU |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | updated by chegewara |
| | | |
| | | Create a BLE server that, once we receive a connection, will send periodic notifications. |
| | | The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b |
| | | And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 |
| | | |
| | | The design of creating the BLE server is: |
| | | 1. Create a BLE Server |
| | | 2. Create a BLE Service |
| | | 3. Create a BLE Characteristic on the Service |
| | | 4. Create a BLE Descriptor on the characteristic |
| | | 5. Start the service. |
| | | 6. Start advertising. |
| | | |
| | | A connect hander associated with the server starts a background task that performs notification |
| | | every couple of seconds. |
| | | */ |
| | | #include <BLEDevice.h> |
| | | #include <BLEServer.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLE2902.h> |
| | | |
| | | BLEServer* pServer = NULL; |
| | | BLECharacteristic* pCharacteristic = NULL; |
| | | bool deviceConnected = false; |
| | | bool oldDeviceConnected = false; |
| | | uint32_t value = 0; |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | |
| | | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" |
| | | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
| | | |
| | | |
| | | class MyServerCallbacks: public BLEServerCallbacks { |
| | | void onConnect(BLEServer* pServer) { |
| | | deviceConnected = true; |
| | | }; |
| | | |
| | | void onDisconnect(BLEServer* pServer) { |
| | | deviceConnected = false; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | |
| | | // Create the BLE Device |
| | | BLEDevice::init("ESP32"); |
| | | |
| | | // Create the BLE Server |
| | | pServer = BLEDevice::createServer(); |
| | | pServer->setCallbacks(new MyServerCallbacks()); |
| | | |
| | | // Create the BLE Service |
| | | BLEService *pService = pServer->createService(SERVICE_UUID); |
| | | |
| | | // Create a BLE Characteristic |
| | | pCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID, |
| | | BLECharacteristic::PROPERTY_READ | |
| | | BLECharacteristic::PROPERTY_WRITE | |
| | | BLECharacteristic::PROPERTY_NOTIFY | |
| | | BLECharacteristic::PROPERTY_INDICATE |
| | | ); |
| | | |
| | | // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml |
| | | // Create a BLE Descriptor |
| | | pCharacteristic->addDescriptor(new BLE2902()); |
| | | |
| | | // Start the service |
| | | pService->start(); |
| | | |
| | | // Start advertising |
| | | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); |
| | | pAdvertising->addServiceUUID(SERVICE_UUID); |
| | | pAdvertising->setScanResponse(false); |
| | | pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter |
| | | BLEDevice::startAdvertising(); |
| | | Serial.println("Waiting a client connection to notify..."); |
| | | } |
| | | |
| | | void loop() { |
| | | // notify changed value |
| | | if (deviceConnected) { |
| | | pCharacteristic->setValue((uint8_t*)&value, 4); |
| | | pCharacteristic->notify(); |
| | | value++; |
| | | delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms |
| | | } |
| | | // disconnecting |
| | | if (!deviceConnected && oldDeviceConnected) { |
| | | delay(500); // give the bluetooth stack the chance to get things ready |
| | | pServer->startAdvertising(); // restart advertising |
| | | Serial.println("start advertising"); |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | // connecting |
| | | if (deviceConnected && !oldDeviceConnected) { |
| | | // do stuff here on connecting |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | */ |
| | | |
| | | #include <BLEDevice.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLEScan.h> |
| | | #include <BLEAdvertisedDevice.h> |
| | | |
| | | int scanTime = 5; //In seconds |
| | | BLEScan* pBLEScan; |
| | | |
| | | class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { |
| | | void onResult(BLEAdvertisedDevice advertisedDevice) { |
| | | Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); |
| | | } |
| | | }; |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | Serial.println("Scanning..."); |
| | | |
| | | BLEDevice::init(""); |
| | | pBLEScan = BLEDevice::getScan(); //create new scan |
| | | pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); |
| | | pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster |
| | | pBLEScan->setInterval(100); |
| | | pBLEScan->setWindow(99); // less or equal setInterval value |
| | | } |
| | | |
| | | void loop() { |
| | | // put your main code here, to run repeatedly: |
| | | BLEScanResults foundDevices = pBLEScan->start(scanTime, false); |
| | | Serial.print("Devices found: "); |
| | | Serial.println(foundDevices.getCount()); |
| | | Serial.println("Scan done!"); |
| | | pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory |
| | | delay(2000); |
| | | } |
| New file |
| | |
| | | /* |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | updates by chegewara |
| | | */ |
| | | |
| | | #include <BLEDevice.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLEServer.h> |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | |
| | | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" |
| | | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | Serial.println("Starting BLE work!"); |
| | | |
| | | BLEDevice::init("Long name works now"); |
| | | BLEServer *pServer = BLEDevice::createServer(); |
| | | BLEService *pService = pServer->createService(SERVICE_UUID); |
| | | BLECharacteristic *pCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID, |
| | | BLECharacteristic::PROPERTY_READ | |
| | | BLECharacteristic::PROPERTY_WRITE |
| | | ); |
| | | |
| | | pCharacteristic->setValue("Hello World says Neil"); |
| | | pService->start(); |
| | | // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility |
| | | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); |
| | | pAdvertising->addServiceUUID(SERVICE_UUID); |
| | | pAdvertising->setScanResponse(true); |
| | | pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue |
| | | pAdvertising->setMinPreferred(0x12); |
| | | BLEDevice::startAdvertising(); |
| | | Serial.println("Characteristic defined! Now you can read it in your phone!"); |
| | | } |
| | | |
| | | void loop() { |
| | | // put your main code here, to run repeatedly: |
| | | delay(2000); |
| | | } |
| New file |
| | |
| | | /* |
| | | Video: https://www.youtube.com/watch?v=oCMOYS71NIU |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | updated by chegewara |
| | | |
| | | Create a BLE server that, once we receive a connection, will send periodic notifications. |
| | | The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b |
| | | And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 |
| | | |
| | | The design of creating the BLE server is: |
| | | 1. Create a BLE Server |
| | | 2. Create a BLE Service |
| | | 3. Create a BLE Characteristic on the Service |
| | | 4. Create a BLE Descriptor on the characteristic |
| | | 5. Start the service. |
| | | 6. Start advertising. |
| | | |
| | | A connect hander associated with the server starts a background task that performs notification |
| | | every couple of seconds. |
| | | */ |
| | | #include <BLEDevice.h> |
| | | #include <BLEServer.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLE2902.h> |
| | | |
| | | BLEServer* pServer = NULL; |
| | | BLECharacteristic* pCharacteristic = NULL; |
| | | bool deviceConnected = false; |
| | | bool oldDeviceConnected = false; |
| | | uint32_t value = 0; |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | |
| | | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" |
| | | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
| | | |
| | | |
| | | class MyServerCallbacks: public BLEServerCallbacks { |
| | | void onConnect(BLEServer* pServer) { |
| | | deviceConnected = true; |
| | | BLEDevice::startAdvertising(); |
| | | }; |
| | | |
| | | void onDisconnect(BLEServer* pServer) { |
| | | deviceConnected = false; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | |
| | | // Create the BLE Device |
| | | BLEDevice::init("ESP32"); |
| | | |
| | | // Create the BLE Server |
| | | pServer = BLEDevice::createServer(); |
| | | pServer->setCallbacks(new MyServerCallbacks()); |
| | | |
| | | // Create the BLE Service |
| | | BLEService *pService = pServer->createService(SERVICE_UUID); |
| | | |
| | | // Create a BLE Characteristic |
| | | pCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID, |
| | | BLECharacteristic::PROPERTY_READ | |
| | | BLECharacteristic::PROPERTY_WRITE | |
| | | BLECharacteristic::PROPERTY_NOTIFY | |
| | | BLECharacteristic::PROPERTY_INDICATE |
| | | ); |
| | | |
| | | // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml |
| | | // Create a BLE Descriptor |
| | | pCharacteristic->addDescriptor(new BLE2902()); |
| | | |
| | | // Start the service |
| | | pService->start(); |
| | | |
| | | // Start advertising |
| | | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); |
| | | pAdvertising->addServiceUUID(SERVICE_UUID); |
| | | pAdvertising->setScanResponse(false); |
| | | pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter |
| | | BLEDevice::startAdvertising(); |
| | | Serial.println("Waiting a client connection to notify..."); |
| | | } |
| | | |
| | | void loop() { |
| | | // notify changed value |
| | | if (deviceConnected) { |
| | | pCharacteristic->setValue((uint8_t*)&value, 4); |
| | | pCharacteristic->notify(); |
| | | value++; |
| | | delay(10); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms |
| | | } |
| | | // disconnecting |
| | | if (!deviceConnected && oldDeviceConnected) { |
| | | delay(500); // give the bluetooth stack the chance to get things ready |
| | | pServer->startAdvertising(); // restart advertising |
| | | Serial.println("start advertising"); |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | // connecting |
| | | if (deviceConnected && !oldDeviceConnected) { |
| | | // do stuff here on connecting |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | Video: https://www.youtube.com/watch?v=oCMOYS71NIU |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | |
| | | Create a BLE server that, once we receive a connection, will send periodic notifications. |
| | | The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E |
| | | Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" |
| | | Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" |
| | | |
| | | The design of creating the BLE server is: |
| | | 1. Create a BLE Server |
| | | 2. Create a BLE Service |
| | | 3. Create a BLE Characteristic on the Service |
| | | 4. Create a BLE Descriptor on the characteristic |
| | | 5. Start the service. |
| | | 6. Start advertising. |
| | | |
| | | In this example rxValue is the data received (only accessible inside that function). |
| | | And txValue is the data to be sent, in this example just a byte incremented every second. |
| | | */ |
| | | #include <BLEDevice.h> |
| | | #include <BLEServer.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLE2902.h> |
| | | |
| | | BLEServer *pServer = NULL; |
| | | BLECharacteristic * pTxCharacteristic; |
| | | bool deviceConnected = false; |
| | | bool oldDeviceConnected = false; |
| | | uint8_t txValue = 0; |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | |
| | | #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID |
| | | #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" |
| | | #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" |
| | | |
| | | |
| | | class MyServerCallbacks: public BLEServerCallbacks { |
| | | void onConnect(BLEServer* pServer) { |
| | | deviceConnected = true; |
| | | }; |
| | | |
| | | void onDisconnect(BLEServer* pServer) { |
| | | deviceConnected = false; |
| | | } |
| | | }; |
| | | |
| | | class MyCallbacks: public BLECharacteristicCallbacks { |
| | | void onWrite(BLECharacteristic *pCharacteristic) { |
| | | std::string rxValue = pCharacteristic->getValue(); |
| | | |
| | | if (rxValue.length() > 0) { |
| | | Serial.println("*********"); |
| | | Serial.print("Received Value: "); |
| | | for (int i = 0; i < rxValue.length(); i++) |
| | | Serial.print(rxValue[i]); |
| | | |
| | | Serial.println(); |
| | | Serial.println("*********"); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | |
| | | // Create the BLE Device |
| | | BLEDevice::init("UART Service"); |
| | | |
| | | // Create the BLE Server |
| | | pServer = BLEDevice::createServer(); |
| | | pServer->setCallbacks(new MyServerCallbacks()); |
| | | |
| | | // Create the BLE Service |
| | | BLEService *pService = pServer->createService(SERVICE_UUID); |
| | | |
| | | // Create a BLE Characteristic |
| | | pTxCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID_TX, |
| | | BLECharacteristic::PROPERTY_NOTIFY |
| | | ); |
| | | |
| | | pTxCharacteristic->addDescriptor(new BLE2902()); |
| | | |
| | | BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID_RX, |
| | | BLECharacteristic::PROPERTY_WRITE |
| | | ); |
| | | |
| | | pRxCharacteristic->setCallbacks(new MyCallbacks()); |
| | | |
| | | // Start the service |
| | | pService->start(); |
| | | |
| | | // Start advertising |
| | | pServer->getAdvertising()->start(); |
| | | Serial.println("Waiting a client connection to notify..."); |
| | | } |
| | | |
| | | void loop() { |
| | | |
| | | if (deviceConnected) { |
| | | pTxCharacteristic->setValue(&txValue, 1); |
| | | pTxCharacteristic->notify(); |
| | | txValue++; |
| | | delay(10); // bluetooth stack will go into congestion, if too many packets are sent |
| | | } |
| | | |
| | | // disconnecting |
| | | if (!deviceConnected && oldDeviceConnected) { |
| | | delay(500); // give the bluetooth stack the chance to get things ready |
| | | pServer->startAdvertising(); // restart advertising |
| | | Serial.println("start advertising"); |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | // connecting |
| | | if (deviceConnected && !oldDeviceConnected) { |
| | | // do stuff here on connecting |
| | | oldDeviceConnected = deviceConnected; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp |
| | | Ported to Arduino ESP32 by Evandro Copercini |
| | | */ |
| | | |
| | | #include <BLEDevice.h> |
| | | #include <BLEUtils.h> |
| | | #include <BLEServer.h> |
| | | |
| | | // See the following for generating UUIDs: |
| | | // https://www.uuidgenerator.net/ |
| | | |
| | | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" |
| | | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
| | | |
| | | |
| | | class MyCallbacks: public BLECharacteristicCallbacks { |
| | | void onWrite(BLECharacteristic *pCharacteristic) { |
| | | std::string value = pCharacteristic->getValue(); |
| | | |
| | | if (value.length() > 0) { |
| | | Serial.println("*********"); |
| | | Serial.print("New value: "); |
| | | for (int i = 0; i < value.length(); i++) |
| | | Serial.print(value[i]); |
| | | |
| | | Serial.println(); |
| | | Serial.println("*********"); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | void setup() { |
| | | Serial.begin(115200); |
| | | |
| | | Serial.println("1- Download and install an BLE scanner app in your phone"); |
| | | Serial.println("2- Scan for BLE devices in the app"); |
| | | Serial.println("3- Connect to MyESP32"); |
| | | Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); |
| | | Serial.println("5- See the magic =)"); |
| | | |
| | | BLEDevice::init("MyESP32"); |
| | | BLEServer *pServer = BLEDevice::createServer(); |
| | | |
| | | BLEService *pService = pServer->createService(SERVICE_UUID); |
| | | |
| | | BLECharacteristic *pCharacteristic = pService->createCharacteristic( |
| | | CHARACTERISTIC_UUID, |
| | | BLECharacteristic::PROPERTY_READ | |
| | | BLECharacteristic::PROPERTY_WRITE |
| | | ); |
| | | |
| | | pCharacteristic->setCallbacks(new MyCallbacks()); |
| | | |
| | | pCharacteristic->setValue("Hello World"); |
| | | pService->start(); |
| | | |
| | | BLEAdvertising *pAdvertising = pServer->getAdvertising(); |
| | | pAdvertising->start(); |
| | | } |
| | | |
| | | void loop() { |
| | | // put your main code here, to run repeatedly: |
| | | delay(2000); |
| | | } |
| New file |
| | |
| | | name=ESP32 BLE Arduino |
| | | version=1.0.1 |
| | | author=Neil Kolban <kolban1@kolban.com> |
| | | maintainer=Dariusz Krempa <esp32@esp32.eu.org> |
| | | sentence=BLE functions for ESP32 |
| | | paragraph=This library provides an implementation Bluetooth Low Energy support for the ESP32 using the Arduino platform. |
| | | category=Communication |
| | | url=https://github.com/nkolban/ESP32_BLE_Arduino |
| | | architectures=esp32 |
| | | includes=BLEDevice.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h |
| New file |
| | |
| | | /* |
| | | * BLE2902.cpp |
| | | * |
| | | * Created on: Jun 25, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | /* |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | |
| | | #include "BLE2902.h" |
| | | |
| | | BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902)) { |
| | | uint8_t data[2] = { 0, 0 }; |
| | | setValue(data, 2); |
| | | } // BLE2902 |
| | | |
| | | |
| | | /** |
| | | * @brief Get the notifications value. |
| | | * @return The notifications value. True if notifications are enabled and false if not. |
| | | */ |
| | | bool BLE2902::getNotifications() { |
| | | return (getValue()[0] & (1 << 0)) != 0; |
| | | } // getNotifications |
| | | |
| | | |
| | | /** |
| | | * @brief Get the indications value. |
| | | * @return The indications value. True if indications are enabled and false if not. |
| | | */ |
| | | bool BLE2902::getIndications() { |
| | | return (getValue()[0] & (1 << 1)) != 0; |
| | | } // getIndications |
| | | |
| | | |
| | | /** |
| | | * @brief Set the indications flag. |
| | | * @param [in] flag The indications flag. |
| | | */ |
| | | void BLE2902::setIndications(bool flag) { |
| | | uint8_t *pValue = getValue(); |
| | | if (flag) pValue[0] |= 1 << 1; |
| | | else pValue[0] &= ~(1 << 1); |
| | | } // setIndications |
| | | |
| | | |
| | | /** |
| | | * @brief Set the notifications flag. |
| | | * @param [in] flag The notifications flag. |
| | | */ |
| | | void BLE2902::setNotifications(bool flag) { |
| | | uint8_t *pValue = getValue(); |
| | | if (flag) pValue[0] |= 1 << 0; |
| | | else pValue[0] &= ~(1 << 0); |
| | | } // setNotifications |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | * BLE2902.h |
| | | * |
| | | * Created on: Jun 25, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLE2902_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLE2902_H_ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | |
| | | #include "BLEDescriptor.h" |
| | | |
| | | /** |
| | | * @brief Descriptor for Client Characteristic Configuration. |
| | | * |
| | | * This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902. |
| | | * |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml |
| | | */ |
| | | class BLE2902: public BLEDescriptor { |
| | | public: |
| | | BLE2902(); |
| | | bool getNotifications(); |
| | | bool getIndications(); |
| | | void setNotifications(bool flag); |
| | | void setIndications(bool flag); |
| | | |
| | | }; // BLE2902 |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | #endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLE2904.cpp |
| | | * |
| | | * Created on: Dec 23, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | /* |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | |
| | | #include "BLE2904.h" |
| | | |
| | | |
| | | BLE2904::BLE2904() : BLEDescriptor(BLEUUID((uint16_t) 0x2904)) { |
| | | m_data.m_format = 0; |
| | | m_data.m_exponent = 0; |
| | | m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers |
| | | m_data.m_unit = 0; |
| | | m_data.m_description = 0; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } // BLE2902 |
| | | |
| | | |
| | | /** |
| | | * @brief Set the description. |
| | | */ |
| | | void BLE2904::setDescription(uint16_t description) { |
| | | m_data.m_description = description; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @brief Set the exponent. |
| | | */ |
| | | void BLE2904::setExponent(int8_t exponent) { |
| | | m_data.m_exponent = exponent; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } // setExponent |
| | | |
| | | |
| | | /** |
| | | * @brief Set the format. |
| | | */ |
| | | void BLE2904::setFormat(uint8_t format) { |
| | | m_data.m_format = format; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } // setFormat |
| | | |
| | | |
| | | /** |
| | | * @brief Set the namespace. |
| | | */ |
| | | void BLE2904::setNamespace(uint8_t namespace_value) { |
| | | m_data.m_namespace = namespace_value; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } // setNamespace |
| | | |
| | | |
| | | /** |
| | | * @brief Set the units for this value. It should be one of the encoded values defined here: |
| | | * https://www.bluetooth.com/specifications/assigned-numbers/units |
| | | * @param [in] unit The type of units of this characteristic as defined by assigned numbers. |
| | | */ |
| | | void BLE2904::setUnit(uint16_t unit) { |
| | | m_data.m_unit = unit; |
| | | setValue((uint8_t*) &m_data, sizeof(m_data)); |
| | | } // setUnit |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | * BLE2904.h |
| | | * |
| | | * Created on: Dec 23, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLE2904_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLE2904_H_ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | |
| | | #include "BLEDescriptor.h" |
| | | |
| | | struct BLE2904_Data { |
| | | uint8_t m_format; |
| | | int8_t m_exponent; |
| | | uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units |
| | | uint8_t m_namespace; |
| | | uint16_t m_description; |
| | | |
| | | } __attribute__((packed)); |
| | | |
| | | /** |
| | | * @brief Descriptor for Characteristic Presentation Format. |
| | | * |
| | | * This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904. |
| | | * |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml |
| | | */ |
| | | class BLE2904: public BLEDescriptor { |
| | | public: |
| | | BLE2904(); |
| | | static const uint8_t FORMAT_BOOLEAN = 1; |
| | | static const uint8_t FORMAT_UINT2 = 2; |
| | | static const uint8_t FORMAT_UINT4 = 3; |
| | | static const uint8_t FORMAT_UINT8 = 4; |
| | | static const uint8_t FORMAT_UINT12 = 5; |
| | | static const uint8_t FORMAT_UINT16 = 6; |
| | | static const uint8_t FORMAT_UINT24 = 7; |
| | | static const uint8_t FORMAT_UINT32 = 8; |
| | | static const uint8_t FORMAT_UINT48 = 9; |
| | | static const uint8_t FORMAT_UINT64 = 10; |
| | | static const uint8_t FORMAT_UINT128 = 11; |
| | | static const uint8_t FORMAT_SINT8 = 12; |
| | | static const uint8_t FORMAT_SINT12 = 13; |
| | | static const uint8_t FORMAT_SINT16 = 14; |
| | | static const uint8_t FORMAT_SINT24 = 15; |
| | | static const uint8_t FORMAT_SINT32 = 16; |
| | | static const uint8_t FORMAT_SINT48 = 17; |
| | | static const uint8_t FORMAT_SINT64 = 18; |
| | | static const uint8_t FORMAT_SINT128 = 19; |
| | | static const uint8_t FORMAT_FLOAT32 = 20; |
| | | static const uint8_t FORMAT_FLOAT64 = 21; |
| | | static const uint8_t FORMAT_SFLOAT16 = 22; |
| | | static const uint8_t FORMAT_SFLOAT32 = 23; |
| | | static const uint8_t FORMAT_IEEE20601 = 24; |
| | | static const uint8_t FORMAT_UTF8 = 25; |
| | | static const uint8_t FORMAT_UTF16 = 26; |
| | | static const uint8_t FORMAT_OPAQUE = 27; |
| | | |
| | | void setDescription(uint16_t); |
| | | void setExponent(int8_t exponent); |
| | | void setFormat(uint8_t format); |
| | | void setNamespace(uint8_t namespace_value); |
| | | void setUnit(uint16_t unit); |
| | | |
| | | private: |
| | | BLE2904_Data m_data; |
| | | }; // BLE2904 |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | #endif /* COMPONENTS_CPP_UTILS_BLE2904_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLEAddress.cpp |
| | | * |
| | | * Created on: Jul 2, 2017 |
| | | * Author: kolban |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | |
| | | #include "BLEAddress.h" |
| | | #include <string> |
| | | #include <sstream> |
| | | #include <iomanip> |
| | | #include <string.h> |
| | | #include <stdio.h> |
| | | #ifdef ARDUINO_ARCH_ESP32 |
| | | #include "esp32-hal-log.h" |
| | | #endif |
| | | |
| | | |
| | | /** |
| | | * @brief Create an address from the native ESP32 representation. |
| | | * @param [in] address The native representation. |
| | | */ |
| | | BLEAddress::BLEAddress(esp_bd_addr_t address) { |
| | | memcpy(m_address, address, ESP_BD_ADDR_LEN); |
| | | } // BLEAddress |
| | | |
| | | |
| | | /** |
| | | * @brief Create an address from a hex string |
| | | * |
| | | * A hex string is of the format: |
| | | * ``` |
| | | * 00:00:00:00:00:00 |
| | | * ``` |
| | | * which is 17 characters in length. |
| | | * |
| | | * @param [in] stringAddress The hex representation of the address. |
| | | */ |
| | | BLEAddress::BLEAddress(std::string stringAddress) { |
| | | if (stringAddress.length() != 17) return; |
| | | |
| | | int data[6]; |
| | | sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); |
| | | m_address[0] = (uint8_t) data[0]; |
| | | m_address[1] = (uint8_t) data[1]; |
| | | m_address[2] = (uint8_t) data[2]; |
| | | m_address[3] = (uint8_t) data[3]; |
| | | m_address[4] = (uint8_t) data[4]; |
| | | m_address[5] = (uint8_t) data[5]; |
| | | } // BLEAddress |
| | | |
| | | |
| | | /** |
| | | * @brief Determine if this address equals another. |
| | | * @param [in] otherAddress The other address to compare against. |
| | | * @return True if the addresses are equal. |
| | | */ |
| | | bool BLEAddress::equals(BLEAddress otherAddress) { |
| | | return memcmp(otherAddress.getNative(), m_address, 6) == 0; |
| | | } // equals |
| | | |
| | | |
| | | /** |
| | | * @brief Return the native representation of the address. |
| | | * @return The native representation of the address. |
| | | */ |
| | | esp_bd_addr_t *BLEAddress::getNative() { |
| | | return &m_address; |
| | | } // getNative |
| | | |
| | | |
| | | /** |
| | | * @brief Convert a BLE address to a string. |
| | | * |
| | | * A string representation of an address is in the format: |
| | | * |
| | | * ``` |
| | | * xx:xx:xx:xx:xx:xx |
| | | * ``` |
| | | * |
| | | * @return The string representation of the address. |
| | | */ |
| | | std::string BLEAddress::toString() { |
| | | std::stringstream stream; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[0] << ':'; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[1] << ':'; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[2] << ':'; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[3] << ':'; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[4] << ':'; |
| | | stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[5]; |
| | | return stream.str(); |
| | | } // toString |
| | | #endif |
| New file |
| | |
| | | /* |
| | | * BLEAddress.h |
| | | * |
| | | * Created on: Jul 2, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLEADDRESS_H_ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <esp_gap_ble_api.h> // ESP32 BLE |
| | | #include <string> |
| | | |
| | | |
| | | /** |
| | | * @brief A %BLE device address. |
| | | * |
| | | * Every %BLE device has a unique address which can be used to identify it and form connections. |
| | | */ |
| | | class BLEAddress { |
| | | public: |
| | | BLEAddress(esp_bd_addr_t address); |
| | | BLEAddress(std::string stringAddress); |
| | | bool equals(BLEAddress otherAddress); |
| | | esp_bd_addr_t* getNative(); |
| | | std::string toString(); |
| | | |
| | | private: |
| | | esp_bd_addr_t m_address; |
| | | }; |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | #endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLEAdvertisedDevice.cpp |
| | | * |
| | | * During the scanning procedure, we will be finding advertised BLE devices. This class |
| | | * models a found device. |
| | | * |
| | | * |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile |
| | | * |
| | | * Created on: Jul 3, 2017 |
| | | * Author: kolban |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <sstream> |
| | | #include "BLEAdvertisedDevice.h" |
| | | #include "BLEUtils.h" |
| | | #include "esp32-hal-log.h" |
| | | |
| | | BLEAdvertisedDevice::BLEAdvertisedDevice() { |
| | | m_adFlag = 0; |
| | | m_appearance = 0; |
| | | m_deviceType = 0; |
| | | m_manufacturerData = ""; |
| | | m_name = ""; |
| | | m_rssi = -9999; |
| | | m_serviceData = ""; |
| | | m_txPower = 0; |
| | | m_pScan = nullptr; |
| | | |
| | | m_haveAppearance = false; |
| | | m_haveManufacturerData = false; |
| | | m_haveName = false; |
| | | m_haveRSSI = false; |
| | | m_haveServiceData = false; |
| | | m_haveServiceUUID = false; |
| | | m_haveTXPower = false; |
| | | |
| | | } // BLEAdvertisedDevice |
| | | |
| | | |
| | | /** |
| | | * @brief Get the address. |
| | | * |
| | | * Every %BLE device exposes an address that is used to identify it and subsequently connect to it. |
| | | * Call this function to obtain the address of the advertised device. |
| | | * |
| | | * @return The address of the advertised device. |
| | | */ |
| | | BLEAddress BLEAdvertisedDevice::getAddress() { |
| | | return m_address; |
| | | } // getAddress |
| | | |
| | | |
| | | /** |
| | | * @brief Get the appearance. |
| | | * |
| | | * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user |
| | | * typcially in the form of an icon. |
| | | * |
| | | * @return The appearance of the advertised device. |
| | | */ |
| | | uint16_t BLEAdvertisedDevice::getAppearance() { |
| | | return m_appearance; |
| | | } // getAppearance |
| | | |
| | | |
| | | /** |
| | | * @brief Get the manufacturer data. |
| | | * @return The manufacturer data of the advertised device. |
| | | */ |
| | | std::string BLEAdvertisedDevice::getManufacturerData() { |
| | | return m_manufacturerData; |
| | | } // getManufacturerData |
| | | |
| | | |
| | | /** |
| | | * @brief Get the name. |
| | | * @return The name of the advertised device. |
| | | */ |
| | | std::string BLEAdvertisedDevice::getName() { |
| | | return m_name; |
| | | } // getName |
| | | |
| | | |
| | | /** |
| | | * @brief Get the RSSI. |
| | | * @return The RSSI of the advertised device. |
| | | */ |
| | | int BLEAdvertisedDevice::getRSSI() { |
| | | return m_rssi; |
| | | } // getRSSI |
| | | |
| | | |
| | | /** |
| | | * @brief Get the scan object that created this advertisement. |
| | | * @return The scan object. |
| | | */ |
| | | BLEScan* BLEAdvertisedDevice::getScan() { |
| | | return m_pScan; |
| | | } // getScan |
| | | |
| | | |
| | | /** |
| | | * @brief Get the service data. |
| | | * @return The ServiceData of the advertised device. |
| | | */ |
| | | std::string BLEAdvertisedDevice::getServiceData() { |
| | | return m_serviceData; |
| | | } //getServiceData |
| | | |
| | | |
| | | /** |
| | | * @brief Get the service data UUID. |
| | | * @return The service data UUID. |
| | | */ |
| | | BLEUUID BLEAdvertisedDevice::getServiceDataUUID() { |
| | | return m_serviceDataUUID; |
| | | } // getServiceDataUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Get the Service UUID. |
| | | * @return The Service UUID of the advertised device. |
| | | */ |
| | | BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is no longer useful |
| | | return m_serviceUUIDs[0]; |
| | | } // getServiceUUID |
| | | |
| | | /** |
| | | * @brief Check advertised serviced for existence required UUID |
| | | * @return Return true if service is advertised |
| | | */ |
| | | bool BLEAdvertisedDevice::isAdvertisingService(BLEUUID uuid){ |
| | | for (int i = 0; i < m_serviceUUIDs.size(); i++) { |
| | | if (m_serviceUUIDs[i].equals(uuid)) return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * @brief Get the TX Power. |
| | | * @return The TX Power of the advertised device. |
| | | */ |
| | | int8_t BLEAdvertisedDevice::getTXPower() { |
| | | return m_txPower; |
| | | } // getTXPower |
| | | |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have an appearance value? |
| | | * @return True if there is an appearance value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveAppearance() { |
| | | return m_haveAppearance; |
| | | } // haveAppearance |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have manufacturer data? |
| | | * @return True if there is manufacturer data present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveManufacturerData() { |
| | | return m_haveManufacturerData; |
| | | } // haveManufacturerData |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have a name value? |
| | | * @return True if there is a name value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveName() { |
| | | return m_haveName; |
| | | } // haveName |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have a signal strength value? |
| | | * @return True if there is a signal strength value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveRSSI() { |
| | | return m_haveRSSI; |
| | | } // haveRSSI |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have a service data value? |
| | | * @return True if there is a service data value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveServiceData() { |
| | | return m_haveServiceData; |
| | | } // haveServiceData |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have a service UUID value? |
| | | * @return True if there is a service UUID value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveServiceUUID() { |
| | | return m_haveServiceUUID; |
| | | } // haveServiceUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Does this advertisement have a transmission power value? |
| | | * @return True if there is a transmission power value present. |
| | | */ |
| | | bool BLEAdvertisedDevice::haveTXPower() { |
| | | return m_haveTXPower; |
| | | } // haveTXPower |
| | | |
| | | |
| | | /** |
| | | * @brief Parse the advertising pay load. |
| | | * |
| | | * The pay load is a buffer of bytes that is either 31 bytes long or terminated by |
| | | * a 0 length value. Each entry in the buffer has the format: |
| | | * [length][type][data...] |
| | | * |
| | | * The length does not include itself but does include everything after it until the next record. A record |
| | | * with a length value of 0 indicates a terminator. |
| | | * |
| | | * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile |
| | | */ |
| | | void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len) { |
| | | uint8_t length; |
| | | uint8_t ad_type; |
| | | uint8_t sizeConsumed = 0; |
| | | bool finished = false; |
| | | m_payload = payload; |
| | | m_payloadLength = total_len; |
| | | |
| | | while(!finished) { |
| | | length = *payload; // Retrieve the length of the record. |
| | | payload++; // Skip to type |
| | | sizeConsumed += 1 + length; // increase the size consumed. |
| | | |
| | | if (length != 0) { // A length of 0 indicates that we have reached the end. |
| | | ad_type = *payload; |
| | | payload++; |
| | | length--; |
| | | |
| | | char* pHex = BLEUtils::buildHexData(nullptr, payload, length); |
| | | log_d("Type: 0x%.2x (%s), length: %d, data: %s", |
| | | ad_type, BLEUtils::advTypeToString(ad_type), length, pHex); |
| | | free(pHex); |
| | | |
| | | switch(ad_type) { |
| | | case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09 |
| | | setName(std::string(reinterpret_cast<char*>(payload), length)); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_NAME_CMPL |
| | | |
| | | case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A |
| | | setTXPower(*payload); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_TX_PWR |
| | | |
| | | case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19 |
| | | setAppearance(*reinterpret_cast<uint16_t*>(payload)); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_APPEARANCE |
| | | |
| | | case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01 |
| | | setAdFlag(*payload); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_FLAG |
| | | |
| | | case ESP_BLE_AD_TYPE_16SRV_CMPL: |
| | | case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02 |
| | | for (int var = 0; var < length/2; ++var) { |
| | | setServiceUUID(BLEUUID(*reinterpret_cast<uint16_t*>(payload + var * 2))); |
| | | } |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_16SRV_PART |
| | | |
| | | case ESP_BLE_AD_TYPE_32SRV_CMPL: |
| | | case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04 |
| | | for (int var = 0; var < length/4; ++var) { |
| | | setServiceUUID(BLEUUID(*reinterpret_cast<uint32_t*>(payload + var * 4))); |
| | | } |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_32SRV_PART |
| | | |
| | | case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07 |
| | | setServiceUUID(BLEUUID(payload, 16, false)); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_128SRV_CMPL |
| | | |
| | | case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06 |
| | | setServiceUUID(BLEUUID(payload, 16, false)); |
| | | break; |
| | | } // ESP_BLE_AD_TYPE_128SRV_PART |
| | | |
| | | // See CSS Part A 1.4 Manufacturer Specific Data |
| | | case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: { |
| | | setManufacturerData(std::string(reinterpret_cast<char*>(payload), length)); |
| | | break; |
| | | } // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE |
| | | |
| | | case ESP_BLE_AD_TYPE_SERVICE_DATA: { // Adv Data Type: 0x16 (Service Data) - 2 byte UUID |
| | | if (length < 2) { |
| | | log_e("Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA"); |
| | | break; |
| | | } |
| | | uint16_t uuid = *(uint16_t*)payload; |
| | | setServiceDataUUID(BLEUUID(uuid)); |
| | | if (length > 2) { |
| | | setServiceData(std::string(reinterpret_cast<char*>(payload + 2), length - 2)); |
| | | } |
| | | break; |
| | | } //ESP_BLE_AD_TYPE_SERVICE_DATA |
| | | |
| | | case ESP_BLE_AD_TYPE_32SERVICE_DATA: { // Adv Data Type: 0x20 (Service Data) - 4 byte UUID |
| | | if (length < 4) { |
| | | log_e("Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA"); |
| | | break; |
| | | } |
| | | uint32_t uuid = *(uint32_t*) payload; |
| | | setServiceDataUUID(BLEUUID(uuid)); |
| | | if (length > 4) { |
| | | setServiceData(std::string(reinterpret_cast<char*>(payload + 4), length - 4)); |
| | | } |
| | | break; |
| | | } //ESP_BLE_AD_TYPE_32SERVICE_DATA |
| | | |
| | | case ESP_BLE_AD_TYPE_128SERVICE_DATA: { // Adv Data Type: 0x21 (Service Data) - 16 byte UUID |
| | | if (length < 16) { |
| | | log_e("Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA"); |
| | | break; |
| | | } |
| | | |
| | | setServiceDataUUID(BLEUUID(payload, (size_t)16, false)); |
| | | if (length > 16) { |
| | | setServiceData(std::string(reinterpret_cast<char*>(payload + 16), length - 16)); |
| | | } |
| | | break; |
| | | } //ESP_BLE_AD_TYPE_32SERVICE_DATA |
| | | |
| | | default: { |
| | | log_d("Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type); |
| | | break; |
| | | } |
| | | } // switch |
| | | payload += length; |
| | | } // Length <> 0 |
| | | |
| | | |
| | | if (sizeConsumed >= total_len) |
| | | finished = true; |
| | | |
| | | } // !finished |
| | | } // parseAdvertisement |
| | | |
| | | |
| | | /** |
| | | * @brief Set the address of the advertised device. |
| | | * @param [in] address The address of the advertised device. |
| | | */ |
| | | void BLEAdvertisedDevice::setAddress(BLEAddress address) { |
| | | m_address = address; |
| | | } // setAddress |
| | | |
| | | |
| | | /** |
| | | * @brief Set the adFlag for this device. |
| | | * @param [in] The discovered adFlag. |
| | | */ |
| | | void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) { |
| | | m_adFlag = adFlag; |
| | | } // setAdFlag |
| | | |
| | | |
| | | /** |
| | | * @brief Set the appearance for this device. |
| | | * @param [in] The discovered appearance. |
| | | */ |
| | | void BLEAdvertisedDevice::setAppearance(uint16_t appearance) { |
| | | m_appearance = appearance; |
| | | m_haveAppearance = true; |
| | | log_d("- appearance: %d", m_appearance); |
| | | } // setAppearance |
| | | |
| | | |
| | | /** |
| | | * @brief Set the manufacturer data for this device. |
| | | * @param [in] The discovered manufacturer data. |
| | | */ |
| | | void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) { |
| | | m_manufacturerData = manufacturerData; |
| | | m_haveManufacturerData = true; |
| | | char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*) m_manufacturerData.data(), (uint8_t) m_manufacturerData.length()); |
| | | log_d("- manufacturer data: %s", pHex); |
| | | free(pHex); |
| | | } // setManufacturerData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the name for this device. |
| | | * @param [in] name The discovered name. |
| | | */ |
| | | void BLEAdvertisedDevice::setName(std::string name) { |
| | | m_name = name; |
| | | m_haveName = true; |
| | | log_d("- setName(): name: %s", m_name.c_str()); |
| | | } // setName |
| | | |
| | | |
| | | /** |
| | | * @brief Set the RSSI for this device. |
| | | * @param [in] rssi The discovered RSSI. |
| | | */ |
| | | void BLEAdvertisedDevice::setRSSI(int rssi) { |
| | | m_rssi = rssi; |
| | | m_haveRSSI = true; |
| | | log_d("- setRSSI(): rssi: %d", m_rssi); |
| | | } // setRSSI |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Scan that created this advertised device. |
| | | * @param pScan The Scan that created this advertised device. |
| | | */ |
| | | void BLEAdvertisedDevice::setScan(BLEScan* pScan) { |
| | | m_pScan = pScan; |
| | | } // setScan |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Service UUID for this device. |
| | | * @param [in] serviceUUID The discovered serviceUUID |
| | | */ |
| | | void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { |
| | | return setServiceUUID(BLEUUID(serviceUUID)); |
| | | } // setServiceUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Service UUID for this device. |
| | | * @param [in] serviceUUID The discovered serviceUUID |
| | | */ |
| | | void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) { |
| | | m_serviceUUIDs.push_back(serviceUUID); |
| | | m_haveServiceUUID = true; |
| | | log_d("- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str()); |
| | | } // setServiceUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Set the ServiceData value. |
| | | * @param [in] data ServiceData value. |
| | | */ |
| | | void BLEAdvertisedDevice::setServiceData(std::string serviceData) { |
| | | m_haveServiceData = true; // Set the flag that indicates we have service data. |
| | | m_serviceData = serviceData; // Save the service data that we received. |
| | | } //setServiceData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the ServiceDataUUID value. |
| | | * @param [in] data ServiceDataUUID value. |
| | | */ |
| | | void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) { |
| | | m_haveServiceData = true; // Set the flag that indicates we have service data. |
| | | m_serviceDataUUID = uuid; |
| | | } // setServiceDataUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Set the power level for this device. |
| | | * @param [in] txPower The discovered power level. |
| | | */ |
| | | void BLEAdvertisedDevice::setTXPower(int8_t txPower) { |
| | | m_txPower = txPower; |
| | | m_haveTXPower = true; |
| | | log_d("- txPower: %d", m_txPower); |
| | | } // setTXPower |
| | | |
| | | |
| | | /** |
| | | * @brief Create a string representation of this device. |
| | | * @return A string representation of this device. |
| | | */ |
| | | std::string BLEAdvertisedDevice::toString() { |
| | | std::stringstream ss; |
| | | ss << "Name: " << getName() << ", Address: " << getAddress().toString(); |
| | | if (haveAppearance()) { |
| | | ss << ", appearance: " << getAppearance(); |
| | | } |
| | | if (haveManufacturerData()) { |
| | | char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length()); |
| | | ss << ", manufacturer data: " << pHex; |
| | | free(pHex); |
| | | } |
| | | if (haveServiceUUID()) { |
| | | ss << ", serviceUUID: " << getServiceUUID().toString(); |
| | | } |
| | | if (haveTXPower()) { |
| | | ss << ", txPower: " << (int)getTXPower(); |
| | | } |
| | | return ss.str(); |
| | | } // toString |
| | | |
| | | uint8_t* BLEAdvertisedDevice::getPayload() { |
| | | return m_payload; |
| | | } |
| | | |
| | | esp_ble_addr_type_t BLEAdvertisedDevice::getAddressType() { |
| | | return m_addressType; |
| | | } |
| | | |
| | | void BLEAdvertisedDevice::setAddressType(esp_ble_addr_type_t type) { |
| | | m_addressType = type; |
| | | } |
| | | |
| | | size_t BLEAdvertisedDevice::getPayloadLength() { |
| | | return m_payloadLength; |
| | | } |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | |
| New file |
| | |
| | | /* |
| | | * BLEAdvertisedDevice.h |
| | | * |
| | | * Created on: Jul 3, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <esp_gattc_api.h> |
| | | |
| | | #include <map> |
| | | |
| | | #include "BLEAddress.h" |
| | | #include "BLEScan.h" |
| | | #include "BLEUUID.h" |
| | | |
| | | |
| | | class BLEScan; |
| | | /** |
| | | * @brief A representation of a %BLE advertised device found by a scan. |
| | | * |
| | | * When we perform a %BLE scan, the result will be a set of devices that are advertising. This |
| | | * class provides a model of a detected device. |
| | | */ |
| | | class BLEAdvertisedDevice { |
| | | public: |
| | | BLEAdvertisedDevice(); |
| | | |
| | | BLEAddress getAddress(); |
| | | uint16_t getAppearance(); |
| | | std::string getManufacturerData(); |
| | | std::string getName(); |
| | | int getRSSI(); |
| | | BLEScan* getScan(); |
| | | std::string getServiceData(); |
| | | BLEUUID getServiceDataUUID(); |
| | | BLEUUID getServiceUUID(); |
| | | int8_t getTXPower(); |
| | | uint8_t* getPayload(); |
| | | size_t getPayloadLength(); |
| | | esp_ble_addr_type_t getAddressType(); |
| | | void setAddressType(esp_ble_addr_type_t type); |
| | | |
| | | |
| | | bool isAdvertisingService(BLEUUID uuid); |
| | | bool haveAppearance(); |
| | | bool haveManufacturerData(); |
| | | bool haveName(); |
| | | bool haveRSSI(); |
| | | bool haveServiceData(); |
| | | bool haveServiceUUID(); |
| | | bool haveTXPower(); |
| | | |
| | | std::string toString(); |
| | | |
| | | private: |
| | | friend class BLEScan; |
| | | |
| | | void parseAdvertisement(uint8_t* payload, size_t total_len=62); |
| | | void setAddress(BLEAddress address); |
| | | void setAdFlag(uint8_t adFlag); |
| | | void setAdvertizementResult(uint8_t* payload); |
| | | void setAppearance(uint16_t appearance); |
| | | void setManufacturerData(std::string manufacturerData); |
| | | void setName(std::string name); |
| | | void setRSSI(int rssi); |
| | | void setScan(BLEScan* pScan); |
| | | void setServiceData(std::string data); |
| | | void setServiceDataUUID(BLEUUID uuid); |
| | | void setServiceUUID(const char* serviceUUID); |
| | | void setServiceUUID(BLEUUID serviceUUID); |
| | | void setTXPower(int8_t txPower); |
| | | |
| | | bool m_haveAppearance; |
| | | bool m_haveManufacturerData; |
| | | bool m_haveName; |
| | | bool m_haveRSSI; |
| | | bool m_haveServiceData; |
| | | bool m_haveServiceUUID; |
| | | bool m_haveTXPower; |
| | | |
| | | |
| | | BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); |
| | | uint8_t m_adFlag; |
| | | uint16_t m_appearance; |
| | | int m_deviceType; |
| | | std::string m_manufacturerData; |
| | | std::string m_name; |
| | | BLEScan* m_pScan; |
| | | int m_rssi; |
| | | std::vector<BLEUUID> m_serviceUUIDs; |
| | | int8_t m_txPower; |
| | | std::string m_serviceData; |
| | | BLEUUID m_serviceDataUUID; |
| | | uint8_t* m_payload; |
| | | size_t m_payloadLength = 0; |
| | | esp_ble_addr_type_t m_addressType; |
| | | }; |
| | | |
| | | /** |
| | | * @brief A callback handler for callbacks associated device scanning. |
| | | * |
| | | * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising |
| | | * has been found. This class can be sub-classed and registered such that when a scan is performed and |
| | | * a new advertised device has been found, we will be called back to be notified. |
| | | */ |
| | | class BLEAdvertisedDeviceCallbacks { |
| | | public: |
| | | virtual ~BLEAdvertisedDeviceCallbacks() {} |
| | | /** |
| | | * @brief Called when a new scan result is detected. |
| | | * |
| | | * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the |
| | | * device that was found. During any individual scan, a device will only be detected one time. |
| | | */ |
| | | virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; |
| | | }; |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLEAdvertising.cpp |
| | | * |
| | | * This class encapsulates advertising a BLE Server. |
| | | * Created on: Jun 21, 2017 |
| | | * Author: kolban |
| | | * |
| | | * The ESP-IDF provides a framework for BLE advertising. It has determined that there are a common set |
| | | * of properties that are advertised and has built a data structure that can be populated by the programmer. |
| | | * This means that the programmer doesn't have to "mess with" the low level construction of a low level |
| | | * BLE advertising frame. Many of the fields are determined for us while others we can set before starting |
| | | * to advertise. |
| | | * |
| | | * Should we wish to construct our own payload, we can use the BLEAdvertisementData class and call the setters |
| | | * upon it. Once it is populated, we can then associate it with the advertising and what ever the programmer |
| | | * set in the data will be advertised. |
| | | * |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include "BLEAdvertising.h" |
| | | #include <esp_err.h> |
| | | #include "BLEUtils.h" |
| | | #include "GeneralUtils.h" |
| | | #include "esp32-hal-log.h" |
| | | |
| | | /** |
| | | * @brief Construct a default advertising object. |
| | | * |
| | | */ |
| | | BLEAdvertising::BLEAdvertising() { |
| | | m_advData.set_scan_rsp = false; |
| | | m_advData.include_name = true; |
| | | m_advData.include_txpower = true; |
| | | m_advData.min_interval = 0x20; |
| | | m_advData.max_interval = 0x40; |
| | | m_advData.appearance = 0x00; |
| | | m_advData.manufacturer_len = 0; |
| | | m_advData.p_manufacturer_data = nullptr; |
| | | m_advData.service_data_len = 0; |
| | | m_advData.p_service_data = nullptr; |
| | | m_advData.service_uuid_len = 0; |
| | | m_advData.p_service_uuid = nullptr; |
| | | m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); |
| | | |
| | | m_advParams.adv_int_min = 0x20; |
| | | m_advParams.adv_int_max = 0x40; |
| | | m_advParams.adv_type = ADV_TYPE_IND; |
| | | m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC; |
| | | m_advParams.channel_map = ADV_CHNL_ALL; |
| | | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; |
| | | m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; |
| | | |
| | | m_customAdvData = false; // No custom advertising data |
| | | m_customScanResponseData = false; // No custom scan response data |
| | | } // BLEAdvertising |
| | | |
| | | |
| | | /** |
| | | * @brief Add a service uuid to exposed list of services. |
| | | * @param [in] serviceUUID The UUID of the service to expose. |
| | | */ |
| | | void BLEAdvertising::addServiceUUID(BLEUUID serviceUUID) { |
| | | m_serviceUUIDs.push_back(serviceUUID); |
| | | } // addServiceUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Add a service uuid to exposed list of services. |
| | | * @param [in] serviceUUID The string representation of the service to expose. |
| | | */ |
| | | void BLEAdvertising::addServiceUUID(const char* serviceUUID) { |
| | | addServiceUUID(BLEUUID(serviceUUID)); |
| | | } // addServiceUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Set the device appearance in the advertising data. |
| | | * The appearance attribute is of type 0x19. The codes for distinct appearances can be found here: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. |
| | | * @param [in] appearance The appearance of the device in the advertising data. |
| | | * @return N/A. |
| | | */ |
| | | void BLEAdvertising::setAppearance(uint16_t appearance) { |
| | | m_advData.appearance = appearance; |
| | | } // setAppearance |
| | | |
| | | void BLEAdvertising::setMinInterval(uint16_t mininterval) { |
| | | m_advParams.adv_int_min = mininterval; |
| | | } // setMinInterval |
| | | |
| | | void BLEAdvertising::setMaxInterval(uint16_t maxinterval) { |
| | | m_advParams.adv_int_max = maxinterval; |
| | | } // setMaxInterval |
| | | |
| | | void BLEAdvertising::setMinPreferred(uint16_t mininterval) { |
| | | m_advData.min_interval = mininterval; |
| | | } // |
| | | |
| | | void BLEAdvertising::setMaxPreferred(uint16_t maxinterval) { |
| | | m_advData.max_interval = maxinterval; |
| | | } // |
| | | |
| | | void BLEAdvertising::setScanResponse(bool set) { |
| | | m_scanResp = set; |
| | | } |
| | | |
| | | /** |
| | | * @brief Set the filtering for the scan filter. |
| | | * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list. |
| | | * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list. |
| | | */ |
| | | void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { |
| | | log_v(">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly); |
| | | if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { |
| | | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; |
| | | log_v("<< setScanFilter"); |
| | | return; |
| | | } |
| | | if (scanRequestWhitelistOnly && !connectWhitelistOnly) { |
| | | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY; |
| | | log_v("<< setScanFilter"); |
| | | return; |
| | | } |
| | | if (!scanRequestWhitelistOnly && connectWhitelistOnly) { |
| | | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST; |
| | | log_v("<< setScanFilter"); |
| | | return; |
| | | } |
| | | if (scanRequestWhitelistOnly && connectWhitelistOnly) { |
| | | m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST; |
| | | log_v("<< setScanFilter"); |
| | | return; |
| | | } |
| | | } // setScanFilter |
| | | |
| | | |
| | | /** |
| | | * @brief Set the advertisement data that is to be published in a regular advertisement. |
| | | * @param [in] advertisementData The data to be advertised. |
| | | */ |
| | | void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) { |
| | | log_v(">> setAdvertisementData"); |
| | | esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw( |
| | | (uint8_t*)advertisementData.getPayload().data(), |
| | | advertisementData.getPayload().length()); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | } |
| | | m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. |
| | | log_v("<< setAdvertisementData"); |
| | | } // setAdvertisementData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the advertisement data that is to be published in a scan response. |
| | | * @param [in] advertisementData The data to be advertised. |
| | | */ |
| | | void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) { |
| | | log_v(">> setScanResponseData"); |
| | | esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw( |
| | | (uint8_t*)advertisementData.getPayload().data(), |
| | | advertisementData.getPayload().length()); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | } |
| | | m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. |
| | | log_v("<< setScanResponseData"); |
| | | } // setScanResponseData |
| | | |
| | | /** |
| | | * @brief Start advertising. |
| | | * Start advertising. |
| | | * @return N/A. |
| | | */ |
| | | void BLEAdvertising::start() { |
| | | log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData); |
| | | |
| | | // We have a vector of service UUIDs that we wish to advertise. In order to use the |
| | | // ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte) |
| | | // representations. If we have 1 or more services to advertise then we allocate enough |
| | | // storage to host them and then copy them in one at a time into the contiguous storage. |
| | | int numServices = m_serviceUUIDs.size(); |
| | | if (numServices > 0) { |
| | | m_advData.service_uuid_len = 16 * numServices; |
| | | m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len]; |
| | | uint8_t* p = m_advData.p_service_uuid; |
| | | for (int i = 0; i < numServices; i++) { |
| | | log_d("- advertising service: %s", m_serviceUUIDs[i].toString().c_str()); |
| | | BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128(); |
| | | memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16); |
| | | p += 16; |
| | | } |
| | | } else { |
| | | m_advData.service_uuid_len = 0; |
| | | log_d("- no services advertised"); |
| | | } |
| | | |
| | | esp_err_t errRc; |
| | | |
| | | if (!m_customAdvData) { |
| | | // Set the configuration for advertising. |
| | | m_advData.set_scan_rsp = false; |
| | | m_advData.include_name = !m_scanResp; |
| | | m_advData.include_txpower = !m_scanResp; |
| | | errRc = ::esp_ble_gap_config_adv_data(&m_advData); |
| | | if (errRc != ESP_OK) { |
| | | log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (!m_customScanResponseData && m_scanResp) { |
| | | m_advData.set_scan_rsp = true; |
| | | m_advData.include_name = m_scanResp; |
| | | m_advData.include_txpower = m_scanResp; |
| | | errRc = ::esp_ble_gap_config_adv_data(&m_advData); |
| | | if (errRc != ESP_OK) { |
| | | log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // If we had services to advertise then we previously allocated some storage for them. |
| | | // Here we release that storage. |
| | | if (m_advData.service_uuid_len > 0) { |
| | | delete[] m_advData.p_service_uuid; |
| | | m_advData.p_service_uuid = nullptr; |
| | | } |
| | | |
| | | // Start advertising. |
| | | errRc = ::esp_ble_gap_start_advertising(&m_advParams); |
| | | if (errRc != ESP_OK) { |
| | | log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | log_v("<< start"); |
| | | } // start |
| | | |
| | | |
| | | /** |
| | | * @brief Stop advertising. |
| | | * Stop advertising. |
| | | * @return N/A. |
| | | */ |
| | | void BLEAdvertising::stop() { |
| | | log_v(">> stop"); |
| | | esp_err_t errRc = ::esp_ble_gap_stop_advertising(); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | log_v("<< stop"); |
| | | } // stop |
| | | |
| | | /** |
| | | * @brief Set BLE address. |
| | | * @param [in] Bluetooth address. |
| | | * @param [in] Bluetooth address type. |
| | | * Set BLE address. |
| | | */ |
| | | |
| | | void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) |
| | | { |
| | | log_v(">> setPrivateAddress") |
| | | |
| | | m_advParams.own_addr_type = type; |
| | | esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t*)addr); |
| | | if (errRc != ESP_OK) |
| | | { |
| | | log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | log_v("<< setPrivateAddress") |
| | | } // setPrivateAddress |
| | | |
| | | /** |
| | | * @brief Add data to the payload to be advertised. |
| | | * @param [in] data The data to be added to the payload. |
| | | */ |
| | | void BLEAdvertisementData::addData(std::string data) { |
| | | if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) { |
| | | return; |
| | | } |
| | | m_payload.append(data); |
| | | } // addData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the appearance. |
| | | * @param [in] appearance The appearance code value. |
| | | * |
| | | * See also: |
| | | * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml |
| | | */ |
| | | void BLEAdvertisementData::setAppearance(uint16_t appearance) { |
| | | char cdata[2]; |
| | | cdata[0] = 3; |
| | | cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19 |
| | | addData(std::string(cdata, 2) + std::string((char*) &appearance, 2)); |
| | | } // setAppearance |
| | | |
| | | |
| | | /** |
| | | * @brief Set the complete services. |
| | | * @param [in] uuid The single service to advertise. |
| | | */ |
| | | void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { |
| | | char cdata[2]; |
| | | switch (uuid.bitSize()) { |
| | | case 16: { |
| | | // [Len] [0x02] [LL] [HH] |
| | | cdata[0] = 3; |
| | | cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03 |
| | | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2)); |
| | | break; |
| | | } |
| | | |
| | | case 32: { |
| | | // [Len] [0x04] [LL] [LL] [HH] [HH] |
| | | cdata[0] = 5; |
| | | cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05 |
| | | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4)); |
| | | break; |
| | | } |
| | | |
| | | case 128: { |
| | | // [Len] [0x04] [0] [1] ... [15] |
| | | cdata[0] = 17; |
| | | cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07 |
| | | addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->uuid.uuid128, 16)); |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | return; |
| | | } |
| | | } // setCompleteServices |
| | | |
| | | |
| | | /** |
| | | * @brief Set the advertisement flags. |
| | | * @param [in] The flags to be set in the advertisement. |
| | | * |
| | | * * ESP_BLE_ADV_FLAG_LIMIT_DISC |
| | | * * ESP_BLE_ADV_FLAG_GEN_DISC |
| | | * * ESP_BLE_ADV_FLAG_BREDR_NOT_SPT |
| | | * * ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT |
| | | * * ESP_BLE_ADV_FLAG_DMT_HOST_SPT |
| | | * * ESP_BLE_ADV_FLAG_NON_LIMIT_DISC |
| | | */ |
| | | void BLEAdvertisementData::setFlags(uint8_t flag) { |
| | | char cdata[3]; |
| | | cdata[0] = 2; |
| | | cdata[1] = ESP_BLE_AD_TYPE_FLAG; // 0x01 |
| | | cdata[2] = flag; |
| | | addData(std::string(cdata, 3)); |
| | | } // setFlag |
| | | |
| | | |
| | | |
| | | /** |
| | | * @brief Set manufacturer specific data. |
| | | * @param [in] data Manufacturer data. |
| | | */ |
| | | void BLEAdvertisementData::setManufacturerData(std::string data) { |
| | | log_d("BLEAdvertisementData", ">> setManufacturerData"); |
| | | char cdata[2]; |
| | | cdata[0] = data.length() + 1; |
| | | cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff |
| | | addData(std::string(cdata, 2) + data); |
| | | log_d("BLEAdvertisementData", "<< setManufacturerData"); |
| | | } // setManufacturerData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the name. |
| | | * @param [in] The complete name of the device. |
| | | */ |
| | | void BLEAdvertisementData::setName(std::string name) { |
| | | log_d("BLEAdvertisementData", ">> setName: %s", name.c_str()); |
| | | char cdata[2]; |
| | | cdata[0] = name.length() + 1; |
| | | cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09 |
| | | addData(std::string(cdata, 2) + name); |
| | | log_d("BLEAdvertisementData", "<< setName"); |
| | | } // setName |
| | | |
| | | |
| | | /** |
| | | * @brief Set the partial services. |
| | | * @param [in] uuid The single service to advertise. |
| | | */ |
| | | void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { |
| | | char cdata[2]; |
| | | switch (uuid.bitSize()) { |
| | | case 16: { |
| | | // [Len] [0x02] [LL] [HH] |
| | | cdata[0] = 3; |
| | | cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02 |
| | | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid16, 2)); |
| | | break; |
| | | } |
| | | |
| | | case 32: { |
| | | // [Len] [0x04] [LL] [LL] [HH] [HH] |
| | | cdata[0] = 5; |
| | | cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04 |
| | | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid32, 4)); |
| | | break; |
| | | } |
| | | |
| | | case 128: { |
| | | // [Len] [0x04] [0] [1] ... [15] |
| | | cdata[0] = 17; |
| | | cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06 |
| | | addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid128, 16)); |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | return; |
| | | } |
| | | } // setPartialServices |
| | | |
| | | |
| | | /** |
| | | * @brief Set the service data (UUID + data) |
| | | * @param [in] uuid The UUID to set with the service data. Size of UUID will be used. |
| | | * @param [in] data The data to be associated with the service data advert. |
| | | */ |
| | | void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) { |
| | | char cdata[2]; |
| | | switch (uuid.bitSize()) { |
| | | case 16: { |
| | | // [Len] [0x16] [UUID16] data |
| | | cdata[0] = data.length() + 3; |
| | | cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16 |
| | | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2) + data); |
| | | break; |
| | | } |
| | | |
| | | case 32: { |
| | | // [Len] [0x20] [UUID32] data |
| | | cdata[0] = data.length() + 5; |
| | | cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20 |
| | | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4) + data); |
| | | break; |
| | | } |
| | | |
| | | case 128: { |
| | | // [Len] [0x21] [UUID128] data |
| | | cdata[0] = data.length() + 17; |
| | | cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21 |
| | | addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid128, 16) + data); |
| | | break; |
| | | } |
| | | |
| | | default: |
| | | return; |
| | | } |
| | | } // setServiceData |
| | | |
| | | |
| | | /** |
| | | * @brief Set the short name. |
| | | * @param [in] The short name of the device. |
| | | */ |
| | | void BLEAdvertisementData::setShortName(std::string name) { |
| | | log_d("BLEAdvertisementData", ">> setShortName: %s", name.c_str()); |
| | | char cdata[2]; |
| | | cdata[0] = name.length() + 1; |
| | | cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08 |
| | | addData(std::string(cdata, 2) + name); |
| | | log_d("BLEAdvertisementData", "<< setShortName"); |
| | | } // setShortName |
| | | |
| | | |
| | | /** |
| | | * @brief Retrieve the payload that is to be advertised. |
| | | * @return The payload that is to be advertised. |
| | | */ |
| | | std::string BLEAdvertisementData::getPayload() { |
| | | return m_payload; |
| | | } // getPayload |
| | | |
| | | void BLEAdvertising::handleGAPEvent( |
| | | esp_gap_ble_cb_event_t event, |
| | | esp_ble_gap_cb_param_t* param) { |
| | | |
| | | log_d("handleGAPEvent [event no: %d]", (int)event); |
| | | |
| | | switch(event) { |
| | | case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { |
| | | // m_semaphoreSetAdv.give(); |
| | | break; |
| | | } |
| | | case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: { |
| | | // m_semaphoreSetAdv.give(); |
| | | break; |
| | | } |
| | | case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { |
| | | // m_semaphoreSetAdv.give(); |
| | | break; |
| | | } |
| | | case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { |
| | | log_i("STOP advertising"); |
| | | start(); |
| | | break; |
| | | } |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| New file |
| | |
| | | /* |
| | | * BLEAdvertising.h |
| | | * |
| | | * Created on: Jun 21, 2017 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <esp_gap_ble_api.h> |
| | | #include "BLEUUID.h" |
| | | #include <vector> |
| | | #include "FreeRTOS.h" |
| | | |
| | | /** |
| | | * @brief Advertisement data set by the programmer to be published by the %BLE server. |
| | | */ |
| | | class BLEAdvertisementData { |
| | | // Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will |
| | | // be exposed on demand/request or as time permits. |
| | | // |
| | | public: |
| | | void setAppearance(uint16_t appearance); |
| | | void setCompleteServices(BLEUUID uuid); |
| | | void setFlags(uint8_t); |
| | | void setManufacturerData(std::string data); |
| | | void setName(std::string name); |
| | | void setPartialServices(BLEUUID uuid); |
| | | void setServiceData(BLEUUID uuid, std::string data); |
| | | void setShortName(std::string name); |
| | | void addData(std::string data); // Add data to the payload. |
| | | std::string getPayload(); // Retrieve the current advert payload. |
| | | |
| | | private: |
| | | friend class BLEAdvertising; |
| | | std::string m_payload; // The payload of the advertisement. |
| | | }; // BLEAdvertisementData |
| | | |
| | | |
| | | /** |
| | | * @brief Perform and manage %BLE advertising. |
| | | * |
| | | * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. |
| | | */ |
| | | class BLEAdvertising { |
| | | public: |
| | | BLEAdvertising(); |
| | | void addServiceUUID(BLEUUID serviceUUID); |
| | | void addServiceUUID(const char* serviceUUID); |
| | | void start(); |
| | | void stop(); |
| | | void setAppearance(uint16_t appearance); |
| | | void setMaxInterval(uint16_t maxinterval); |
| | | void setMinInterval(uint16_t mininterval); |
| | | void setAdvertisementData(BLEAdvertisementData& advertisementData); |
| | | void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly); |
| | | void setScanResponseData(BLEAdvertisementData& advertisementData); |
| | | void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); |
| | | void setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); |
| | | |
| | | void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); |
| | | void setMinPreferred(uint16_t); |
| | | void setMaxPreferred(uint16_t); |
| | | void setScanResponse(bool); |
| | | |
| | | private: |
| | | esp_ble_adv_data_t m_advData; |
| | | esp_ble_adv_params_t m_advParams; |
| | | std::vector<BLEUUID> m_serviceUUIDs; |
| | | bool m_customAdvData = false; // Are we using custom advertising data? |
| | | bool m_customScanResponseData = false; // Are we using custom scan response data? |
| | | FreeRTOS::Semaphore m_semaphoreSetAdv = FreeRTOS::Semaphore("startAdvert"); |
| | | bool m_scanResp = true; |
| | | |
| | | }; |
| | | #endif /* CONFIG_BT_ENABLED */ |
| | | #endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLEBeacon.cpp |
| | | * |
| | | * Created on: Jan 4, 2018 |
| | | * Author: kolban |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <string.h> |
| | | #include "BLEBeacon.h" |
| | | #include "esp32-hal-log.h" |
| | | |
| | | #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) |
| | | |
| | | |
| | | BLEBeacon::BLEBeacon() { |
| | | m_beaconData.manufacturerId = 0x4c00; |
| | | m_beaconData.subType = 0x02; |
| | | m_beaconData.subTypeLength = 0x15; |
| | | m_beaconData.major = 0; |
| | | m_beaconData.minor = 0; |
| | | m_beaconData.signalPower = 0; |
| | | memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID)); |
| | | } // BLEBeacon |
| | | |
| | | std::string BLEBeacon::getData() { |
| | | return std::string((char*) &m_beaconData, sizeof(m_beaconData)); |
| | | } // getData |
| | | |
| | | uint16_t BLEBeacon::getMajor() { |
| | | return m_beaconData.major; |
| | | } |
| | | |
| | | uint16_t BLEBeacon::getManufacturerId() { |
| | | return m_beaconData.manufacturerId; |
| | | } |
| | | |
| | | uint16_t BLEBeacon::getMinor() { |
| | | return m_beaconData.minor; |
| | | } |
| | | |
| | | BLEUUID BLEBeacon::getProximityUUID() { |
| | | return BLEUUID(m_beaconData.proximityUUID, 16, false); |
| | | } |
| | | |
| | | int8_t BLEBeacon::getSignalPower() { |
| | | return m_beaconData.signalPower; |
| | | } |
| | | |
| | | /** |
| | | * Set the raw data for the beacon record. |
| | | */ |
| | | void BLEBeacon::setData(std::string data) { |
| | | if (data.length() != sizeof(m_beaconData)) { |
| | | log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData)); |
| | | return; |
| | | } |
| | | memcpy(&m_beaconData, data.data(), sizeof(m_beaconData)); |
| | | } // setData |
| | | |
| | | void BLEBeacon::setMajor(uint16_t major) { |
| | | m_beaconData.major = ENDIAN_CHANGE_U16(major); |
| | | } // setMajor |
| | | |
| | | void BLEBeacon::setManufacturerId(uint16_t manufacturerId) { |
| | | m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId); |
| | | } // setManufacturerId |
| | | |
| | | void BLEBeacon::setMinor(uint16_t minor) { |
| | | m_beaconData.minor = ENDIAN_CHANGE_U16(minor); |
| | | } // setMinior |
| | | |
| | | void BLEBeacon::setProximityUUID(BLEUUID uuid) { |
| | | uuid = uuid.to128(); |
| | | memcpy(m_beaconData.proximityUUID, uuid.getNative()->uuid.uuid128, 16); |
| | | } // setProximityUUID |
| | | |
| | | void BLEBeacon::setSignalPower(int8_t signalPower) { |
| | | m_beaconData.signalPower = signalPower; |
| | | } // setSignalPower |
| | | |
| | | |
| | | #endif |
| New file |
| | |
| | | /* |
| | | * BLEBeacon2.h |
| | | * |
| | | * Created on: Jan 4, 2018 |
| | | * Author: kolban |
| | | */ |
| | | |
| | | #ifndef COMPONENTS_CPP_UTILS_BLEBEACON_H_ |
| | | #define COMPONENTS_CPP_UTILS_BLEBEACON_H_ |
| | | #include "BLEUUID.h" |
| | | /** |
| | | * @brief Representation of a beacon. |
| | | * See: |
| | | * * https://en.wikipedia.org/wiki/IBeacon |
| | | */ |
| | | class BLEBeacon { |
| | | private: |
| | | struct { |
| | | uint16_t manufacturerId; |
| | | uint8_t subType; |
| | | uint8_t subTypeLength; |
| | | uint8_t proximityUUID[16]; |
| | | uint16_t major; |
| | | uint16_t minor; |
| | | int8_t signalPower; |
| | | } __attribute__((packed)) m_beaconData; |
| | | public: |
| | | BLEBeacon(); |
| | | std::string getData(); |
| | | uint16_t getMajor(); |
| | | uint16_t getMinor(); |
| | | uint16_t getManufacturerId(); |
| | | BLEUUID getProximityUUID(); |
| | | int8_t getSignalPower(); |
| | | void setData(std::string data); |
| | | void setMajor(uint16_t major); |
| | | void setMinor(uint16_t minor); |
| | | void setManufacturerId(uint16_t manufacturerId); |
| | | void setProximityUUID(BLEUUID uuid); |
| | | void setSignalPower(int8_t signalPower); |
| | | }; // BLEBeacon |
| | | |
| | | #endif /* COMPONENTS_CPP_UTILS_BLEBEACON_H_ */ |
| New file |
| | |
| | | /* |
| | | * BLECharacteristic.cpp |
| | | * |
| | | * Created on: Jun 22, 2017 |
| | | * Author: kolban |
| | | */ |
| | | #include "sdkconfig.h" |
| | | #if defined(CONFIG_BT_ENABLED) |
| | | #include <sstream> |
| | | #include <string.h> |
| | | #include <iomanip> |
| | | #include <stdlib.h> |
| | | #include "sdkconfig.h" |
| | | #include <esp_err.h> |
| | | #include "BLECharacteristic.h" |
| | | #include "BLEService.h" |
| | | #include "BLEDevice.h" |
| | | #include "BLEUtils.h" |
| | | #include "BLE2902.h" |
| | | #include "GeneralUtils.h" |
| | | #include "esp32-hal-log.h" |
| | | |
| | | #define NULL_HANDLE (0xffff) |
| | | |
| | | |
| | | /** |
| | | * @brief Construct a characteristic |
| | | * @param [in] uuid - UUID (const char*) for the characteristic. |
| | | * @param [in] properties - Properties for the characteristic. |
| | | */ |
| | | BLECharacteristic::BLECharacteristic(const char* uuid, uint32_t properties) : BLECharacteristic(BLEUUID(uuid), properties) { |
| | | } |
| | | |
| | | /** |
| | | * @brief Construct a characteristic |
| | | * @param [in] uuid - UUID for the characteristic. |
| | | * @param [in] properties - Properties for the characteristic. |
| | | */ |
| | | BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) { |
| | | m_bleUUID = uuid; |
| | | m_handle = NULL_HANDLE; |
| | | m_properties = (esp_gatt_char_prop_t)0; |
| | | m_pCallbacks = nullptr; |
| | | |
| | | setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0); |
| | | setReadProperty((properties & PROPERTY_READ) != 0); |
| | | setWriteProperty((properties & PROPERTY_WRITE) != 0); |
| | | setNotifyProperty((properties & PROPERTY_NOTIFY) != 0); |
| | | setIndicateProperty((properties & PROPERTY_INDICATE) != 0); |
| | | setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0); |
| | | } // BLECharacteristic |
| | | |
| | | /** |
| | | * @brief Destructor. |
| | | */ |
| | | BLECharacteristic::~BLECharacteristic() { |
| | | //free(m_value.attr_value); // Release the storage for the value. |
| | | } // ~BLECharacteristic |
| | | |
| | | |
| | | /** |
| | | * @brief Associate a descriptor with this characteristic. |
| | | * @param [in] pDescriptor |
| | | * @return N/A. |
| | | */ |
| | | void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) { |
| | | log_v(">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str()); |
| | | m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor); |
| | | log_v("<< addDescriptor()"); |
| | | } // addDescriptor |
| | | |
| | | |
| | | /** |
| | | * @brief Register a new characteristic with the ESP runtime. |
| | | * @param [in] pService The service with which to associate this characteristic. |
| | | */ |
| | | void BLECharacteristic::executeCreate(BLEService* pService) { |
| | | log_v(">> executeCreate()"); |
| | | |
| | | if (m_handle != NULL_HANDLE) { |
| | | log_e("Characteristic already has a handle."); |
| | | return; |
| | | } |
| | | |
| | | m_pService = pService; // Save the service to which this characteristic belongs. |
| | | |
| | | log_d("Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s", |
| | | getUUID().toString().c_str(), |
| | | m_pService->toString().c_str()); |
| | | |
| | | esp_attr_control_t control; |
| | | control.auto_rsp = ESP_GATT_RSP_BY_APP; |
| | | |
| | | m_semaphoreCreateEvt.take("executeCreate"); |
| | | esp_err_t errRc = ::esp_ble_gatts_add_char( |
| | | m_pService->getHandle(), |
| | | getUUID().getNative(), |
| | | static_cast<esp_gatt_perm_t>(m_permissions), |
| | | getProperties(), |
| | | nullptr, |
| | | &control); // Whether to auto respond or not. |
| | | |
| | | if (errRc != ESP_OK) { |
| | | log_e("<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | return; |
| | | } |
| | | m_semaphoreCreateEvt.wait("executeCreate"); |
| | | |
| | | BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); |
| | | while (pDescriptor != nullptr) { |
| | | pDescriptor->executeCreate(this); |
| | | pDescriptor = m_descriptorMap.getNext(); |
| | | } // End while |
| | | |
| | | log_v("<< executeCreate"); |
| | | } // executeCreate |
| | | |
| | | |
| | | /** |
| | | * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. |
| | | * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. |
| | | * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. |
| | | */ |
| | | BLEDescriptor* BLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) { |
| | | return m_descriptorMap.getByUUID(BLEUUID(descriptorUUID)); |
| | | } // getDescriptorByUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. |
| | | * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. |
| | | * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. |
| | | */ |
| | | BLEDescriptor* BLECharacteristic::getDescriptorByUUID(BLEUUID descriptorUUID) { |
| | | return m_descriptorMap.getByUUID(descriptorUUID); |
| | | } // getDescriptorByUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Get the handle of the characteristic. |
| | | * @return The handle of the characteristic. |
| | | */ |
| | | uint16_t BLECharacteristic::getHandle() { |
| | | return m_handle; |
| | | } // getHandle |
| | | |
| | | void BLECharacteristic::setAccessPermissions(esp_gatt_perm_t perm) { |
| | | m_permissions = perm; |
| | | } |
| | | |
| | | esp_gatt_char_prop_t BLECharacteristic::getProperties() { |
| | | return m_properties; |
| | | } // getProperties |
| | | |
| | | |
| | | /** |
| | | * @brief Get the service associated with this characteristic. |
| | | */ |
| | | BLEService* BLECharacteristic::getService() { |
| | | return m_pService; |
| | | } // getService |
| | | |
| | | |
| | | /** |
| | | * @brief Get the UUID of the characteristic. |
| | | * @return The UUID of the characteristic. |
| | | */ |
| | | BLEUUID BLECharacteristic::getUUID() { |
| | | return m_bleUUID; |
| | | } // getUUID |
| | | |
| | | |
| | | /** |
| | | * @brief Retrieve the current value of the characteristic. |
| | | * @return A pointer to storage containing the current characteristic value. |
| | | */ |
| | | std::string BLECharacteristic::getValue() { |
| | | return m_value.getValue(); |
| | | } // getValue |
| | | |
| | | /** |
| | | * @brief Retrieve the current raw data of the characteristic. |
| | | * @return A pointer to storage containing the current characteristic data. |
| | | */ |
| | | uint8_t* BLECharacteristic::getData() { |
| | | return m_value.getData(); |
| | | } // getData |
| | | |
| | | |
| | | /** |
| | | * Handle a GATT server event. |
| | | */ |
| | | void BLECharacteristic::handleGATTServerEvent( |
| | | esp_gatts_cb_event_t event, |
| | | esp_gatt_if_t gatts_if, |
| | | esp_ble_gatts_cb_param_t* param) { |
| | | log_v(">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); |
| | | |
| | | switch(event) { |
| | | // Events handled: |
| | | // |
| | | // ESP_GATTS_ADD_CHAR_EVT |
| | | // ESP_GATTS_CONF_EVT |
| | | // ESP_GATTS_CONNECT_EVT |
| | | // ESP_GATTS_DISCONNECT_EVT |
| | | // ESP_GATTS_EXEC_WRITE_EVT |
| | | // ESP_GATTS_READ_EVT |
| | | // ESP_GATTS_WRITE_EVT |
| | | |
| | | // |
| | | // ESP_GATTS_EXEC_WRITE_EVT |
| | | // When we receive this event it is an indication that a previous write long needs to be committed. |
| | | // |
| | | // exec_write: |
| | | // - uint16_t conn_id |
| | | // - uint32_t trans_id |
| | | // - esp_bd_addr_t bda |
| | | // - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL |
| | | // |
| | | case ESP_GATTS_EXEC_WRITE_EVT: { |
| | | if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { |
| | | m_value.commit(); |
| | | if (m_pCallbacks != nullptr) { |
| | | m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. |
| | | } |
| | | } else { |
| | | m_value.cancel(); |
| | | } |
| | | // ??? |
| | | esp_err_t errRc = ::esp_ble_gatts_send_response( |
| | | gatts_if, |
| | | param->write.conn_id, |
| | | param->write.trans_id, ESP_GATT_OK, nullptr); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | } |
| | | break; |
| | | } // ESP_GATTS_EXEC_WRITE_EVT |
| | | |
| | | |
| | | // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. |
| | | // add_char: |
| | | // - esp_gatt_status_t status |
| | | // - uint16_t attr_handle |
| | | // - uint16_t service_handle |
| | | // - esp_bt_uuid_t char_uuid |
| | | case ESP_GATTS_ADD_CHAR_EVT: { |
| | | if (getHandle() == param->add_char.attr_handle) { |
| | | // we have created characteristic, now we can create descriptors |
| | | // BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); |
| | | // while (pDescriptor != nullptr) { |
| | | // pDescriptor->executeCreate(this); |
| | | // pDescriptor = m_descriptorMap.getNext(); |
| | | // } // End while |
| | | m_semaphoreCreateEvt.give(); |
| | | } |
| | | break; |
| | | } // ESP_GATTS_ADD_CHAR_EVT |
| | | |
| | | |
| | | // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. |
| | | // |
| | | // write: |
| | | // - uint16_t conn_id |
| | | // - uint16_t trans_id |
| | | // - esp_bd_addr_t bda |
| | | // - uint16_t handle |
| | | // - uint16_t offset |
| | | // - bool need_rsp |
| | | // - bool is_prep |
| | | // - uint16_t len |
| | | // - uint8_t *value |
| | | // |
| | | case ESP_GATTS_WRITE_EVT: { |
| | | // We check if this write request is for us by comparing the handles in the event. If it is for us |
| | | // we save the new value. Next we look at the need_rsp flag which indicates whether or not we need |
| | | // to send a response. If we do, then we formulate a response and send it. |
| | | if (param->write.handle == m_handle) { |
| | | if (param->write.is_prep) { |
| | | m_value.addPart(param->write.value, param->write.len); |
| | | } else { |
| | | setValue(param->write.value, param->write.len); |
| | | } |
| | | |
| | | log_d(" - Response to write event: New value: handle: %.2x, uuid: %s", |
| | | getHandle(), getUUID().toString().c_str()); |
| | | |
| | | char* pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len); |
| | | log_d(" - Data: length: %d, data: %s", param->write.len, pHexData); |
| | | free(pHexData); |
| | | |
| | | if (param->write.need_rsp) { |
| | | esp_gatt_rsp_t rsp; |
| | | |
| | | rsp.attr_value.len = param->write.len; |
| | | rsp.attr_value.handle = m_handle; |
| | | rsp.attr_value.offset = param->write.offset; |
| | | rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; |
| | | memcpy(rsp.attr_value.value, param->write.value, param->write.len); |
| | | |
| | | esp_err_t errRc = ::esp_ble_gatts_send_response( |
| | | gatts_if, |
| | | param->write.conn_id, |
| | | param->write.trans_id, ESP_GATT_OK, &rsp); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | } |
| | | } // Response needed |
| | | |
| | | if (m_pCallbacks != nullptr && param->write.is_prep != true) { |
| | | m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. |
| | | } |
| | | } // Match on handles. |
| | | break; |
| | | } // ESP_GATTS_WRITE_EVT |
| | | |
| | | |
| | | // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. |
| | | // |
| | | // read: |
| | | // - uint16_t conn_id |
| | | // - uint32_t trans_id |
| | | // - esp_bd_addr_t bda |
| | | // - uint16_t handle |
| | | // - uint16_t offset |
| | | // - bool is_long |
| | | // - bool need_rsp |
| | | // |
| | | case ESP_GATTS_READ_EVT: { |
| | | if (param->read.handle == m_handle) { |
| | | |
| | | |
| | | |
| | | // Here's an interesting thing. The read request has the option of saying whether we need a response |
| | | // or not. What would it "mean" to receive a read request and NOT send a response back? That feels like |
| | | // a very strange read. |
| | | // |
| | | // We have to handle the case where the data we wish to send back to the client is greater than the maximum |
| | | // packet size of 22 bytes. In this case, we become responsible for chunking the data into units of 22 bytes. |
| | | // The apparent algorithm is as follows: |
| | | // |
| | | // If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes. |
| | | // If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than |
| | | // 22 bytes, then we "just" send it and thats the end of the story. |
| | | // If we are sending 22 bytes exactly, we just send it BUT we will get a follow on request. |
| | | // If we are sending more than 22 bytes, we send the first 22 bytes and we will get a follow on request. |
| | | // Because of follow on request processing, we need to maintain an offset of how much data we have already sent |
| | | // so that when a follow on request arrives, we know where to start in the data to send the next sequence. |
| | | // Note that the indication that the client will send a follow on request is that we sent exactly 22 bytes as a response. |
| | | // If our payload is divisible by 22 then the last response will be a response of 0 bytes in length. |
| | | // |
| | | // The following code has deliberately not been factored to make it fewer statements because this would cloud the |
| | | // the logic flow comprehension. |
| | | // |
| | | |
| | | // get mtu for peer device that we are sending read request to |
| | | uint16_t maxOffset = getService()->getServer()->getPeerMTU(param->read.conn_id) - 1; |
| | | log_d("mtu value: %d", maxOffset); |
| | | if (param->read.need_rsp) { |
| | | log_d("Sending a response (esp_ble_gatts_send_response)"); |
| | | esp_gatt_rsp_t rsp; |
| | | |
| | | if (param->read.is_long) { |
| | | std::string value = m_value.getValue(); |
| | | |
| | | if (value.length() - m_value.getReadOffset() < maxOffset) { |
| | | // This is the last in the chain |
| | | rsp.attr_value.len = value.length() - m_value.getReadOffset(); |
| | | rsp.attr_value.offset = m_value.getReadOffset(); |
| | | memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); |
| | | m_value.setReadOffset(0); |
| | | } else { |
| | | // There will be more to come. |
| | | rsp.attr_value.len = maxOffset; |
| | | rsp.attr_value.offset = m_value.getReadOffset(); |
| | | memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); |
| | | m_value.setReadOffset(rsp.attr_value.offset + maxOffset); |
| | | } |
| | | } else { // read.is_long == false |
| | | |
| | | std::string value = m_value.getValue(); |
| | | |
| | | if (value.length() + 1 > maxOffset) { |
| | | // Too big for a single shot entry. |
| | | m_value.setReadOffset(maxOffset); |
| | | rsp.attr_value.len = maxOffset; |
| | | rsp.attr_value.offset = 0; |
| | | memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); |
| | | } else { |
| | | // Will fit in a single packet with no callbacks required. |
| | | rsp.attr_value.len = value.length(); |
| | | rsp.attr_value.offset = 0; |
| | | memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); |
| | | } |
| | | |
| | | if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback |
| | | m_pCallbacks->onRead(this); // Invoke the read callback. |
| | | } |
| | | } |
| | | rsp.attr_value.handle = param->read.handle; |
| | | rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; |
| | | |
| | | char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len); |
| | | log_d(" - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset); |
| | | free(pHexData); |
| | | |
| | | esp_err_t errRc = ::esp_ble_gatts_send_response( |
| | | gatts_if, param->read.conn_id, |
| | | param->read.trans_id, |
| | | ESP_GATT_OK, |
| | | &rsp); |
| | | if (errRc != ESP_OK) { |
| | | log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); |
| | | } |
| | | } // Response needed |
| | | } // Handle matches this characteristic. |
| | | break; |
| | | } // ESP_GATTS_READ_EVT |
| | | |
| | | |
| | | // ESP_GATTS_CONF_EVT |
| | | // |
| | | // conf: |
| | | // - esp_gatt_status_t status – The status code. |
| | | // - uint16_t conn_id – The connection used. |
| | | // |
| | | case ESP_GATTS_CONF_EVT: { |
| | | // log_d("m_handle = %d, conf->handle = %d", m_handle, param->conf.handle); |
| | | if(param->conf.conn_id == getService()->getServer()->getConnId()) // && param->conf.handle == m_handle) // bug in esp-idf and not implemented in arduino yet |
| | | m_semaphoreConfEvt.give(param->conf.status); |
| | | break; |
| | | } |
| | | |
| | | case ESP_GATTS_CONNECT_EVT: { |
| | | break; |
| | | } |
| | | |
| | | case ESP_GATTS_DISCONNECT_EVT: { |
| | | m_semaphoreConfEvt.give(); |
| | | break; |
| | | } |
| | | |
| | | default: { |
| | | break; |
| | | } // default |
| | | |
| | | } // switch event |
| | | |
| | | // Give each of the descriptors associated with this characteristic the opportunity to handle the |
| | | // event. |
| | | |
| | | m_descriptorMap.handleGATTServerEvent(event, gatts_if, param); |
| | | log_v("<< handleGATTServerEvent"); |
| | | } // handleGATTServerEvent |
| | | |
| | | |
| | | /** |
| | | * @brief Send an indication. |
| | | * An indication is a transmission of up to the first 20 bytes of the characteristic value. An indication |
| | | * will block waiting a positive confirmation from the client. |
| | | * @return N/A |
| | | */ |
| | | void BLECharacteristic::indicate() { |
| | | |
| | | log_v(">> indicate: length: %d", m_value.getValue().length()); |
| | | notify(false); |
| | | log_v("<< indicate"); |
| | | } // indicate |
| | | |
| | | |
| | | /** |
| | | * @brief Send a notify. |
| | | * A notification is a transmission of up to the first 20 bytes of the characteristic value. An notification |
| | | * will not block; it is a fire and forget. |
| | | * @return N/A. |
| | | */ |
| | | void BLECharacteristic::notify(bool is_notification) { |
| | | log_v(">> notify: length: %d", m_value.getValue().length()); |
| | | |
| | | assert(getService() != nullptr); |
| | | assert(getService()->getServer() != nullptr); |
| | | |
| | | GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); |
| | | |
| | | if (getService()->getServer()->getConnectedCount() == 0) { |
| | | log_v("<< notify: No connected clients."); |
| | | return; |
| | | } |
| | | |
| | | // Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled |
| | | // and, if not, prevent the notification. |
| | | |
| | | BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); |
| | | if(is_notification) { |
| | | if (p2902 != nullptr && !p2902->getNotifications()) { |
| | | log_v("<< notifications disabled; ignoring"); |
| | | return; |
| | | } |
| | | } |
| | | else{ |
| | | if (p2902 != nullptr && !p2902->getIndications()) { |
| | | log_v("<< indications disabled; ignoring"); |
| | | return; |
| | | } |
| | | } |
| | | for (auto &myPair : getService()->getServer()->getPeerDevices(false)) { |
| | | uint16_t _mtu = (myPair.second.mtu); |
| | | if (m_value.getValue().length() > _mtu - 3) { |
| | | log_w("- Truncating to %d bytes (maximum notify size)", _mtu - 3); |
| | | } |
| | | |
| | | size_t length = m_value.getValue().length(); |
| | | if(!is_notification) |
| | | m_semaphoreConfEvt.take("indicate"); |
| | | esp_err_t errRc = ::esp_ble_gatts_send_indicate( |
| | | getService()->getServer()->getGattsIf(), |
| | | myPair.first, |
| | | getHandle(), length, (uint8_t*)m_value.getValue().data(), !is_notification); // The need_confirm = false makes this a notify. |
| | | if (errRc != ESP_OK) { |
| | | log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc)); |
| | | m_semaphoreConfEvt.give(); |
| | | return; |
| | | } |
| | | if(!is_notification) |
| | | m_semaphoreConfEvt.wait("indicate"); |
| | | } |
| | | log_v("<< notify"); |
| | | } // Notify |
| | | |
| | | |
| | | /** |
| | | * @brief Set the permission to broadcast. |
| | | * A characteristics has properties associated with it which define what it is capable of doing. |
| | | * One of these is the broadcast flag. |
| | | * @param [in] value The flag value of the property. |
| | | * @return N/A |
| | | */ |
| | | void BLECharacteristic::setBroadcastProperty(bool value) { |
| | | //log_d("setBroadcastProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); |
| | | } |
| | | } // setBroadcastProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Set the callback handlers for this characteristic. |
| | | * @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic. |
| | | */ |
| | | void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) { |
| | | log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks); |
| | | m_pCallbacks = pCallbacks; |
| | | log_v("<< setCallbacks"); |
| | | } // setCallbacks |
| | | |
| | | |
| | | /** |
| | | * @brief Set the BLE handle associated with this characteristic. |
| | | * A user program will request that a characteristic be created against a service. When the characteristic has been |
| | | * registered, the service will be given a "handle" that it knows the characteristic as. This handle is unique to the |
| | | * server/service but it is told to the service, not the characteristic associated with the service. This internally |
| | | * exposed function can be invoked by the service against this model of the characteristic to allow the characteristic |
| | | * to learn its own handle. Once the characteristic knows its own handle, it will be able to see incoming GATT events |
| | | * that will be propagated down to it which contain a handle value and now know that the event is destined for it. |
| | | * @param [in] handle The handle associated with this characteristic. |
| | | */ |
| | | void BLECharacteristic::setHandle(uint16_t handle) { |
| | | log_v(">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str()); |
| | | m_handle = handle; |
| | | log_v("<< setHandle"); |
| | | } // setHandle |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Indicate property value. |
| | | * @param [in] value Set to true if we are to allow indicate messages. |
| | | */ |
| | | void BLECharacteristic::setIndicateProperty(bool value) { |
| | | //log_d("setIndicateProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); |
| | | } |
| | | } // setIndicateProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Notify property value. |
| | | * @param [in] value Set to true if we are to allow notification messages. |
| | | */ |
| | | void BLECharacteristic::setNotifyProperty(bool value) { |
| | | //log_d("setNotifyProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); |
| | | } |
| | | } // setNotifyProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Read property value. |
| | | * @param [in] value Set to true if we are to allow reads. |
| | | */ |
| | | void BLECharacteristic::setReadProperty(bool value) { |
| | | //log_d("setReadProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_READ); |
| | | } |
| | | } // setReadProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Set the value of the characteristic. |
| | | * @param [in] data The data to set for the characteristic. |
| | | * @param [in] length The length of the data in bytes. |
| | | */ |
| | | void BLECharacteristic::setValue(uint8_t* data, size_t length) { |
| | | char* pHex = BLEUtils::buildHexData(nullptr, data, length); |
| | | log_v(">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); |
| | | free(pHex); |
| | | if (length > ESP_GATT_MAX_ATTR_LEN) { |
| | | log_e("Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); |
| | | return; |
| | | } |
| | | m_semaphoreSetValue.take(); |
| | | m_value.setValue(data, length); |
| | | m_semaphoreSetValue.give(); |
| | | log_v("<< setValue"); |
| | | } // setValue |
| | | |
| | | |
| | | /** |
| | | * @brief Set the value of the characteristic from string data. |
| | | * We set the value of the characteristic from the bytes contained in the |
| | | * string. |
| | | * @param [in] Set the value of the characteristic. |
| | | * @return N/A. |
| | | */ |
| | | void BLECharacteristic::setValue(std::string value) { |
| | | setValue((uint8_t*)(value.data()), value.length()); |
| | | } // setValue |
| | | |
| | | void BLECharacteristic::setValue(uint16_t& data16) { |
| | | uint8_t temp[2]; |
| | | temp[0] = data16; |
| | | temp[1] = data16 >> 8; |
| | | setValue(temp, 2); |
| | | } // setValue |
| | | |
| | | void BLECharacteristic::setValue(uint32_t& data32) { |
| | | uint8_t temp[4]; |
| | | temp[0] = data32; |
| | | temp[1] = data32 >> 8; |
| | | temp[2] = data32 >> 16; |
| | | temp[3] = data32 >> 24; |
| | | setValue(temp, 4); |
| | | } // setValue |
| | | |
| | | void BLECharacteristic::setValue(int& data32) { |
| | | uint8_t temp[4]; |
| | | temp[0] = data32; |
| | | temp[1] = data32 >> 8; |
| | | temp[2] = data32 >> 16; |
| | | temp[3] = data32 >> 24; |
| | | setValue(temp, 4); |
| | | } // setValue |
| | | |
| | | void BLECharacteristic::setValue(float& data32) { |
| | | uint8_t temp[4]; |
| | | *((float*)temp) = data32; |
| | | setValue(temp, 4); |
| | | } // setValue |
| | | |
| | | void BLECharacteristic::setValue(double& data64) { |
| | | uint8_t temp[8]; |
| | | *((double*)temp) = data64; |
| | | setValue(temp, 8); |
| | | } // setValue |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Write No Response property value. |
| | | * @param [in] value Set to true if we are to allow writes with no response. |
| | | */ |
| | | void BLECharacteristic::setWriteNoResponseProperty(bool value) { |
| | | //log_d("setWriteNoResponseProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); |
| | | } |
| | | } // setWriteNoResponseProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Set the Write property value. |
| | | * @param [in] value Set to true if we are to allow writes. |
| | | */ |
| | | void BLECharacteristic::setWriteProperty(bool value) { |
| | | //log_d("setWriteProperty(%d)", value); |
| | | if (value) { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE); |
| | | } else { |
| | | m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE); |
| | | } |
| | | } // setWriteProperty |
| | | |
| | | |
| | | /** |
| | | * @brief Return a string representation of the characteristic. |
| | | * @return A string representation of the characteristic. |
| | | */ |
| | | std::string BLECharacteristic::toString() { |
| | | std::stringstream stringstream; |
| | | stringstream << std::hex << std::setfill('0'); |
| | | stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; |
| | | stringstream << " " << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_READ) ? "Read " : "") << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) ? "Write " : "") << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) ? "WriteNoResponse " : "") << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) ? "Broadcast " : "") << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) ? "Notify " : "") << |
| | | ((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) ? "Indicate " : ""); |
| | | return stringstream.str(); |
| | | } // toString |
| | | |
| | | |
| | | BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {} |
| | | |
| | | |
| | | /** |
| | | * @brief Callback function to support a read request. |
| | | * @param [in] pCharacteristic The characteristic that is the source of the event. |
| | | */ |
| | | void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) { |
| | | log_d("BLECharacteristicCallbacks", ">> onRead: default"); |
| | | log_d("BLECharacteristicCallbacks", "<< onRead"); |
| | | } // onRead |
| | | |
| | | |
| | | /** |
| | | * @brief Callback function to support a write request. |
| | | * @param [in] pCharacteristic The characteristic that is the source of the event. |
| | | */ |
| | | void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) { |
| | | log_d("BLECharacteristicCallbacks", ">> onWrite: default"); |
| | | log_d("BLECharacteristicCallbacks", "<< onWrite"); |
| | | } // onWrite |
| | | |
| | | #endif /* CONFIG_BT_ENABLED */ |
| libraries/BLE/src/BLECharacteristic.h
libraries/BLE/src/BLECharacteristicMap.cpp
libraries/BLE/src/BLEClient.cpp
libraries/BLE/src/BLEClient.h
libraries/BLE/src/BLEDescriptor.cpp
libraries/BLE/src/BLEDescriptor.h
libraries/BLE/src/BLEDescriptorMap.cpp
libraries/BLE/src/BLEDevice.cpp
libraries/BLE/src/BLEDevice.h
libraries/BLE/src/BLEEddystoneTLM.cpp
libraries/BLE/src/BLEEddystoneTLM.h
libraries/BLE/src/BLEEddystoneURL.cpp
libraries/BLE/src/BLEEddystoneURL.h
libraries/BLE/src/BLEExceptions.cpp
libraries/BLE/src/BLEExceptions.h
libraries/BLE/src/BLEHIDDevice.cpp
libraries/BLE/src/BLEHIDDevice.h
libraries/BLE/src/BLERemoteCharacteristic.cpp
libraries/BLE/src/BLERemoteCharacteristic.h
libraries/BLE/src/BLERemoteDescriptor.cpp
libraries/BLE/src/BLERemoteDescriptor.h
libraries/BLE/src/BLERemoteService.cpp
libraries/BLE/src/BLERemoteService.h
libraries/BLE/src/BLEScan.cpp
libraries/BLE/src/BLEScan.h
libraries/BLE/src/BLESecurity.cpp
libraries/BLE/src/BLESecurity.h
libraries/BLE/src/BLEServer.cpp
libraries/BLE/src/BLEServer.h
libraries/BLE/src/BLEService.cpp
libraries/BLE/src/BLEService.h
libraries/BLE/src/BLEServiceMap.cpp
libraries/BLE/src/BLEUUID.cpp
libraries/BLE/src/BLEUUID.h
libraries/BLE/src/BLEUtils.cpp
libraries/BLE/src/BLEUtils.h
libraries/BLE/src/BLEValue.cpp
libraries/BLE/src/BLEValue.h
libraries/BLE/src/FreeRTOS.cpp
libraries/BLE/src/FreeRTOS.h
libraries/BLE/src/GeneralUtils.cpp
libraries/BLE/src/GeneralUtils.h
libraries/BLE/src/HIDKeyboardTypes.h
libraries/BLE/src/HIDTypes.h
libraries/BluetoothSerial/README.md
libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino
libraries/BluetoothSerial/keywords.txt
libraries/BluetoothSerial/library.properties
libraries/BluetoothSerial/src/BluetoothSerial.cpp
libraries/BluetoothSerial/src/BluetoothSerial.h
libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino
libraries/DNSServer/library.properties
libraries/DNSServer/src/DNSServer.cpp
libraries/DNSServer/src/DNSServer.h
libraries/EEPROM/README.md
libraries/EEPROM/examples/eeprom_class/eeprom_class.ino
libraries/EEPROM/examples/eeprom_extra/eeprom_extra.ino
libraries/EEPROM/examples/eeprom_write/eeprom_write.ino
libraries/EEPROM/keywords.txt
libraries/EEPROM/library.properties
libraries/EEPROM/src/EEPROM.cpp
libraries/EEPROM/src/EEPROM.h
libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino
libraries/ESP32/examples/AnalogOut/SigmaDelta/SigmaDelta.ino
libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino
libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino
libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp
libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h
libraries/ESP32/examples/Camera/CameraWebServer/camera_pins.h
libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino
libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ExternalWakeUp.ino
libraries/ESP32/examples/DeepSleep/TimerWakeUp/TimerWakeUp.ino
libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino
libraries/ESP32/examples/ESPNow/Basic/Master/Master.ino
libraries/ESP32/examples/ESPNow/Basic/Slave/Slave.ino
libraries/ESP32/examples/ESPNow/Multi-Slave/Master/Master.ino
libraries/ESP32/examples/ESPNow/Multi-Slave/Slave/Slave.ino
libraries/ESP32/examples/FreeRTOS/FreeRTOS.ino
libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino
libraries/ESP32/examples/GPIO/GPIOInterrupt/GPIOInterrupt.ino
libraries/ESP32/examples/HallSensor/HallSensor.ino
libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino
libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino
libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino
libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino
libraries/ESP32/examples/ResetReason/ResetReason.ino
libraries/ESP32/examples/Time/SimpleTime/SimpleTime.ino
libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino
libraries/ESP32/examples/Timer/WatchdogTimer/WatchdogTimer.ino
libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino
libraries/ESP32/examples/Touch/TouchRead/TouchRead.ino
libraries/ESP32/library.properties
libraries/ESP32/src/dummy.h
libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino
libraries/ESPmDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino
libraries/ESPmDNS/keywords.txt
libraries/ESPmDNS/library.properties
libraries/ESPmDNS/src/ESPmDNS.cpp
libraries/ESPmDNS/src/ESPmDNS.h
libraries/FFat/examples/FFat_Test/FFat_Test.ino
libraries/FFat/library.properties
libraries/FFat/src/FFat.cpp
libraries/FFat/src/FFat.h
libraries/FS/library.properties
libraries/FS/src/FS.cpp
libraries/FS/src/FS.h
libraries/FS/src/FSImpl.h
libraries/FS/src/vfs_api.cpp
libraries/FS/src/vfs_api.h
libraries/HTTPClient/examples/Authorization/Authorization.ino
libraries/HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino
libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino
libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino
libraries/HTTPClient/examples/ReuseConnection/ReuseConnection.ino
libraries/HTTPClient/examples/StreamHttpClient/StreamHttpClient.ino
libraries/HTTPClient/library.properties
libraries/HTTPClient/src/HTTPClient.cpp
libraries/HTTPClient/src/HTTPClient.h
libraries/HTTPUpdate/examples/httpUpdate/httpUpdate.ino
libraries/HTTPUpdate/examples/httpUpdateSPIFFS/httpUpdateSPIFFS.ino
libraries/HTTPUpdate/examples/httpUpdateSecure/httpUpdateSecure.ino
libraries/HTTPUpdate/keywords.txt
libraries/HTTPUpdate/library.properties
libraries/HTTPUpdate/src/HTTPUpdate.cpp
libraries/HTTPUpdate/src/HTTPUpdate.h
libraries/NetBIOS/examples/ESP_NBNST/ESP_NBNST.ino
libraries/NetBIOS/keywords.txt
libraries/NetBIOS/library.properties
libraries/NetBIOS/src/NetBIOS.cpp
libraries/NetBIOS/src/NetBIOS.h
libraries/Preferences/examples/Prefs2Struct/Prefs2Struct.ino
libraries/Preferences/examples/StartCounter/StartCounter.ino
libraries/Preferences/keywords.txt
libraries/Preferences/library.properties
libraries/Preferences/src/Preferences.cpp
libraries/Preferences/src/Preferences.h
libraries/SD/README.md
libraries/SD/examples/SD_Test/SD_Test.ino
libraries/SD/examples/SD_time/SD_time.ino
libraries/SD/library.properties
libraries/SD/src/SD.cpp
libraries/SD/src/SD.h
libraries/SD/src/sd_defines.h
libraries/SD/src/sd_diskio.cpp
libraries/SD/src/sd_diskio.h
libraries/SD/src/sd_diskio_crc.c
libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino
libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino
libraries/SD_MMC/library.properties
libraries/SD_MMC/src/SD_MMC.cpp
libraries/SD_MMC/src/SD_MMC.h
libraries/SD_MMC/src/sd_defines.h
libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino
libraries/SPI/examples/SPI_Multiple_Buses/multiple_bus_output.PNG
libraries/SPI/keywords.txt
libraries/SPI/library.properties
libraries/SPI/src/SPI.cpp
libraries/SPI/src/SPI.h
libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino
libraries/SPIFFS/examples/SPIFFS_time/SPIFFS_time.ino
libraries/SPIFFS/library.properties
libraries/SPIFFS/src/SPIFFS.cpp
libraries/SPIFFS/src/SPIFFS.h
libraries/SimpleBLE/examples/SimpleBleDevice/SimpleBleDevice.ino
libraries/SimpleBLE/library.properties
libraries/SimpleBLE/src/SimpleBLE.cpp
libraries/SimpleBLE/src/SimpleBLE.h
libraries/Ticker/examples/Arguments/Arguments.ino
libraries/Ticker/examples/Blinker/Blinker.ino
libraries/Ticker/keywords.txt
libraries/Ticker/library.properties
libraries/Ticker/src/Ticker.cpp
libraries/Ticker/src/Ticker.h
libraries/Update/examples/AWS_S3_OTA_Update/AWS_S3_OTA_Update.ino
libraries/Update/examples/AWS_S3_OTA_Update/StartCounter.ino.bin
libraries/Update/examples/SD_Update/SD_Update.ino
libraries/Update/keywords.txt
libraries/Update/library.properties
libraries/Update/src/Update.h
libraries/Update/src/Updater.cpp
libraries/WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino
libraries/WebServer/examples/FSBrowser/FSBrowser.ino
libraries/WebServer/examples/FSBrowser/data/edit.htm.gz
libraries/WebServer/examples/FSBrowser/data/favicon.ico
libraries/WebServer/examples/FSBrowser/data/graphs.js.gz
libraries/WebServer/examples/FSBrowser/data/index.htm
libraries/WebServer/examples/HelloServer/HelloServer.ino
libraries/WebServer/examples/HttpAdvancedAuth/HttpAdvancedAuth.ino
libraries/WebServer/examples/HttpBasicAuth/HttpBasicAuth.ino
libraries/WebServer/examples/PathArgServer/PathArgServer.ino
libraries/WebServer/examples/SDWebServer/SDWebServer.ino
libraries/WebServer/examples/SDWebServer/SdRoot/edit/index.htm
libraries/WebServer/examples/SDWebServer/SdRoot/index.htm
libraries/WebServer/examples/SDWebServer/SdRoot/pins.png
libraries/WebServer/examples/SimpleAuthentification/SimpleAuthentification.ino
libraries/WebServer/examples/WebUpdate/WebUpdate.ino
libraries/WebServer/keywords.txt
libraries/WebServer/library.properties
libraries/WebServer/src/HTTP_Method.h
libraries/WebServer/src/Parsing.cpp
libraries/WebServer/src/WebServer.cpp
libraries/WebServer/src/WebServer.h
libraries/WebServer/src/detail/RequestHandler.h
libraries/WebServer/src/detail/RequestHandlersImpl.h
libraries/WebServer/src/detail/mimetable.cpp
libraries/WebServer/src/detail/mimetable.h
libraries/WiFi/examples/ETH_LAN8720/ETH_LAN8720.ino
libraries/WiFi/examples/ETH_LAN8720_internal_clock/ETH_LAN8720_internal_clock.ino
libraries/WiFi/examples/ETH_TLK110/ETH_TLK110.ino
libraries/WiFi/examples/SimpleWiFiServer/SimpleWiFiServer.ino
libraries/WiFi/examples/WPS/README.md
libraries/WiFi/examples/WPS/WPS.ino
libraries/WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino
libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino
libraries/WiFi/examples/WiFiClient/WiFiClient.ino
libraries/WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino
libraries/WiFi/examples/WiFiClientEnterprise/README.md
libraries/WiFi/examples/WiFiClientEnterprise/WiFiClientEnterprise.ino
libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino
libraries/WiFi/examples/WiFiClientStaticIP/WiFiClientStaticIP.ino
libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino
libraries/WiFi/examples/WiFiMulti/WiFiMulti.ino
libraries/WiFi/examples/WiFiScan/WiFiScan.ino
libraries/WiFi/examples/WiFiSmartConfig/WiFiSmartConfig.ino
libraries/WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino
libraries/WiFi/examples/WiFiUDPClient/WiFiUDPClient.ino
libraries/WiFi/examples/WiFiUDPClient/udp_server.py
libraries/WiFi/examples/WiFiUDPClient/udp_server.rb
libraries/WiFi/keywords.txt
libraries/WiFi/library.properties
libraries/WiFi/src/ETH.cpp
libraries/WiFi/src/ETH.h
libraries/WiFi/src/WiFi.cpp
libraries/WiFi/src/WiFi.h
libraries/WiFi/src/WiFiAP.cpp
libraries/WiFi/src/WiFiAP.h
libraries/WiFi/src/WiFiClient.cpp
libraries/WiFi/src/WiFiClient.h
libraries/WiFi/src/WiFiGeneric.cpp
libraries/WiFi/src/WiFiGeneric.h
libraries/WiFi/src/WiFiMulti.cpp
libraries/WiFi/src/WiFiMulti.h
libraries/WiFi/src/WiFiSTA.cpp
libraries/WiFi/src/WiFiSTA.h
libraries/WiFi/src/WiFiScan.cpp
libraries/WiFi/src/WiFiScan.h
libraries/WiFi/src/WiFiServer.cpp
libraries/WiFi/src/WiFiServer.h
libraries/WiFi/src/WiFiType.h
libraries/WiFi/src/WiFiUdp.cpp
libraries/WiFi/src/WiFiUdp.h
libraries/WiFiClientSecure/README.md
libraries/WiFiClientSecure/examples/WiFiClientPSK/WiFiClientPSK.ino
libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino
libraries/WiFiClientSecure/examples/WiFiClientSecureEnterprise/WiFiClientSecureEnterprise.ino
libraries/WiFiClientSecure/keywords.txt
libraries/WiFiClientSecure/library.properties
libraries/WiFiClientSecure/src/WiFiClientSecure.cpp
libraries/WiFiClientSecure/src/WiFiClientSecure.h
libraries/WiFiClientSecure/src/ssl_client.cpp
libraries/WiFiClientSecure/src/ssl_client.h
libraries/Wire/doc/i2c_debugging.md
libraries/Wire/keywords.txt
libraries/Wire/library.properties
libraries/Wire/src/Wire.cpp
libraries/Wire/src/Wire.h
package.json
package/merge_packages.py
package/package_esp32_index.template.json
platform.txt
programmers.txt
tools/build-release.sh
tools/build-tests.sh
tools/build.py
tools/build.sh
tools/check_cmakelists.sh
tools/common.sh
tools/deploy.sh
tools/espota.exe
tools/espota.py
tools/esptool.py
tools/gen_esp32part.exe
tools/gen_esp32part.py
tools/get.exe
tools/get.py
tools/partitions/boot_app0.bin
tools/partitions/default.bin
tools/partitions/default.csv
tools/partitions/default_16MB.csv
tools/partitions/default_8MB.csv
tools/partitions/default_ffat.csv
tools/partitions/ffat.csv
tools/partitions/huge_app.csv
tools/partitions/large_spiffs_16MB.csv
tools/partitions/min_spiffs.csv
tools/partitions/minimal.csv
tools/partitions/no_ota.csv
tools/partitions/noota_3g.csv
tools/partitions/noota_3gffat.csv
tools/partitions/noota_ffat.csv
tools/platformio-build.py
tools/sdk/bin/bootloader_dio_40m.bin
tools/sdk/bin/bootloader_dio_80m.bin
tools/sdk/bin/bootloader_dout_40m.bin
tools/sdk/bin/bootloader_dout_80m.bin
tools/sdk/bin/bootloader_qio_40m.bin
tools/sdk/bin/bootloader_qio_80m.bin
tools/sdk/bin/bootloader_qout_40m.bin
tools/sdk/bin/bootloader_qout_80m.bin
tools/sdk/include/app_trace/esp_app_trace.h
tools/sdk/include/app_trace/esp_app_trace_util.h
tools/sdk/include/app_update/esp_ota_ops.h
tools/sdk/include/asio/asio.hpp
tools/sdk/include/asio/asio/associated_allocator.hpp
tools/sdk/include/asio/asio/associated_executor.hpp
tools/sdk/include/asio/asio/async_result.hpp
tools/sdk/include/asio/asio/basic_datagram_socket.hpp
tools/sdk/include/asio/asio/basic_deadline_timer.hpp
tools/sdk/include/asio/asio/basic_io_object.hpp
tools/sdk/include/asio/asio/basic_raw_socket.hpp
tools/sdk/include/asio/asio/basic_seq_packet_socket.hpp
tools/sdk/include/asio/asio/basic_serial_port.hpp
tools/sdk/include/asio/asio/basic_signal_set.hpp
tools/sdk/include/asio/asio/basic_socket.hpp
tools/sdk/include/asio/asio/basic_socket_acceptor.hpp
tools/sdk/include/asio/asio/basic_socket_iostream.hpp
tools/sdk/include/asio/asio/basic_socket_streambuf.hpp
tools/sdk/include/asio/asio/basic_stream_socket.hpp
tools/sdk/include/asio/asio/basic_streambuf.hpp
tools/sdk/include/asio/asio/basic_streambuf_fwd.hpp
tools/sdk/include/asio/asio/basic_waitable_timer.hpp
tools/sdk/include/asio/asio/bind_executor.hpp
tools/sdk/include/asio/asio/buffer.hpp
tools/sdk/include/asio/asio/buffered_read_stream.hpp
tools/sdk/include/asio/asio/buffered_read_stream_fwd.hpp
tools/sdk/include/asio/asio/buffered_stream.hpp
tools/sdk/include/asio/asio/buffered_stream_fwd.hpp
tools/sdk/include/asio/asio/buffered_write_stream.hpp
tools/sdk/include/asio/asio/buffered_write_stream_fwd.hpp
tools/sdk/include/asio/asio/buffers_iterator.hpp
tools/sdk/include/asio/asio/completion_condition.hpp
tools/sdk/include/asio/asio/connect.hpp
tools/sdk/include/asio/asio/coroutine.hpp
tools/sdk/include/asio/asio/datagram_socket_service.hpp
tools/sdk/include/asio/asio/deadline_timer.hpp
tools/sdk/include/asio/asio/deadline_timer_service.hpp
tools/sdk/include/asio/asio/defer.hpp
tools/sdk/include/asio/asio/detail/array.hpp
tools/sdk/include/asio/asio/detail/array_fwd.hpp
tools/sdk/include/asio/asio/detail/assert.hpp
tools/sdk/include/asio/asio/detail/atomic_count.hpp
tools/sdk/include/asio/asio/detail/base_from_completion_cond.hpp
tools/sdk/include/asio/asio/detail/bind_handler.hpp
tools/sdk/include/asio/asio/detail/buffer_resize_guard.hpp
tools/sdk/include/asio/asio/detail/buffer_sequence_adapter.hpp
tools/sdk/include/asio/asio/detail/buffered_stream_storage.hpp
tools/sdk/include/asio/asio/detail/call_stack.hpp
tools/sdk/include/asio/asio/detail/chrono.hpp
tools/sdk/include/asio/asio/detail/chrono_time_traits.hpp
tools/sdk/include/asio/asio/detail/completion_handler.hpp
tools/sdk/include/asio/asio/detail/concurrency_hint.hpp
tools/sdk/include/asio/asio/detail/conditionally_enabled_event.hpp
tools/sdk/include/asio/asio/detail/conditionally_enabled_mutex.hpp
tools/sdk/include/asio/asio/detail/config.hpp
tools/sdk/include/asio/asio/detail/consuming_buffers.hpp
tools/sdk/include/asio/asio/detail/cstddef.hpp
tools/sdk/include/asio/asio/detail/cstdint.hpp
tools/sdk/include/asio/asio/detail/date_time_fwd.hpp
tools/sdk/include/asio/asio/detail/deadline_timer_service.hpp
tools/sdk/include/asio/asio/detail/dependent_type.hpp
tools/sdk/include/asio/asio/detail/descriptor_ops.hpp
tools/sdk/include/asio/asio/detail/descriptor_read_op.hpp
tools/sdk/include/asio/asio/detail/descriptor_write_op.hpp
tools/sdk/include/asio/asio/detail/dev_poll_reactor.hpp
tools/sdk/include/asio/asio/detail/epoll_reactor.hpp
tools/sdk/include/asio/asio/detail/event.hpp
tools/sdk/include/asio/asio/detail/eventfd_select_interrupter.hpp
tools/sdk/include/asio/asio/detail/executor_op.hpp
tools/sdk/include/asio/asio/detail/fd_set_adapter.hpp
tools/sdk/include/asio/asio/detail/fenced_block.hpp
tools/sdk/include/asio/asio/detail/functional.hpp
tools/sdk/include/asio/asio/detail/gcc_arm_fenced_block.hpp
tools/sdk/include/asio/asio/detail/gcc_hppa_fenced_block.hpp
tools/sdk/include/asio/asio/detail/gcc_sync_fenced_block.hpp
tools/sdk/include/asio/asio/detail/gcc_x86_fenced_block.hpp
tools/sdk/include/asio/asio/detail/global.hpp
tools/sdk/include/asio/asio/detail/handler_alloc_helpers.hpp
tools/sdk/include/asio/asio/detail/handler_cont_helpers.hpp
tools/sdk/include/asio/asio/detail/handler_invoke_helpers.hpp
tools/sdk/include/asio/asio/detail/handler_tracking.hpp
tools/sdk/include/asio/asio/detail/handler_type_requirements.hpp
tools/sdk/include/asio/asio/detail/handler_work.hpp
tools/sdk/include/asio/asio/detail/hash_map.hpp
tools/sdk/include/asio/asio/detail/impl/dev_poll_reactor.hpp
tools/sdk/include/asio/asio/detail/impl/epoll_reactor.hpp
tools/sdk/include/asio/asio/detail/impl/kqueue_reactor.hpp
tools/sdk/include/asio/asio/detail/impl/select_reactor.hpp
tools/sdk/include/asio/asio/detail/impl/service_registry.hpp
tools/sdk/include/asio/asio/detail/impl/strand_executor_service.hpp
tools/sdk/include/asio/asio/detail/impl/strand_service.hpp
tools/sdk/include/asio/asio/detail/impl/win_iocp_io_context.hpp
tools/sdk/include/asio/asio/detail/impl/winrt_timer_scheduler.hpp
tools/sdk/include/asio/asio/detail/io_control.hpp
tools/sdk/include/asio/asio/detail/is_buffer_sequence.hpp
tools/sdk/include/asio/asio/detail/is_executor.hpp
tools/sdk/include/asio/asio/detail/keyword_tss_ptr.hpp
tools/sdk/include/asio/asio/detail/kqueue_reactor.hpp
tools/sdk/include/asio/asio/detail/limits.hpp
tools/sdk/include/asio/asio/detail/local_free_on_block_exit.hpp
tools/sdk/include/asio/asio/detail/macos_fenced_block.hpp
tools/sdk/include/asio/asio/detail/memory.hpp
tools/sdk/include/asio/asio/detail/mutex.hpp
tools/sdk/include/asio/asio/detail/noncopyable.hpp
tools/sdk/include/asio/asio/detail/null_event.hpp
tools/sdk/include/asio/asio/detail/null_fenced_block.hpp
tools/sdk/include/asio/asio/detail/null_global.hpp
tools/sdk/include/asio/asio/detail/null_mutex.hpp
tools/sdk/include/asio/asio/detail/null_reactor.hpp
tools/sdk/include/asio/asio/detail/null_signal_blocker.hpp
tools/sdk/include/asio/asio/detail/null_socket_service.hpp
tools/sdk/include/asio/asio/detail/null_static_mutex.hpp
tools/sdk/include/asio/asio/detail/null_thread.hpp
tools/sdk/include/asio/asio/detail/null_tss_ptr.hpp
tools/sdk/include/asio/asio/detail/object_pool.hpp
tools/sdk/include/asio/asio/detail/old_win_sdk_compat.hpp
tools/sdk/include/asio/asio/detail/op_queue.hpp
tools/sdk/include/asio/asio/detail/operation.hpp
tools/sdk/include/asio/asio/detail/pipe_select_interrupter.hpp
tools/sdk/include/asio/asio/detail/pop_options.hpp
tools/sdk/include/asio/asio/detail/posix_event.hpp
tools/sdk/include/asio/asio/detail/posix_fd_set_adapter.hpp
tools/sdk/include/asio/asio/detail/posix_global.hpp
tools/sdk/include/asio/asio/detail/posix_mutex.hpp
tools/sdk/include/asio/asio/detail/posix_signal_blocker.hpp
tools/sdk/include/asio/asio/detail/posix_static_mutex.hpp
tools/sdk/include/asio/asio/detail/posix_thread.hpp
tools/sdk/include/asio/asio/detail/posix_tss_ptr.hpp
tools/sdk/include/asio/asio/detail/push_options.hpp
tools/sdk/include/asio/asio/detail/reactive_descriptor_service.hpp
tools/sdk/include/asio/asio/detail/reactive_null_buffers_op.hpp
tools/sdk/include/asio/asio/detail/reactive_serial_port_service.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_accept_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_connect_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_recv_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_recvfrom_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_recvmsg_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_send_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_sendto_op.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_service.hpp
tools/sdk/include/asio/asio/detail/reactive_socket_service_base.hpp
tools/sdk/include/asio/asio/detail/reactive_wait_op.hpp
tools/sdk/include/asio/asio/detail/reactor.hpp
tools/sdk/include/asio/asio/detail/reactor_fwd.hpp
tools/sdk/include/asio/asio/detail/reactor_op.hpp
tools/sdk/include/asio/asio/detail/reactor_op_queue.hpp
tools/sdk/include/asio/asio/detail/recycling_allocator.hpp
tools/sdk/include/asio/asio/detail/regex_fwd.hpp
tools/sdk/include/asio/asio/detail/resolve_endpoint_op.hpp
tools/sdk/include/asio/asio/detail/resolve_op.hpp
tools/sdk/include/asio/asio/detail/resolve_query_op.hpp
tools/sdk/include/asio/asio/detail/resolver_service.hpp
tools/sdk/include/asio/asio/detail/resolver_service_base.hpp
tools/sdk/include/asio/asio/detail/scheduler.hpp
tools/sdk/include/asio/asio/detail/scheduler_operation.hpp
tools/sdk/include/asio/asio/detail/scheduler_thread_info.hpp
tools/sdk/include/asio/asio/detail/scoped_lock.hpp
tools/sdk/include/asio/asio/detail/scoped_ptr.hpp
tools/sdk/include/asio/asio/detail/select_interrupter.hpp
tools/sdk/include/asio/asio/detail/select_reactor.hpp
tools/sdk/include/asio/asio/detail/service_registry.hpp
tools/sdk/include/asio/asio/detail/signal_blocker.hpp
tools/sdk/include/asio/asio/detail/signal_handler.hpp
tools/sdk/include/asio/asio/detail/signal_init.hpp
tools/sdk/include/asio/asio/detail/signal_op.hpp
tools/sdk/include/asio/asio/detail/signal_set_service.hpp
tools/sdk/include/asio/asio/detail/socket_holder.hpp
tools/sdk/include/asio/asio/detail/socket_ops.hpp
tools/sdk/include/asio/asio/detail/socket_option.hpp
tools/sdk/include/asio/asio/detail/socket_select_interrupter.hpp
tools/sdk/include/asio/asio/detail/socket_types.hpp
tools/sdk/include/asio/asio/detail/solaris_fenced_block.hpp
tools/sdk/include/asio/asio/detail/static_mutex.hpp
tools/sdk/include/asio/asio/detail/std_event.hpp
tools/sdk/include/asio/asio/detail/std_fenced_block.hpp
tools/sdk/include/asio/asio/detail/std_global.hpp
tools/sdk/include/asio/asio/detail/std_mutex.hpp
tools/sdk/include/asio/asio/detail/std_static_mutex.hpp
tools/sdk/include/asio/asio/detail/std_thread.hpp
tools/sdk/include/asio/asio/detail/strand_executor_service.hpp
tools/sdk/include/asio/asio/detail/strand_service.hpp
tools/sdk/include/asio/asio/detail/string_view.hpp
tools/sdk/include/asio/asio/detail/thread.hpp
tools/sdk/include/asio/asio/detail/thread_context.hpp
tools/sdk/include/asio/asio/detail/thread_group.hpp
tools/sdk/include/asio/asio/detail/thread_info_base.hpp
tools/sdk/include/asio/asio/detail/throw_error.hpp
tools/sdk/include/asio/asio/detail/throw_exception.hpp
tools/sdk/include/asio/asio/detail/timer_queue.hpp
tools/sdk/include/asio/asio/detail/timer_queue_base.hpp
tools/sdk/include/asio/asio/detail/timer_queue_ptime.hpp
tools/sdk/include/asio/asio/detail/timer_queue_set.hpp
tools/sdk/include/asio/asio/detail/timer_scheduler.hpp
tools/sdk/include/asio/asio/detail/timer_scheduler_fwd.hpp
tools/sdk/include/asio/asio/detail/tss_ptr.hpp
tools/sdk/include/asio/asio/detail/type_traits.hpp
tools/sdk/include/asio/asio/detail/variadic_templates.hpp
tools/sdk/include/asio/asio/detail/wait_handler.hpp
tools/sdk/include/asio/asio/detail/wait_op.hpp
tools/sdk/include/asio/asio/detail/win_event.hpp
tools/sdk/include/asio/asio/detail/win_fd_set_adapter.hpp
tools/sdk/include/asio/asio/detail/win_fenced_block.hpp
tools/sdk/include/asio/asio/detail/win_global.hpp
tools/sdk/include/asio/asio/detail/win_iocp_handle_read_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_handle_service.hpp
tools/sdk/include/asio/asio/detail/win_iocp_handle_write_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_io_context.hpp
tools/sdk/include/asio/asio/detail/win_iocp_null_buffers_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_operation.hpp
tools/sdk/include/asio/asio/detail/win_iocp_overlapped_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_overlapped_ptr.hpp
tools/sdk/include/asio/asio/detail/win_iocp_serial_port_service.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_accept_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_connect_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_recv_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_recvmsg_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_send_op.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_service.hpp
tools/sdk/include/asio/asio/detail/win_iocp_socket_service_base.hpp
tools/sdk/include/asio/asio/detail/win_iocp_thread_info.hpp
tools/sdk/include/asio/asio/detail/win_iocp_wait_op.hpp
tools/sdk/include/asio/asio/detail/win_mutex.hpp
tools/sdk/include/asio/asio/detail/win_object_handle_service.hpp
tools/sdk/include/asio/asio/detail/win_static_mutex.hpp
tools/sdk/include/asio/asio/detail/win_thread.hpp
tools/sdk/include/asio/asio/detail/win_tss_ptr.hpp
tools/sdk/include/asio/asio/detail/winapp_thread.hpp
tools/sdk/include/asio/asio/detail/wince_thread.hpp
tools/sdk/include/asio/asio/detail/winrt_async_manager.hpp
tools/sdk/include/asio/asio/detail/winrt_async_op.hpp
tools/sdk/include/asio/asio/detail/winrt_resolve_op.hpp
tools/sdk/include/asio/asio/detail/winrt_resolver_service.hpp
tools/sdk/include/asio/asio/detail/winrt_socket_connect_op.hpp
tools/sdk/include/asio/asio/detail/winrt_socket_recv_op.hpp
tools/sdk/include/asio/asio/detail/winrt_socket_send_op.hpp
tools/sdk/include/asio/asio/detail/winrt_ssocket_service.hpp
tools/sdk/include/asio/asio/detail/winrt_ssocket_service_base.hpp
tools/sdk/include/asio/asio/detail/winrt_timer_scheduler.hpp
tools/sdk/include/asio/asio/detail/winrt_utils.hpp
tools/sdk/include/asio/asio/detail/winsock_init.hpp
tools/sdk/include/asio/asio/detail/work_dispatcher.hpp
tools/sdk/include/asio/asio/detail/wrapped_handler.hpp
tools/sdk/include/asio/asio/dispatch.hpp
tools/sdk/include/asio/asio/error.hpp
tools/sdk/include/asio/asio/error_code.hpp
tools/sdk/include/asio/asio/execution_context.hpp
tools/sdk/include/asio/asio/executor.hpp
tools/sdk/include/asio/asio/executor_work_guard.hpp
tools/sdk/include/asio/asio/experimental.hpp
tools/sdk/include/asio/asio/experimental/co_spawn.hpp
tools/sdk/include/asio/asio/experimental/detached.hpp
tools/sdk/include/asio/asio/experimental/impl/co_spawn.hpp
tools/sdk/include/asio/asio/experimental/impl/detached.hpp
tools/sdk/include/asio/asio/experimental/impl/redirect_error.hpp
tools/sdk/include/asio/asio/experimental/redirect_error.hpp
tools/sdk/include/asio/asio/generic/basic_endpoint.hpp
tools/sdk/include/asio/asio/generic/datagram_protocol.hpp
tools/sdk/include/asio/asio/generic/detail/endpoint.hpp
tools/sdk/include/asio/asio/generic/raw_protocol.hpp
tools/sdk/include/asio/asio/generic/seq_packet_protocol.hpp
tools/sdk/include/asio/asio/generic/stream_protocol.hpp
tools/sdk/include/asio/asio/handler_alloc_hook.hpp
tools/sdk/include/asio/asio/handler_continuation_hook.hpp
tools/sdk/include/asio/asio/handler_invoke_hook.hpp
tools/sdk/include/asio/asio/handler_type.hpp
tools/sdk/include/asio/asio/high_resolution_timer.hpp
tools/sdk/include/asio/asio/impl/buffered_read_stream.hpp
tools/sdk/include/asio/asio/impl/buffered_write_stream.hpp
tools/sdk/include/asio/asio/impl/connect.hpp
tools/sdk/include/asio/asio/impl/defer.hpp
tools/sdk/include/asio/asio/impl/dispatch.hpp
tools/sdk/include/asio/asio/impl/execution_context.hpp
tools/sdk/include/asio/asio/impl/executor.hpp
tools/sdk/include/asio/asio/impl/io_context.hpp
tools/sdk/include/asio/asio/impl/post.hpp
tools/sdk/include/asio/asio/impl/read.hpp
tools/sdk/include/asio/asio/impl/read_at.hpp
tools/sdk/include/asio/asio/impl/read_until.hpp
tools/sdk/include/asio/asio/impl/serial_port_base.hpp
tools/sdk/include/asio/asio/impl/spawn.hpp
tools/sdk/include/asio/asio/impl/src.hpp
tools/sdk/include/asio/asio/impl/system_context.hpp
tools/sdk/include/asio/asio/impl/system_executor.hpp
tools/sdk/include/asio/asio/impl/thread_pool.hpp
tools/sdk/include/asio/asio/impl/use_future.hpp
tools/sdk/include/asio/asio/impl/write.hpp
tools/sdk/include/asio/asio/impl/write_at.hpp
tools/sdk/include/asio/asio/io_context.hpp
tools/sdk/include/asio/asio/io_context_strand.hpp
tools/sdk/include/asio/asio/io_service.hpp
tools/sdk/include/asio/asio/io_service_strand.hpp
tools/sdk/include/asio/asio/ip/address.hpp
tools/sdk/include/asio/asio/ip/address_v4.hpp
tools/sdk/include/asio/asio/ip/address_v4_iterator.hpp
tools/sdk/include/asio/asio/ip/address_v4_range.hpp
tools/sdk/include/asio/asio/ip/address_v6.hpp
tools/sdk/include/asio/asio/ip/address_v6_iterator.hpp
tools/sdk/include/asio/asio/ip/address_v6_range.hpp
tools/sdk/include/asio/asio/ip/bad_address_cast.hpp
tools/sdk/include/asio/asio/ip/basic_endpoint.hpp
tools/sdk/include/asio/asio/ip/basic_resolver.hpp
tools/sdk/include/asio/asio/ip/basic_resolver_entry.hpp
tools/sdk/include/asio/asio/ip/basic_resolver_iterator.hpp
tools/sdk/include/asio/asio/ip/basic_resolver_query.hpp
tools/sdk/include/asio/asio/ip/basic_resolver_results.hpp
tools/sdk/include/asio/asio/ip/detail/endpoint.hpp
tools/sdk/include/asio/asio/ip/detail/socket_option.hpp
tools/sdk/include/asio/asio/ip/host_name.hpp
tools/sdk/include/asio/asio/ip/icmp.hpp
tools/sdk/include/asio/asio/ip/impl/address.hpp
tools/sdk/include/asio/asio/ip/impl/address_v4.hpp
tools/sdk/include/asio/asio/ip/impl/address_v6.hpp
tools/sdk/include/asio/asio/ip/impl/basic_endpoint.hpp
tools/sdk/include/asio/asio/ip/impl/network_v4.hpp
tools/sdk/include/asio/asio/ip/impl/network_v6.hpp
tools/sdk/include/asio/asio/ip/multicast.hpp
tools/sdk/include/asio/asio/ip/network_v4.hpp
tools/sdk/include/asio/asio/ip/network_v6.hpp
tools/sdk/include/asio/asio/ip/resolver_base.hpp
tools/sdk/include/asio/asio/ip/resolver_query_base.hpp
tools/sdk/include/asio/asio/ip/resolver_service.hpp
tools/sdk/include/asio/asio/ip/tcp.hpp
tools/sdk/include/asio/asio/ip/udp.hpp
tools/sdk/include/asio/asio/ip/unicast.hpp
tools/sdk/include/asio/asio/ip/v6_only.hpp
tools/sdk/include/asio/asio/is_executor.hpp
tools/sdk/include/asio/asio/is_read_buffered.hpp
tools/sdk/include/asio/asio/is_write_buffered.hpp
tools/sdk/include/asio/asio/local/basic_endpoint.hpp
tools/sdk/include/asio/asio/local/connect_pair.hpp
tools/sdk/include/asio/asio/local/datagram_protocol.hpp
tools/sdk/include/asio/asio/local/detail/endpoint.hpp
tools/sdk/include/asio/asio/local/stream_protocol.hpp
tools/sdk/include/asio/asio/packaged_task.hpp
tools/sdk/include/asio/asio/placeholders.hpp
tools/sdk/include/asio/asio/posix/basic_descriptor.hpp
tools/sdk/include/asio/asio/posix/basic_stream_descriptor.hpp
tools/sdk/include/asio/asio/posix/descriptor.hpp
tools/sdk/include/asio/asio/posix/descriptor_base.hpp
tools/sdk/include/asio/asio/posix/stream_descriptor.hpp
tools/sdk/include/asio/asio/posix/stream_descriptor_service.hpp
tools/sdk/include/asio/asio/post.hpp
tools/sdk/include/asio/asio/raw_socket_service.hpp
tools/sdk/include/asio/asio/read.hpp
tools/sdk/include/asio/asio/read_at.hpp
tools/sdk/include/asio/asio/read_until.hpp
tools/sdk/include/asio/asio/seq_packet_socket_service.hpp
tools/sdk/include/asio/asio/serial_port.hpp
tools/sdk/include/asio/asio/serial_port_base.hpp
tools/sdk/include/asio/asio/serial_port_service.hpp
tools/sdk/include/asio/asio/signal_set.hpp
tools/sdk/include/asio/asio/signal_set_service.hpp
tools/sdk/include/asio/asio/socket_acceptor_service.hpp
tools/sdk/include/asio/asio/socket_base.hpp
tools/sdk/include/asio/asio/spawn.hpp
tools/sdk/include/asio/asio/ssl.hpp
tools/sdk/include/asio/asio/ssl/context.hpp
tools/sdk/include/asio/asio/ssl/context_base.hpp
tools/sdk/include/asio/asio/ssl/detail/buffered_handshake_op.hpp
tools/sdk/include/asio/asio/ssl/detail/engine.hpp
tools/sdk/include/asio/asio/ssl/detail/handshake_op.hpp
tools/sdk/include/asio/asio/ssl/detail/io.hpp
tools/sdk/include/asio/asio/ssl/detail/openssl_init.hpp
tools/sdk/include/asio/asio/ssl/detail/openssl_types.hpp
tools/sdk/include/asio/asio/ssl/detail/password_callback.hpp
tools/sdk/include/asio/asio/ssl/detail/read_op.hpp
tools/sdk/include/asio/asio/ssl/detail/shutdown_op.hpp
tools/sdk/include/asio/asio/ssl/detail/stream_core.hpp
tools/sdk/include/asio/asio/ssl/detail/verify_callback.hpp
tools/sdk/include/asio/asio/ssl/detail/write_op.hpp
tools/sdk/include/asio/asio/ssl/error.hpp
tools/sdk/include/asio/asio/ssl/impl/context.hpp
tools/sdk/include/asio/asio/ssl/impl/src.hpp
tools/sdk/include/asio/asio/ssl/rfc2818_verification.hpp
tools/sdk/include/asio/asio/ssl/stream.hpp
tools/sdk/include/asio/asio/ssl/stream_base.hpp
tools/sdk/include/asio/asio/ssl/verify_context.hpp
tools/sdk/include/asio/asio/ssl/verify_mode.hpp
tools/sdk/include/asio/asio/steady_timer.hpp
tools/sdk/include/asio/asio/strand.hpp
tools/sdk/include/asio/asio/stream_socket_service.hpp
tools/sdk/include/asio/asio/streambuf.hpp
tools/sdk/include/asio/asio/system_context.hpp
tools/sdk/include/asio/asio/system_error.hpp
tools/sdk/include/asio/asio/system_executor.hpp
tools/sdk/include/asio/asio/system_timer.hpp
tools/sdk/include/asio/asio/thread.hpp
tools/sdk/include/asio/asio/thread_pool.hpp
tools/sdk/include/asio/asio/time_traits.hpp
tools/sdk/include/asio/asio/ts/buffer.hpp
tools/sdk/include/asio/asio/ts/executor.hpp
tools/sdk/include/asio/asio/ts/internet.hpp
tools/sdk/include/asio/asio/ts/io_context.hpp
tools/sdk/include/asio/asio/ts/net.hpp
tools/sdk/include/asio/asio/ts/netfwd.hpp
tools/sdk/include/asio/asio/ts/socket.hpp
tools/sdk/include/asio/asio/ts/timer.hpp
tools/sdk/include/asio/asio/unyield.hpp
tools/sdk/include/asio/asio/use_future.hpp
tools/sdk/include/asio/asio/uses_executor.hpp
tools/sdk/include/asio/asio/version.hpp
tools/sdk/include/asio/asio/wait_traits.hpp
tools/sdk/include/asio/asio/waitable_timer_service.hpp
tools/sdk/include/asio/asio/windows/basic_handle.hpp
tools/sdk/include/asio/asio/windows/basic_object_handle.hpp
tools/sdk/include/asio/asio/windows/basic_random_access_handle.hpp
tools/sdk/include/asio/asio/windows/basic_stream_handle.hpp
tools/sdk/include/asio/asio/windows/object_handle.hpp
tools/sdk/include/asio/asio/windows/object_handle_service.hpp
tools/sdk/include/asio/asio/windows/overlapped_handle.hpp
tools/sdk/include/asio/asio/windows/overlapped_ptr.hpp
tools/sdk/include/asio/asio/windows/random_access_handle.hpp
tools/sdk/include/asio/asio/windows/random_access_handle_service.hpp
tools/sdk/include/asio/asio/windows/stream_handle.hpp
tools/sdk/include/asio/asio/windows/stream_handle_service.hpp
tools/sdk/include/asio/asio/write.hpp
tools/sdk/include/asio/asio/write_at.hpp
tools/sdk/include/asio/asio/yield.hpp
tools/sdk/include/asio/esp_asio_config.h
tools/sdk/include/asio/esp_exception.h
tools/sdk/include/bootloader_support/bootloader_clock.h
tools/sdk/include/bootloader_support/bootloader_common.h
tools/sdk/include/bootloader_support/bootloader_random.h
tools/sdk/include/bootloader_support/bootloader_util.h
tools/sdk/include/bootloader_support/esp_efuse.h
tools/sdk/include/bootloader_support/esp_flash_encrypt.h
tools/sdk/include/bootloader_support/esp_flash_partitions.h
tools/sdk/include/bootloader_support/esp_image_format.h
tools/sdk/include/bootloader_support/esp_secure_boot.h
tools/sdk/include/bt/bt.h
tools/sdk/include/bt/esp_a2dp_api.h
tools/sdk/include/bt/esp_avrc_api.h
tools/sdk/include/bt/esp_blufi_api.h
tools/sdk/include/bt/esp_bt.h
tools/sdk/include/bt/esp_bt_defs.h
tools/sdk/include/bt/esp_bt_device.h
tools/sdk/include/bt/esp_bt_main.h
tools/sdk/include/bt/esp_gap_ble_api.h
tools/sdk/include/bt/esp_gap_bt_api.h
tools/sdk/include/bt/esp_gatt_common_api.h
tools/sdk/include/bt/esp_gatt_defs.h
tools/sdk/include/bt/esp_gattc_api.h
tools/sdk/include/bt/esp_gatts_api.h
tools/sdk/include/bt/esp_hf_client_api.h
tools/sdk/include/bt/esp_hf_defs.h
tools/sdk/include/bt/esp_spp_api.h
tools/sdk/include/coap/address.h
tools/sdk/include/coap/async.h
tools/sdk/include/coap/bits.h
tools/sdk/include/coap/block.h
tools/sdk/include/coap/coap.h
tools/sdk/include/coap/coap/address.h
tools/sdk/include/coap/coap/async.h
tools/sdk/include/coap/coap/bits.h
tools/sdk/include/coap/coap/block.h
tools/sdk/include/coap/coap/coap.h
tools/sdk/include/coap/coap/coap_io.h
tools/sdk/include/coap/coap/coap_time.h
tools/sdk/include/coap/coap/debug.h
tools/sdk/include/coap/coap/encode.h
tools/sdk/include/coap/coap/hashkey.h
tools/sdk/include/coap/coap/libcoap.h
tools/sdk/include/coap/coap/lwippools.h
tools/sdk/include/coap/coap/mem.h
tools/sdk/include/coap/coap/net.h
tools/sdk/include/coap/coap/option.h
tools/sdk/include/coap/coap/pdu.h
tools/sdk/include/coap/coap/prng.h
tools/sdk/include/coap/coap/resource.h
tools/sdk/include/coap/coap/str.h
tools/sdk/include/coap/coap/subscribe.h
tools/sdk/include/coap/coap/uri.h
tools/sdk/include/coap/coap/uthash.h
tools/sdk/include/coap/coap/utlist.h
tools/sdk/include/coap/coap_config.h
tools/sdk/include/coap/coap_config_posix.h
tools/sdk/include/coap/coap_io.h
tools/sdk/include/coap/coap_time.h
tools/sdk/include/coap/debug.h
tools/sdk/include/coap/encode.h
tools/sdk/include/coap/hashkey.h
tools/sdk/include/coap/libcoap.h
tools/sdk/include/coap/lwippools.h
tools/sdk/include/coap/mem.h
tools/sdk/include/coap/net.h
tools/sdk/include/coap/option.h
tools/sdk/include/coap/pdu.h
tools/sdk/include/coap/prng.h
tools/sdk/include/coap/resource.h
tools/sdk/include/coap/str.h
tools/sdk/include/coap/subscribe.h
tools/sdk/include/coap/uri.h
tools/sdk/include/coap/uthash.h
tools/sdk/include/coap/utlist.h
tools/sdk/include/config/sdkconfig.h
tools/sdk/include/console/argtable3/argtable3.h
tools/sdk/include/console/esp_console.h
tools/sdk/include/console/linenoise/linenoise.h
tools/sdk/include/driver/driver/adc.h
tools/sdk/include/driver/driver/adc2_wifi_internal.h
tools/sdk/include/driver/driver/can.h
tools/sdk/include/driver/driver/dac.h
tools/sdk/include/driver/driver/gpio.h
tools/sdk/include/driver/driver/i2c.h
tools/sdk/include/driver/driver/i2s.h
tools/sdk/include/driver/driver/ledc.h
tools/sdk/include/driver/driver/mcpwm.h
tools/sdk/include/driver/driver/pcnt.h
tools/sdk/include/driver/driver/periph_ctrl.h
tools/sdk/include/driver/driver/rmt.h
tools/sdk/include/driver/driver/rtc_cntl.h
tools/sdk/include/driver/driver/rtc_io.h
tools/sdk/include/driver/driver/sdio_slave.h
tools/sdk/include/driver/driver/sdmmc_defs.h
tools/sdk/include/driver/driver/sdmmc_host.h
tools/sdk/include/driver/driver/sdmmc_types.h
tools/sdk/include/driver/driver/sdspi_host.h
tools/sdk/include/driver/driver/sigmadelta.h
tools/sdk/include/driver/driver/spi_common.h
tools/sdk/include/driver/driver/spi_master.h
tools/sdk/include/driver/driver/spi_slave.h
tools/sdk/include/driver/driver/timer.h
tools/sdk/include/driver/driver/touch_pad.h
tools/sdk/include/driver/driver/uart.h
tools/sdk/include/driver/driver/uart_select.h
tools/sdk/include/esp-face/dl_lib_matrix3d.h
tools/sdk/include/esp-face/dl_lib_matrix3dq.h
tools/sdk/include/esp-face/fd_forward.h
tools/sdk/include/esp-face/fr_flash.h
tools/sdk/include/esp-face/fr_forward.h
tools/sdk/include/esp-face/frmn.h
tools/sdk/include/esp-face/image_util.h
tools/sdk/include/esp-face/mtmn.h
tools/sdk/include/esp-tls/esp_tls.h
tools/sdk/include/esp32-camera/esp_camera.h
tools/sdk/include/esp32-camera/esp_jpg_decode.h
tools/sdk/include/esp32-camera/img_converters.h
tools/sdk/include/esp32-camera/sensor.h
tools/sdk/include/esp32/esp32/pm.h
tools/sdk/include/esp32/esp_assert.h
tools/sdk/include/esp32/esp_attr.h
tools/sdk/include/esp32/esp_brownout.h
tools/sdk/include/esp32/esp_cache_err_int.h
tools/sdk/include/esp32/esp_clk.h
tools/sdk/include/esp32/esp_coexist.h
tools/sdk/include/esp32/esp_coexist_adapter.h
tools/sdk/include/esp32/esp_coexist_internal.h
tools/sdk/include/esp32/esp_core_dump.h
tools/sdk/include/esp32/esp_crosscore_int.h
tools/sdk/include/esp32/esp_dbg_stubs.h
tools/sdk/include/esp32/esp_deep_sleep.h
tools/sdk/include/esp32/esp_deepsleep.h
tools/sdk/include/esp32/esp_dport_access.h
tools/sdk/include/esp32/esp_err.h
tools/sdk/include/esp32/esp_event_legacy.h
tools/sdk/include/esp32/esp_event_loop.h
tools/sdk/include/esp32/esp_flash_data_types.h
tools/sdk/include/esp32/esp_freertos_hooks.h
tools/sdk/include/esp32/esp_gdbstub.h
tools/sdk/include/esp32/esp_himem.h
tools/sdk/include/esp32/esp_int_wdt.h
tools/sdk/include/esp32/esp_interface.h
tools/sdk/include/esp32/esp_intr.h
tools/sdk/include/esp32/esp_intr_alloc.h
tools/sdk/include/esp32/esp_ipc.h
tools/sdk/include/esp32/esp_mesh.h
tools/sdk/include/esp32/esp_mesh_internal.h
tools/sdk/include/esp32/esp_now.h
tools/sdk/include/esp32/esp_panic.h
tools/sdk/include/esp32/esp_phy_init.h
tools/sdk/include/esp32/esp_pm.h
tools/sdk/include/esp32/esp_sleep.h
tools/sdk/include/esp32/esp_smartconfig.h
tools/sdk/include/esp32/esp_spiram.h
tools/sdk/include/esp32/esp_ssc.h
tools/sdk/include/esp32/esp_system.h
tools/sdk/include/esp32/esp_task.h
tools/sdk/include/esp32/esp_task_wdt.h
tools/sdk/include/esp32/esp_timer.h
tools/sdk/include/esp32/esp_types.h
tools/sdk/include/esp32/esp_wifi.h
tools/sdk/include/esp32/esp_wifi_crypto_types.h
tools/sdk/include/esp32/esp_wifi_internal.h
tools/sdk/include/esp32/esp_wifi_os_adapter.h
tools/sdk/include/esp32/esp_wifi_types.h
tools/sdk/include/esp32/esp_wpa2.h
tools/sdk/include/esp32/esp_wps.h
tools/sdk/include/esp32/hwcrypto/aes.h
tools/sdk/include/esp32/hwcrypto/sha.h
tools/sdk/include/esp32/rom/aes.h
tools/sdk/include/esp32/rom/bigint.h
tools/sdk/include/esp32/rom/cache.h
tools/sdk/include/esp32/rom/crc.h
tools/sdk/include/esp32/rom/efuse.h
tools/sdk/include/esp32/rom/ets_sys.h
tools/sdk/include/esp32/rom/gpio.h
tools/sdk/include/esp32/rom/libc_stubs.h
tools/sdk/include/esp32/rom/lldesc.h
tools/sdk/include/esp32/rom/md5_hash.h
tools/sdk/include/esp32/rom/miniz.h
tools/sdk/include/esp32/rom/queue.h
tools/sdk/include/esp32/rom/rtc.h
tools/sdk/include/esp32/rom/secure_boot.h
tools/sdk/include/esp32/rom/sha.h
tools/sdk/include/esp32/rom/spi_flash.h
tools/sdk/include/esp32/rom/tbconsole.h
tools/sdk/include/esp32/rom/tjpgd.h
tools/sdk/include/esp32/rom/uart.h
tools/sdk/include/esp32/xtensa/cacheasm.h
tools/sdk/include/esp32/xtensa/cacheattrasm.h
tools/sdk/include/esp32/xtensa/config/core-isa.h
tools/sdk/include/esp32/xtensa/config/core-matmap.h
tools/sdk/include/esp32/xtensa/config/core.h
tools/sdk/include/esp32/xtensa/config/defs.h
tools/sdk/include/esp32/xtensa/config/specreg.h
tools/sdk/include/esp32/xtensa/config/system.h
tools/sdk/include/esp32/xtensa/config/tie-asm.h
tools/sdk/include/esp32/xtensa/config/tie.h
tools/sdk/include/esp32/xtensa/core-macros.h
tools/sdk/include/esp32/xtensa/coreasm.h
tools/sdk/include/esp32/xtensa/corebits.h
tools/sdk/include/esp32/xtensa/hal.h
tools/sdk/include/esp32/xtensa/specreg.h
tools/sdk/include/esp32/xtensa/traxreg.h
tools/sdk/include/esp32/xtensa/xdm-regs.h
tools/sdk/include/esp32/xtensa/xt_perf_consts.h
tools/sdk/include/esp32/xtensa/xtensa-libdb-macros.h
tools/sdk/include/esp32/xtensa/xtensa-versions.h
tools/sdk/include/esp32/xtensa/xtensa-xer.h
tools/sdk/include/esp32/xtensa/xtruntime-core-state.h
tools/sdk/include/esp32/xtensa/xtruntime-frames.h
tools/sdk/include/esp32/xtensa/xtruntime.h
tools/sdk/include/esp_adc_cal/esp_adc_cal.h
tools/sdk/include/esp_event/esp_event.h
tools/sdk/include/esp_event/esp_event_base.h
tools/sdk/include/esp_http_client/esp_http_client.h
tools/sdk/include/esp_http_server/esp_http_server.h
tools/sdk/include/esp_http_server/http_server.h
tools/sdk/include/esp_https_ota/esp_https_ota.h
tools/sdk/include/esp_ringbuf/freertos/ringbuf.h
tools/sdk/include/ethernet/esp_eth.h
tools/sdk/include/ethernet/eth_phy/phy.h
tools/sdk/include/ethernet/eth_phy/phy_ip101.h
tools/sdk/include/ethernet/eth_phy/phy_lan8720.h
tools/sdk/include/ethernet/eth_phy/phy_reg.h
tools/sdk/include/ethernet/eth_phy/phy_tlk110.h
tools/sdk/include/expat/ascii.h
tools/sdk/include/expat/asciitab.h
tools/sdk/include/expat/expat.h
tools/sdk/include/expat/expat_config.h
tools/sdk/include/expat/expat_external.h
tools/sdk/include/expat/iasciitab.h
tools/sdk/include/expat/internal.h
tools/sdk/include/expat/latin1tab.h
tools/sdk/include/expat/nametab.h
tools/sdk/include/expat/siphash.h
tools/sdk/include/expat/utf8tab.h
tools/sdk/include/expat/winconfig.h
tools/sdk/include/expat/xmlrole.h
tools/sdk/include/expat/xmltok.h
tools/sdk/include/expat/xmltok_impl.h
tools/sdk/include/fatfs/diskio.h
tools/sdk/include/fatfs/diskio_rawflash.h
tools/sdk/include/fatfs/diskio_wl.h
tools/sdk/include/fatfs/esp_vfs_fat.h
tools/sdk/include/fatfs/ff.h
tools/sdk/include/fatfs/ffconf.h
tools/sdk/include/fatfs/integer.h
tools/sdk/include/fatfs/vfs_fat_internal.h
tools/sdk/include/fb_gfx/fb_gfx.h
tools/sdk/include/freemodbus/mb.h
tools/sdk/include/freemodbus/mbconfig.h
tools/sdk/include/freemodbus/mbcontroller.h
tools/sdk/include/freemodbus/mbframe.h
tools/sdk/include/freemodbus/mbfunc.h
tools/sdk/include/freemodbus/mbport.h
tools/sdk/include/freemodbus/mbproto.h
tools/sdk/include/freemodbus/mbutils.h
tools/sdk/include/freertos/freertos/FreeRTOS.h
tools/sdk/include/freertos/freertos/FreeRTOSConfig.h
tools/sdk/include/freertos/freertos/StackMacros.h
tools/sdk/include/freertos/freertos/croutine.h
tools/sdk/include/freertos/freertos/deprecated_definitions.h
tools/sdk/include/freertos/freertos/event_groups.h
tools/sdk/include/freertos/freertos/list.h
tools/sdk/include/freertos/freertos/mpu_wrappers.h
tools/sdk/include/freertos/freertos/portable.h
tools/sdk/include/freertos/freertos/portbenchmark.h
tools/sdk/include/freertos/freertos/portmacro.h
tools/sdk/include/freertos/freertos/porttrace.h
tools/sdk/include/freertos/freertos/projdefs.h
tools/sdk/include/freertos/freertos/queue.h
tools/sdk/include/freertos/freertos/semphr.h
tools/sdk/include/freertos/freertos/task.h
tools/sdk/include/freertos/freertos/timers.h
tools/sdk/include/freertos/freertos/xtensa_api.h
tools/sdk/include/freertos/freertos/xtensa_config.h
tools/sdk/include/freertos/freertos/xtensa_context.h
tools/sdk/include/freertos/freertos/xtensa_rtos.h
tools/sdk/include/freertos/freertos/xtensa_timer.h
tools/sdk/include/heap/esp_heap_alloc_caps.h
tools/sdk/include/heap/esp_heap_caps.h
tools/sdk/include/heap/esp_heap_caps_init.h
tools/sdk/include/heap/esp_heap_task_info.h
tools/sdk/include/heap/esp_heap_trace.h
tools/sdk/include/heap/multi_heap.h
tools/sdk/include/idf_test/idf_performance.h
tools/sdk/include/jsmn/jsmn.h
tools/sdk/include/json/cJSON.h
tools/sdk/include/json/cJSON_Utils.h
tools/sdk/include/json/tests/common.h
tools/sdk/include/json/tests/unity/examples/example_1/src/ProductionCode.h
tools/sdk/include/json/tests/unity/examples/example_1/src/ProductionCode2.h
tools/sdk/include/json/tests/unity/examples/example_2/src/ProductionCode.h
tools/sdk/include/json/tests/unity/examples/example_2/src/ProductionCode2.h
tools/sdk/include/json/tests/unity/examples/example_3/helper/UnityHelper.h
tools/sdk/include/json/tests/unity/examples/example_3/src/ProductionCode.h
tools/sdk/include/json/tests/unity/examples/example_3/src/ProductionCode2.h
tools/sdk/include/json/tests/unity/examples/unity_config.h
tools/sdk/include/json/tests/unity/extras/fixture/src/unity_fixture.h
tools/sdk/include/json/tests/unity/extras/fixture/src/unity_fixture_internals.h
tools/sdk/include/json/tests/unity/extras/fixture/src/unity_fixture_malloc_overrides.h
tools/sdk/include/json/tests/unity/extras/fixture/test/unity_output_Spy.h
tools/sdk/include/json/tests/unity/src/unity.h
tools/sdk/include/json/tests/unity/src/unity_internals.h
tools/sdk/include/json/tests/unity/test/expectdata/testsample_head1.h
tools/sdk/include/json/tests/unity/test/expectdata/testsample_mock_head1.h
tools/sdk/include/json/tests/unity/test/testdata/CException.h
tools/sdk/include/json/tests/unity/test/testdata/Defs.h
tools/sdk/include/json/tests/unity/test/testdata/cmock.h
tools/sdk/include/json/tests/unity/test/testdata/mockMock.h
tools/sdk/include/libsodium/sodium.h
tools/sdk/include/libsodium/sodium/core.h
tools/sdk/include/libsodium/sodium/crypto_aead_aes256gcm.h
tools/sdk/include/libsodium/sodium/crypto_aead_chacha20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_auth.h
tools/sdk/include/libsodium/sodium/crypto_auth_hmacsha256.h
tools/sdk/include/libsodium/sodium/crypto_auth_hmacsha512.h
tools/sdk/include/libsodium/sodium/crypto_auth_hmacsha512256.h
tools/sdk/include/libsodium/sodium/crypto_box.h
tools/sdk/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_core_hchacha20.h
tools/sdk/include/libsodium/sodium/crypto_core_hsalsa20.h
tools/sdk/include/libsodium/sodium/crypto_core_salsa20.h
tools/sdk/include/libsodium/sodium/crypto_core_salsa2012.h
tools/sdk/include/libsodium/sodium/crypto_core_salsa208.h
tools/sdk/include/libsodium/sodium/crypto_generichash.h
tools/sdk/include/libsodium/sodium/crypto_generichash_blake2b.h
tools/sdk/include/libsodium/sodium/crypto_hash.h
tools/sdk/include/libsodium/sodium/crypto_hash_sha256.h
tools/sdk/include/libsodium/sodium/crypto_hash_sha512.h
tools/sdk/include/libsodium/sodium/crypto_kdf.h
tools/sdk/include/libsodium/sodium/crypto_kdf_blake2b.h
tools/sdk/include/libsodium/sodium/crypto_kx.h
tools/sdk/include/libsodium/sodium/crypto_onetimeauth.h
tools/sdk/include/libsodium/sodium/crypto_onetimeauth_poly1305.h
tools/sdk/include/libsodium/sodium/crypto_pwhash.h
tools/sdk/include/libsodium/sodium/crypto_pwhash_argon2i.h
tools/sdk/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h
tools/sdk/include/libsodium/sodium/crypto_scalarmult.h
tools/sdk/include/libsodium/sodium/crypto_scalarmult_curve25519.h
tools/sdk/include/libsodium/sodium/crypto_secretbox.h
tools/sdk/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h
tools/sdk/include/libsodium/sodium/crypto_shorthash.h
tools/sdk/include/libsodium/sodium/crypto_shorthash_siphash24.h
tools/sdk/include/libsodium/sodium/crypto_sign.h
tools/sdk/include/libsodium/sodium/crypto_sign_ed25519.h
tools/sdk/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h
tools/sdk/include/libsodium/sodium/crypto_stream.h
tools/sdk/include/libsodium/sodium/crypto_stream_aes128ctr.h
tools/sdk/include/libsodium/sodium/crypto_stream_chacha20.h
tools/sdk/include/libsodium/sodium/crypto_stream_salsa20.h
tools/sdk/include/libsodium/sodium/crypto_stream_salsa2012.h
tools/sdk/include/libsodium/sodium/crypto_stream_salsa208.h
tools/sdk/include/libsodium/sodium/crypto_stream_xchacha20.h
tools/sdk/include/libsodium/sodium/crypto_stream_xsalsa20.h
tools/sdk/include/libsodium/sodium/crypto_verify_16.h
tools/sdk/include/libsodium/sodium/crypto_verify_32.h
tools/sdk/include/libsodium/sodium/crypto_verify_64.h
tools/sdk/include/libsodium/sodium/export.h
tools/sdk/include/libsodium/sodium/private/common.h
tools/sdk/include/libsodium/sodium/private/curve25519_ref10.h
tools/sdk/include/libsodium/sodium/private/mutex.h
tools/sdk/include/libsodium/sodium/private/sse2_64_32.h
tools/sdk/include/libsodium/sodium/randombytes.h
tools/sdk/include/libsodium/sodium/randombytes_nativeclient.h
tools/sdk/include/libsodium/sodium/randombytes_salsa20_random.h
tools/sdk/include/libsodium/sodium/randombytes_sysrandom.h
tools/sdk/include/libsodium/sodium/runtime.h
tools/sdk/include/libsodium/sodium/utils.h
tools/sdk/include/libsodium/sodium/version.h
tools/sdk/include/log/esp_log.h
tools/sdk/include/log/esp_log_internal.h
tools/sdk/include/lwip/apps/sntp/sntp.h
tools/sdk/include/lwip/arch/cc.h
tools/sdk/include/lwip/arch/perf.h
tools/sdk/include/lwip/arch/sys_arch.h
tools/sdk/include/lwip/arch/vfs_lwip.h
tools/sdk/include/lwip/arpa/inet.h
tools/sdk/include/lwip/cc.h
tools/sdk/include/lwip/debug/lwip_debug.h
tools/sdk/include/lwip/dhcpserver/dhcpserver.h
tools/sdk/include/lwip/dhcpserver/dhcpserver_options.h
tools/sdk/include/lwip/esp_ping.h
tools/sdk/include/lwip/lwip/api.h
tools/sdk/include/lwip/lwip/apps/fs.h
tools/sdk/include/lwip/lwip/apps/httpd.h
tools/sdk/include/lwip/lwip/apps/httpd_opts.h
tools/sdk/include/lwip/lwip/apps/lwiperf.h
tools/sdk/include/lwip/lwip/apps/mdns.h
tools/sdk/include/lwip/lwip/apps/mdns_opts.h
tools/sdk/include/lwip/lwip/apps/mdns_priv.h
tools/sdk/include/lwip/lwip/apps/mqtt.h
tools/sdk/include/lwip/lwip/apps/mqtt_opts.h
tools/sdk/include/lwip/lwip/apps/netbiosns.h
tools/sdk/include/lwip/lwip/apps/netbiosns_opts.h
tools/sdk/include/lwip/lwip/apps/snmp.h
tools/sdk/include/lwip/lwip/apps/snmp_core.h
tools/sdk/include/lwip/lwip/apps/snmp_mib2.h
tools/sdk/include/lwip/lwip/apps/snmp_opts.h
tools/sdk/include/lwip/lwip/apps/snmp_scalar.h
tools/sdk/include/lwip/lwip/apps/snmp_table.h
tools/sdk/include/lwip/lwip/apps/snmp_threadsync.h
tools/sdk/include/lwip/lwip/apps/snmpv3.h
tools/sdk/include/lwip/lwip/apps/sntp.h
tools/sdk/include/lwip/lwip/apps/sntp_opts.h
tools/sdk/include/lwip/lwip/apps/tftp_opts.h
tools/sdk/include/lwip/lwip/apps/tftp_server.h
tools/sdk/include/lwip/lwip/arch.h
tools/sdk/include/lwip/lwip/autoip.h
tools/sdk/include/lwip/lwip/debug.h
tools/sdk/include/lwip/lwip/def.h
tools/sdk/include/lwip/lwip/dhcp.h
tools/sdk/include/lwip/lwip/dhcp6.h
tools/sdk/include/lwip/lwip/dns.h
tools/sdk/include/lwip/lwip/err.h
tools/sdk/include/lwip/lwip/errno.h
tools/sdk/include/lwip/lwip/etharp.h
tools/sdk/include/lwip/lwip/ethip6.h
tools/sdk/include/lwip/lwip/icmp.h
tools/sdk/include/lwip/lwip/icmp6.h
tools/sdk/include/lwip/lwip/igmp.h
tools/sdk/include/lwip/lwip/inet.h
tools/sdk/include/lwip/lwip/inet_chksum.h
tools/sdk/include/lwip/lwip/init.h
tools/sdk/include/lwip/lwip/ip.h
tools/sdk/include/lwip/lwip/ip4.h
tools/sdk/include/lwip/lwip/ip4_addr.h
tools/sdk/include/lwip/lwip/ip4_frag.h
tools/sdk/include/lwip/lwip/ip6.h
tools/sdk/include/lwip/lwip/ip6_addr.h
tools/sdk/include/lwip/lwip/ip6_frag.h
tools/sdk/include/lwip/lwip/ip_addr.h
tools/sdk/include/lwip/lwip/mem.h
tools/sdk/include/lwip/lwip/memp.h
tools/sdk/include/lwip/lwip/mld6.h
tools/sdk/include/lwip/lwip/nd6.h
tools/sdk/include/lwip/lwip/netbuf.h
tools/sdk/include/lwip/lwip/netdb.h
tools/sdk/include/lwip/lwip/netif.h
tools/sdk/include/lwip/lwip/netifapi.h
tools/sdk/include/lwip/lwip/opt.h
tools/sdk/include/lwip/lwip/pbuf.h
tools/sdk/include/lwip/lwip/priv/api_msg.h
tools/sdk/include/lwip/lwip/priv/memp_priv.h
tools/sdk/include/lwip/lwip/priv/memp_std.h
tools/sdk/include/lwip/lwip/priv/nd6_priv.h
tools/sdk/include/lwip/lwip/priv/tcp_priv.h
tools/sdk/include/lwip/lwip/priv/tcpip_priv.h
tools/sdk/include/lwip/lwip/prot/autoip.h
tools/sdk/include/lwip/lwip/prot/dhcp.h
tools/sdk/include/lwip/lwip/prot/dns.h
tools/sdk/include/lwip/lwip/prot/etharp.h
tools/sdk/include/lwip/lwip/prot/ethernet.h
tools/sdk/include/lwip/lwip/prot/icmp.h
tools/sdk/include/lwip/lwip/prot/icmp6.h
tools/sdk/include/lwip/lwip/prot/igmp.h
tools/sdk/include/lwip/lwip/prot/ip.h
tools/sdk/include/lwip/lwip/prot/ip4.h
tools/sdk/include/lwip/lwip/prot/ip6.h
tools/sdk/include/lwip/lwip/prot/mld6.h
tools/sdk/include/lwip/lwip/prot/nd6.h
tools/sdk/include/lwip/lwip/prot/tcp.h
tools/sdk/include/lwip/lwip/prot/udp.h
tools/sdk/include/lwip/lwip/raw.h
tools/sdk/include/lwip/lwip/sio.h
tools/sdk/include/lwip/lwip/snmp.h
tools/sdk/include/lwip/lwip/sockets.h
tools/sdk/include/lwip/lwip/stats.h
tools/sdk/include/lwip/lwip/sys.h
tools/sdk/include/lwip/lwip/tcp.h
tools/sdk/include/lwip/lwip/tcpip.h
tools/sdk/include/lwip/lwip/timeouts.h
tools/sdk/include/lwip/lwip/udp.h
tools/sdk/include/lwip/lwipopts.h
tools/sdk/include/lwip/netdb.h
tools/sdk/include/lwip/netif/dhcp_state.h
tools/sdk/include/lwip/netif/etharp.h
tools/sdk/include/lwip/netif/ethernet.h
tools/sdk/include/lwip/netif/ethernetif.h
tools/sdk/include/lwip/netif/lowpan6.h
tools/sdk/include/lwip/netif/lowpan6_opts.h
tools/sdk/include/lwip/netif/ppp/ccp.h
tools/sdk/include/lwip/netif/ppp/chap-md5.h
tools/sdk/include/lwip/netif/ppp/chap-new.h
tools/sdk/include/lwip/netif/ppp/chap_ms.h
tools/sdk/include/lwip/netif/ppp/eap.h
tools/sdk/include/lwip/netif/ppp/ecp.h
tools/sdk/include/lwip/netif/ppp/eui64.h
tools/sdk/include/lwip/netif/ppp/fsm.h
tools/sdk/include/lwip/netif/ppp/ipcp.h
tools/sdk/include/lwip/netif/ppp/ipv6cp.h
tools/sdk/include/lwip/netif/ppp/lcp.h
tools/sdk/include/lwip/netif/ppp/magic.h
tools/sdk/include/lwip/netif/ppp/mppe.h
tools/sdk/include/lwip/netif/ppp/polarssl/arc4.h
tools/sdk/include/lwip/netif/ppp/polarssl/des.h
tools/sdk/include/lwip/netif/ppp/polarssl/md4.h
tools/sdk/include/lwip/netif/ppp/polarssl/md5.h
tools/sdk/include/lwip/netif/ppp/polarssl/sha1.h
tools/sdk/include/lwip/netif/ppp/ppp.h
tools/sdk/include/lwip/netif/ppp/ppp_impl.h
tools/sdk/include/lwip/netif/ppp/ppp_opts.h
tools/sdk/include/lwip/netif/ppp/pppapi.h
tools/sdk/include/lwip/netif/ppp/pppcrypt.h
tools/sdk/include/lwip/netif/ppp/pppdebug.h
tools/sdk/include/lwip/netif/ppp/pppoe.h
tools/sdk/include/lwip/netif/ppp/pppol2tp.h
tools/sdk/include/lwip/netif/ppp/pppos.h
tools/sdk/include/lwip/netif/ppp/upap.h
tools/sdk/include/lwip/netif/ppp/vj.h
tools/sdk/include/lwip/netif/slipif.h
tools/sdk/include/lwip/netif/wlanif.h
tools/sdk/include/lwip/netinet/in.h
tools/sdk/include/lwip/perf.h
tools/sdk/include/lwip/ping/ping.h
tools/sdk/include/lwip/posix/errno.h
tools/sdk/include/lwip/posix/netdb.h
tools/sdk/include/lwip/posix/sys/socket.h
tools/sdk/include/lwip/sys/socket.h
tools/sdk/include/lwip/sys_arch.h
tools/sdk/include/lwip/vfs_lwip.h
tools/sdk/include/mbedtls/aes_alt.h
tools/sdk/include/mbedtls/esp_mem.h
tools/sdk/include/mbedtls/mbedtls/aes.h
tools/sdk/include/mbedtls/mbedtls/aesni.h
tools/sdk/include/mbedtls/mbedtls/arc4.h
tools/sdk/include/mbedtls/mbedtls/aria.h
tools/sdk/include/mbedtls/mbedtls/asn1.h
tools/sdk/include/mbedtls/mbedtls/asn1write.h
tools/sdk/include/mbedtls/mbedtls/base64.h
tools/sdk/include/mbedtls/mbedtls/bignum.h
tools/sdk/include/mbedtls/mbedtls/blowfish.h
tools/sdk/include/mbedtls/mbedtls/bn_mul.h
tools/sdk/include/mbedtls/mbedtls/camellia.h
tools/sdk/include/mbedtls/mbedtls/ccm.h
tools/sdk/include/mbedtls/mbedtls/certs.h
tools/sdk/include/mbedtls/mbedtls/chacha20.h
tools/sdk/include/mbedtls/mbedtls/chachapoly.h
tools/sdk/include/mbedtls/mbedtls/check_config.h
tools/sdk/include/mbedtls/mbedtls/cipher.h
tools/sdk/include/mbedtls/mbedtls/cipher_internal.h
tools/sdk/include/mbedtls/mbedtls/cmac.h
tools/sdk/include/mbedtls/mbedtls/compat-1.3.h
tools/sdk/include/mbedtls/mbedtls/config.h
tools/sdk/include/mbedtls/mbedtls/ctr_drbg.h
tools/sdk/include/mbedtls/mbedtls/debug.h
tools/sdk/include/mbedtls/mbedtls/des.h
tools/sdk/include/mbedtls/mbedtls/dhm.h
tools/sdk/include/mbedtls/mbedtls/ecdh.h
tools/sdk/include/mbedtls/mbedtls/ecdsa.h
tools/sdk/include/mbedtls/mbedtls/ecjpake.h
tools/sdk/include/mbedtls/mbedtls/ecp.h
tools/sdk/include/mbedtls/mbedtls/ecp_internal.h
tools/sdk/include/mbedtls/mbedtls/entropy.h
tools/sdk/include/mbedtls/mbedtls/entropy_poll.h
tools/sdk/include/mbedtls/mbedtls/error.h
tools/sdk/include/mbedtls/mbedtls/esp_config.h
tools/sdk/include/mbedtls/mbedtls/esp_debug.h
tools/sdk/include/mbedtls/mbedtls/gcm.h
tools/sdk/include/mbedtls/mbedtls/havege.h
tools/sdk/include/mbedtls/mbedtls/hkdf.h
tools/sdk/include/mbedtls/mbedtls/hmac_drbg.h
tools/sdk/include/mbedtls/mbedtls/md.h
tools/sdk/include/mbedtls/mbedtls/md2.h
tools/sdk/include/mbedtls/mbedtls/md4.h
tools/sdk/include/mbedtls/mbedtls/md5.h
tools/sdk/include/mbedtls/mbedtls/md_internal.h
tools/sdk/include/mbedtls/mbedtls/memory_buffer_alloc.h
tools/sdk/include/mbedtls/mbedtls/net.h
tools/sdk/include/mbedtls/mbedtls/net_sockets.h
tools/sdk/include/mbedtls/mbedtls/nist_kw.h
tools/sdk/include/mbedtls/mbedtls/oid.h
tools/sdk/include/mbedtls/mbedtls/padlock.h
tools/sdk/include/mbedtls/mbedtls/pem.h
tools/sdk/include/mbedtls/mbedtls/pk.h
tools/sdk/include/mbedtls/mbedtls/pk_internal.h
tools/sdk/include/mbedtls/mbedtls/pkcs11.h
tools/sdk/include/mbedtls/mbedtls/pkcs12.h
tools/sdk/include/mbedtls/mbedtls/pkcs5.h
tools/sdk/include/mbedtls/mbedtls/platform.h
tools/sdk/include/mbedtls/mbedtls/platform_time.h
tools/sdk/include/mbedtls/mbedtls/platform_util.h
tools/sdk/include/mbedtls/mbedtls/poly1305.h
tools/sdk/include/mbedtls/mbedtls/ripemd160.h
tools/sdk/include/mbedtls/mbedtls/rsa.h
tools/sdk/include/mbedtls/mbedtls/rsa_internal.h
tools/sdk/include/mbedtls/mbedtls/sha1.h
tools/sdk/include/mbedtls/mbedtls/sha256.h
tools/sdk/include/mbedtls/mbedtls/sha512.h
tools/sdk/include/mbedtls/mbedtls/ssl.h
tools/sdk/include/mbedtls/mbedtls/ssl_cache.h
tools/sdk/include/mbedtls/mbedtls/ssl_ciphersuites.h
tools/sdk/include/mbedtls/mbedtls/ssl_cookie.h
tools/sdk/include/mbedtls/mbedtls/ssl_internal.h
tools/sdk/include/mbedtls/mbedtls/ssl_ticket.h
tools/sdk/include/mbedtls/mbedtls/threading.h
tools/sdk/include/mbedtls/mbedtls/timing.h
tools/sdk/include/mbedtls/mbedtls/version.h
tools/sdk/include/mbedtls/mbedtls/x509.h
tools/sdk/include/mbedtls/mbedtls/x509_crl.h
tools/sdk/include/mbedtls/mbedtls/x509_crt.h
tools/sdk/include/mbedtls/mbedtls/x509_csr.h
tools/sdk/include/mbedtls/mbedtls/xtea.h
tools/sdk/include/mbedtls/sha1_alt.h
tools/sdk/include/mbedtls/sha256_alt.h
tools/sdk/include/mbedtls/sha512_alt.h
tools/sdk/include/mdns/mdns.h
tools/sdk/include/mdns/mdns_console.h
tools/sdk/include/micro-ecc/types.h
tools/sdk/include/micro-ecc/uECC.h
tools/sdk/include/micro-ecc/uECC_vli.h
tools/sdk/include/mqtt/mqtt_client.h
tools/sdk/include/mqtt/mqtt_config.h
tools/sdk/include/newlib/_ansi.h
tools/sdk/include/newlib/_syslist.h
tools/sdk/include/newlib/alloca.h
tools/sdk/include/newlib/ar.h
tools/sdk/include/newlib/argz.h
tools/sdk/include/newlib/assert.h
tools/sdk/include/newlib/complex.h
tools/sdk/include/newlib/config.h
tools/sdk/include/newlib/ctype.h
tools/sdk/include/newlib/dirent.h
tools/sdk/include/newlib/envlock.h
tools/sdk/include/newlib/envz.h
tools/sdk/include/newlib/errno.h
tools/sdk/include/newlib/esp_newlib.h
tools/sdk/include/newlib/fastmath.h
tools/sdk/include/newlib/fcntl.h
tools/sdk/include/newlib/fenv.h
tools/sdk/include/newlib/fnmatch.h
tools/sdk/include/newlib/getopt.h
tools/sdk/include/newlib/glob.h
tools/sdk/include/newlib/grp.h
tools/sdk/include/newlib/iconv.h
tools/sdk/include/newlib/ieeefp.h
tools/sdk/include/newlib/inttypes.h
tools/sdk/include/newlib/langinfo.h
tools/sdk/include/newlib/libgen.h
tools/sdk/include/newlib/limits.h
tools/sdk/include/newlib/locale.h
tools/sdk/include/newlib/machine/_default_types.h
tools/sdk/include/newlib/machine/_types.h
tools/sdk/include/newlib/machine/ansi.h
tools/sdk/include/newlib/machine/endian.h
tools/sdk/include/newlib/machine/fastmath.h
tools/sdk/include/newlib/machine/ieeefp.h
tools/sdk/include/newlib/machine/malloc.h
tools/sdk/include/newlib/machine/param.h
tools/sdk/include/newlib/machine/setjmp-dj.h
tools/sdk/include/newlib/machine/setjmp.h
tools/sdk/include/newlib/machine/stdlib.h
tools/sdk/include/newlib/machine/termios.h
tools/sdk/include/newlib/machine/time.h
tools/sdk/include/newlib/machine/types.h
tools/sdk/include/newlib/malloc.h
tools/sdk/include/newlib/math.h
tools/sdk/include/newlib/net/if.h
tools/sdk/include/newlib/newlib.h
tools/sdk/include/newlib/paths.h
tools/sdk/include/newlib/pthread.h
tools/sdk/include/newlib/pwd.h
tools/sdk/include/newlib/reent.h
tools/sdk/include/newlib/regdef.h
tools/sdk/include/newlib/regex.h
tools/sdk/include/newlib/sched.h
tools/sdk/include/newlib/search.h
tools/sdk/include/newlib/setjmp.h
tools/sdk/include/newlib/signal.h
tools/sdk/include/newlib/spawn.h
tools/sdk/include/newlib/stdatomic.h
tools/sdk/include/newlib/stdint.h
tools/sdk/include/newlib/stdio.h
tools/sdk/include/newlib/stdio_ext.h
tools/sdk/include/newlib/stdlib.h
tools/sdk/include/newlib/string.h
tools/sdk/include/newlib/strings.h
tools/sdk/include/newlib/sys/_default_fcntl.h
tools/sdk/include/newlib/sys/_intsup.h
tools/sdk/include/newlib/sys/_types.h
tools/sdk/include/newlib/sys/cdefs.h
tools/sdk/include/newlib/sys/config.h
tools/sdk/include/newlib/sys/custom_file.h
tools/sdk/include/newlib/sys/dir.h
tools/sdk/include/newlib/sys/errno.h
tools/sdk/include/newlib/sys/fcntl.h
tools/sdk/include/newlib/sys/features.h
tools/sdk/include/newlib/sys/file.h
tools/sdk/include/newlib/sys/iconvnls.h
tools/sdk/include/newlib/sys/lock.h
tools/sdk/include/newlib/sys/param.h
tools/sdk/include/newlib/sys/poll.h
tools/sdk/include/newlib/sys/queue.h
tools/sdk/include/newlib/sys/random.h
tools/sdk/include/newlib/sys/reent.h
tools/sdk/include/newlib/sys/resource.h
tools/sdk/include/newlib/sys/sched.h
tools/sdk/include/newlib/sys/select.h
tools/sdk/include/newlib/sys/signal.h
tools/sdk/include/newlib/sys/stat.h
tools/sdk/include/newlib/sys/stdio.h
tools/sdk/include/newlib/sys/string.h
tools/sdk/include/newlib/sys/syslimits.h
tools/sdk/include/newlib/sys/termios.h
tools/sdk/include/newlib/sys/time.h
tools/sdk/include/newlib/sys/timeb.h
tools/sdk/include/newlib/sys/times.h
tools/sdk/include/newlib/sys/types.h
tools/sdk/include/newlib/sys/uio.h
tools/sdk/include/newlib/sys/un.h
tools/sdk/include/newlib/sys/unistd.h
tools/sdk/include/newlib/sys/utime.h
tools/sdk/include/newlib/sys/wait.h
tools/sdk/include/newlib/tar.h
tools/sdk/include/newlib/termios.h
tools/sdk/include/newlib/tgmath.h
tools/sdk/include/newlib/time.h
tools/sdk/include/newlib/unctrl.h
tools/sdk/include/newlib/unistd.h
tools/sdk/include/newlib/utime.h
tools/sdk/include/newlib/utmp.h
tools/sdk/include/newlib/wchar.h
tools/sdk/include/newlib/wctype.h
tools/sdk/include/newlib/wordexp.h
tools/sdk/include/newlib/xtensa/config/core-isa.h
tools/sdk/include/nghttp/config.h
tools/sdk/include/nghttp/http_parser.h
tools/sdk/include/nghttp/nghttp2/nghttp2.h
tools/sdk/include/nghttp/nghttp2/nghttp2ver.h
tools/sdk/include/nvs_flash/nvs.h
tools/sdk/include/nvs_flash/nvs_flash.h
tools/sdk/include/openssl/internal/ssl3.h
tools/sdk/include/openssl/internal/ssl_cert.h
tools/sdk/include/openssl/internal/ssl_code.h
tools/sdk/include/openssl/internal/ssl_dbg.h
tools/sdk/include/openssl/internal/ssl_lib.h
tools/sdk/include/openssl/internal/ssl_methods.h
tools/sdk/include/openssl/internal/ssl_pkey.h
tools/sdk/include/openssl/internal/ssl_stack.h
tools/sdk/include/openssl/internal/ssl_types.h
tools/sdk/include/openssl/internal/ssl_x509.h
tools/sdk/include/openssl/internal/tls1.h
tools/sdk/include/openssl/internal/x509_vfy.h
tools/sdk/include/openssl/openssl/ssl.h
tools/sdk/include/openssl/platform/ssl_opt.h
tools/sdk/include/openssl/platform/ssl_pm.h
tools/sdk/include/openssl/platform/ssl_port.h
tools/sdk/include/protobuf-c/protobuf-c/protobuf-c.h
tools/sdk/include/protobuf-c/protoc-c/c_bytes_field.h
tools/sdk/include/protobuf-c/protoc-c/c_enum.h
tools/sdk/include/protobuf-c/protoc-c/c_enum_field.h
tools/sdk/include/protobuf-c/protoc-c/c_extension.h
tools/sdk/include/protobuf-c/protoc-c/c_field.h
tools/sdk/include/protobuf-c/protoc-c/c_file.h
tools/sdk/include/protobuf-c/protoc-c/c_generator.h
tools/sdk/include/protobuf-c/protoc-c/c_helpers.h
tools/sdk/include/protobuf-c/protoc-c/c_message.h
tools/sdk/include/protobuf-c/protoc-c/c_message_field.h
tools/sdk/include/protobuf-c/protoc-c/c_primitive_field.h
tools/sdk/include/protobuf-c/protoc-c/c_service.h
tools/sdk/include/protobuf-c/protoc-c/c_string_field.h
tools/sdk/include/protobuf-c/t/generated-code2/common-test-arrays.h
tools/sdk/include/protocomm/protocomm.h
tools/sdk/include/protocomm/protocomm_ble.h
tools/sdk/include/protocomm/protocomm_console.h
tools/sdk/include/protocomm/protocomm_httpd.h
tools/sdk/include/protocomm/protocomm_security.h
tools/sdk/include/protocomm/protocomm_security0.h
tools/sdk/include/protocomm/protocomm_security1.h
tools/sdk/include/pthread/esp_pthread.h
tools/sdk/include/sdmmc/sdmmc_cmd.h
tools/sdk/include/smartconfig_ack/smartconfig_ack.h
tools/sdk/include/soc/soc/adc_channel.h
tools/sdk/include/soc/soc/apb_ctrl_reg.h
tools/sdk/include/soc/soc/apb_ctrl_struct.h
tools/sdk/include/soc/soc/bb_reg.h
tools/sdk/include/soc/soc/boot_mode.h
tools/sdk/include/soc/soc/can_struct.h
tools/sdk/include/soc/soc/clkout_channel.h
tools/sdk/include/soc/soc/cpu.h
tools/sdk/include/soc/soc/dac_channel.h
tools/sdk/include/soc/soc/dport_access.h
tools/sdk/include/soc/soc/dport_reg.h
tools/sdk/include/soc/soc/efuse_reg.h
tools/sdk/include/soc/soc/emac_ex_reg.h
tools/sdk/include/soc/soc/emac_reg_v2.h
tools/sdk/include/soc/soc/fe_reg.h
tools/sdk/include/soc/soc/frc_timer_reg.h
tools/sdk/include/soc/soc/gpio_periph.h
tools/sdk/include/soc/soc/gpio_pins.h
tools/sdk/include/soc/soc/gpio_reg.h
tools/sdk/include/soc/soc/gpio_sd_reg.h
tools/sdk/include/soc/soc/gpio_sd_struct.h
tools/sdk/include/soc/soc/gpio_sig_map.h
tools/sdk/include/soc/soc/gpio_struct.h
tools/sdk/include/soc/soc/hinf_reg.h
tools/sdk/include/soc/soc/hinf_struct.h
tools/sdk/include/soc/soc/host_reg.h
tools/sdk/include/soc/soc/host_struct.h
tools/sdk/include/soc/soc/hwcrypto_reg.h
tools/sdk/include/soc/soc/i2c_reg.h
tools/sdk/include/soc/soc/i2c_struct.h
tools/sdk/include/soc/soc/i2s_reg.h
tools/sdk/include/soc/soc/i2s_struct.h
tools/sdk/include/soc/soc/io_mux_reg.h
tools/sdk/include/soc/soc/ledc_reg.h
tools/sdk/include/soc/soc/ledc_struct.h
tools/sdk/include/soc/soc/mcpwm_reg.h
tools/sdk/include/soc/soc/mcpwm_struct.h
tools/sdk/include/soc/soc/nrx_reg.h
tools/sdk/include/soc/soc/pcnt_reg.h
tools/sdk/include/soc/soc/pcnt_struct.h
tools/sdk/include/soc/soc/periph_defs.h
tools/sdk/include/soc/soc/pid.h
tools/sdk/include/soc/soc/rmt_reg.h
tools/sdk/include/soc/soc/rmt_struct.h
tools/sdk/include/soc/soc/rtc.h
tools/sdk/include/soc/soc/rtc_cntl_reg.h
tools/sdk/include/soc/soc/rtc_cntl_struct.h
tools/sdk/include/soc/soc/rtc_gpio_channel.h
tools/sdk/include/soc/soc/rtc_i2c_reg.h
tools/sdk/include/soc/soc/rtc_io_reg.h
tools/sdk/include/soc/soc/rtc_io_struct.h
tools/sdk/include/soc/soc/rtc_periph.h
tools/sdk/include/soc/soc/rtc_wdt.h
tools/sdk/include/soc/soc/sdio_slave_periph.h
tools/sdk/include/soc/soc/sdio_slave_pins.h
tools/sdk/include/soc/soc/sdmmc_periph.h
tools/sdk/include/soc/soc/sdmmc_pins.h
tools/sdk/include/soc/soc/sdmmc_reg.h
tools/sdk/include/soc/soc/sdmmc_struct.h
tools/sdk/include/soc/soc/sens_reg.h
tools/sdk/include/soc/soc/sens_struct.h
tools/sdk/include/soc/soc/slc_reg.h
tools/sdk/include/soc/soc/slc_struct.h
tools/sdk/include/soc/soc/soc.h
tools/sdk/include/soc/soc/soc_memory_layout.h
tools/sdk/include/soc/soc/soc_ulp.h
tools/sdk/include/soc/soc/spi_periph.h
tools/sdk/include/soc/soc/spi_pins.h
tools/sdk/include/soc/soc/spi_reg.h
tools/sdk/include/soc/soc/spi_struct.h
tools/sdk/include/soc/soc/syscon_reg.h
tools/sdk/include/soc/soc/syscon_struct.h
tools/sdk/include/soc/soc/timer_group_reg.h
tools/sdk/include/soc/soc/timer_group_struct.h
tools/sdk/include/soc/soc/touch_channel.h
tools/sdk/include/soc/soc/uart_channel.h
tools/sdk/include/soc/soc/uart_reg.h
tools/sdk/include/soc/soc/uart_struct.h
tools/sdk/include/soc/soc/uhci_reg.h
tools/sdk/include/soc/soc/uhci_struct.h
tools/sdk/include/soc/soc/wdev_reg.h
tools/sdk/include/spi_flash/esp_partition.h
tools/sdk/include/spi_flash/esp_spi_flash.h
tools/sdk/include/spiffs/esp_spiffs.h
tools/sdk/include/spiffs/spiffs_config.h
tools/sdk/include/tcp_transport/esp_transport.h
tools/sdk/include/tcp_transport/esp_transport_ssl.h
tools/sdk/include/tcp_transport/esp_transport_tcp.h
tools/sdk/include/tcp_transport/esp_transport_utils.h
tools/sdk/include/tcp_transport/esp_transport_ws.h
tools/sdk/include/tcpip_adapter/tcpip_adapter.h
tools/sdk/include/ulp/esp32/ulp.h
tools/sdk/include/vfs/esp_vfs.h
tools/sdk/include/vfs/esp_vfs_dev.h
tools/sdk/include/vfs/sys/dirent.h
tools/sdk/include/vfs/sys/ioctl.h
tools/sdk/include/wear_levelling/wear_levelling.h
tools/sdk/include/wifi_provisioning/wifi_provisioning/wifi_config.h
tools/sdk/include/wpa_supplicant/byteswap.h
tools/sdk/include/wpa_supplicant/crypto/aes.h
tools/sdk/include/wpa_supplicant/crypto/aes_i.h
tools/sdk/include/wpa_supplicant/crypto/aes_wrap.h
tools/sdk/include/wpa_supplicant/crypto/base64.h
tools/sdk/include/wpa_supplicant/crypto/common.h
tools/sdk/include/wpa_supplicant/crypto/crypto.h
tools/sdk/include/wpa_supplicant/crypto/dh_group5.h
tools/sdk/include/wpa_supplicant/crypto/dh_groups.h
tools/sdk/include/wpa_supplicant/crypto/includes.h
tools/sdk/include/wpa_supplicant/crypto/md5.h
tools/sdk/include/wpa_supplicant/crypto/md5_i.h
tools/sdk/include/wpa_supplicant/crypto/ms_funcs.h
tools/sdk/include/wpa_supplicant/crypto/random.h
tools/sdk/include/wpa_supplicant/crypto/sha1.h
tools/sdk/include/wpa_supplicant/crypto/sha1_i.h
tools/sdk/include/wpa_supplicant/crypto/sha256.h
tools/sdk/include/wpa_supplicant/endian.h
tools/sdk/include/wpa_supplicant/os.h
tools/sdk/include/wpa_supplicant/wpa/ap_config.h
tools/sdk/include/wpa_supplicant/wpa/common.h
tools/sdk/include/wpa_supplicant/wpa/defs.h
tools/sdk/include/wpa_supplicant/wpa/eapol_common.h
tools/sdk/include/wpa_supplicant/wpa/hostapd.h
tools/sdk/include/wpa_supplicant/wpa/ieee80211_crypto.h
tools/sdk/include/wpa_supplicant/wpa/ieee802_11_defs.h
tools/sdk/include/wpa_supplicant/wpa/ieee802_1x.h
tools/sdk/include/wpa_supplicant/wpa/includes.h
tools/sdk/include/wpa_supplicant/wpa/list.h
tools/sdk/include/wpa_supplicant/wpa/sta_info.h
tools/sdk/include/wpa_supplicant/wpa/state_machine.h
tools/sdk/include/wpa_supplicant/wpa/wpa.h
tools/sdk/include/wpa_supplicant/wpa/wpa_auth.h
tools/sdk/include/wpa_supplicant/wpa/wpa_auth_i.h
tools/sdk/include/wpa_supplicant/wpa/wpa_auth_ie.h
tools/sdk/include/wpa_supplicant/wpa/wpa_common.h
tools/sdk/include/wpa_supplicant/wpa/wpa_debug.h
tools/sdk/include/wpa_supplicant/wpa/wpa_i.h
tools/sdk/include/wpa_supplicant/wpa/wpa_ie.h
tools/sdk/include/wpa_supplicant/wpa/wpabuf.h
tools/sdk/include/wpa_supplicant/wpa/wpas_glue.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_common.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_config.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_defs.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_i.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_methods.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_peap_common.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_tls.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_tls_common.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_tlv_common.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/eap_ttls.h
tools/sdk/include/wpa_supplicant/wpa2/eap_peer/mschapv2.h
tools/sdk/include/wpa_supplicant/wpa2/tls/asn1.h
tools/sdk/include/wpa_supplicant/wpa2/tls/bignum.h
tools/sdk/include/wpa_supplicant/wpa2/tls/libtommath.h
tools/sdk/include/wpa_supplicant/wpa2/tls/pkcs1.h
tools/sdk/include/wpa_supplicant/wpa2/tls/pkcs5.h
tools/sdk/include/wpa_supplicant/wpa2/tls/pkcs8.h
tools/sdk/include/wpa_supplicant/wpa2/tls/rsa.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tls.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_client.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_client_i.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_common.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_cred.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_record.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_server.h
tools/sdk/include/wpa_supplicant/wpa2/tls/tlsv1_server_i.h
tools/sdk/include/wpa_supplicant/wpa2/tls/x509v3.h
tools/sdk/include/wpa_supplicant/wpa2/utils/base64.h
tools/sdk/include/wpa_supplicant/wpa2/utils/ext_password.h
tools/sdk/include/wpa_supplicant/wpa2/utils/ext_password_i.h
tools/sdk/include/wpa_supplicant/wps/utils/uuid.h
tools/sdk/include/wpa_supplicant/wps/wps.h
tools/sdk/include/wpa_supplicant/wps/wps_attr_parse.h
tools/sdk/include/wpa_supplicant/wps/wps_defs.h
tools/sdk/include/wpa_supplicant/wps/wps_dev_attr.h
tools/sdk/include/wpa_supplicant/wps/wps_i.h
tools/sdk/include/xtensa-debug-module/eri.h
tools/sdk/include/xtensa-debug-module/trax.h
tools/sdk/include/xtensa-debug-module/xtensa-debug-module.h
tools/sdk/ld/esp32.common.ld
tools/sdk/ld/esp32.extram.bss.ld
tools/sdk/ld/esp32.ld
tools/sdk/ld/esp32.peripherals.ld
tools/sdk/ld/esp32.rom.ld
tools/sdk/ld/esp32.rom.libgcc.ld
tools/sdk/ld/esp32.rom.nanofmt.ld
tools/sdk/ld/esp32.rom.redefined.ld
tools/sdk/ld/esp32.rom.spiflash.ld
tools/sdk/ld/esp32.rom.spiram_incompatible_fns.ld
tools/sdk/ld/esp32.spiram.rom-functions-dram.ld
tools/sdk/ld/esp32.spiram.rom-functions-iram.ld
tools/sdk/ld/esp32_out.ld
tools/sdk/ld/wifi_iram.ld
tools/sdk/lib/libapp_trace.a
tools/sdk/lib/libapp_update.a
tools/sdk/lib/libasio.a
tools/sdk/lib/libbootloader_support.a
tools/sdk/lib/libbt.a
tools/sdk/lib/libbtdm_app.a
tools/sdk/lib/libc.a
tools/sdk/lib/libc_nano.a
tools/sdk/lib/libcoap.a
tools/sdk/lib/libcoexist.a
tools/sdk/lib/libconsole.a
tools/sdk/lib/libcore.a
tools/sdk/lib/libcxx.a
tools/sdk/lib/libdl_lib.a
tools/sdk/lib/libdriver.a
tools/sdk/lib/libesp-tls.a
tools/sdk/lib/libesp32-camera.a
tools/sdk/lib/libesp32.a
tools/sdk/lib/libesp_adc_cal.a
tools/sdk/lib/libesp_event.a
tools/sdk/lib/libesp_http_client.a
tools/sdk/lib/libesp_http_server.a
tools/sdk/lib/libesp_https_ota.a
tools/sdk/lib/libesp_ringbuf.a
tools/sdk/lib/libespnow.a
tools/sdk/lib/libethernet.a
tools/sdk/lib/libexpat.a
tools/sdk/lib/libface_detection.a
tools/sdk/lib/libface_recognition.a
tools/sdk/lib/libfatfs.a
tools/sdk/lib/libfb_gfx.a
tools/sdk/lib/libfd.a
tools/sdk/lib/libfr.a
tools/sdk/lib/libfreemodbus.a
tools/sdk/lib/libfreertos.a
tools/sdk/lib/libhal.a
tools/sdk/lib/libheap.a
tools/sdk/lib/libimage_util.a
tools/sdk/lib/libjsmn.a
tools/sdk/lib/libjson.a
tools/sdk/lib/liblibsodium.a
tools/sdk/lib/liblog.a
tools/sdk/lib/liblwip.a
tools/sdk/lib/libm.a
tools/sdk/lib/libmbedtls.a
tools/sdk/lib/libmdns.a
tools/sdk/lib/libmesh.a
tools/sdk/lib/libmicro-ecc.a
tools/sdk/lib/libmqtt.a
tools/sdk/lib/libnet80211.a
tools/sdk/lib/libnewlib.a
tools/sdk/lib/libnghttp.a
tools/sdk/lib/libnvs_flash.a
tools/sdk/lib/libopenssl.a
tools/sdk/lib/libphy.a
tools/sdk/lib/libpp.a
tools/sdk/lib/libprotobuf-c.a
tools/sdk/lib/libprotocomm.a
tools/sdk/lib/libpthread.a
tools/sdk/lib/librtc.a
tools/sdk/lib/libsdmmc.a
tools/sdk/lib/libsmartconfig.a
tools/sdk/lib/libsmartconfig_ack.a
tools/sdk/lib/libsoc.a
tools/sdk/lib/libspi_flash.a
tools/sdk/lib/libspiffs.a
tools/sdk/lib/libtcp_transport.a
tools/sdk/lib/libtcpip_adapter.a
tools/sdk/lib/libulp.a
tools/sdk/lib/libvfs.a
tools/sdk/lib/libwear_levelling.a
tools/sdk/lib/libwifi_provisioning.a
tools/sdk/lib/libwpa.a
tools/sdk/lib/libwpa2.a
tools/sdk/lib/libwpa_supplicant.a
tools/sdk/lib/libwps.a
tools/sdk/lib/libxtensa-debug-module.a
tools/sdk/sdkconfig
variants/Microduino-esp32/pins_arduino.h
variants/alksesp32/pins_arduino.h
variants/bpi-bit/pins_arduino.h
variants/d-duino-32/pins_arduino.h
variants/d1_mini32/pins_arduino.h
variants/d32/d32_core.h
variants/d32/pins_arduino.h
variants/d32_pro/pins_arduino.h
variants/doitESP32devkitV1/pins_arduino.h
variants/esp32-devkit-lipo/pins_arduino.h
variants/esp32-evb/pins_arduino.h
variants/esp32-gateway/pins_arduino.h
variants/esp32-poe-iso/pins_arduino.h
variants/esp32-poe/pins_arduino.h
variants/esp32/pins_arduino.h
variants/esp320/pins_arduino.h
variants/esp32thing/pins_arduino.h
variants/esp32vn-iot-uno/pins_arduino.h
variants/espea32/pins_arduino.h
variants/espectro32/pins_arduino.h
variants/espino32/pins_arduino.h
variants/feather_esp32/pins_arduino.h
variants/firebeetle32/pins_arduino.h
variants/fm-devkit/pins_arduino.h
variants/frog32/pins_arduino.h
variants/gpy/pins_arduino.h
variants/heltec_wifi_kit_32/pins_arduino.h
variants/heltec_wifi_lora_32/pins_arduino.h
variants/heltec_wifi_lora_32_V2/pins_arduino.h
variants/heltec_wireless_stick/pins_arduino.h
variants/hornbill32dev/pins_arduino.h
variants/hornbill32minima/pins_arduino.h
variants/intorobot-fig/pins_arduino.h
variants/lolin32/pins_arduino.h
variants/lopy/pins_arduino.h
variants/lopy4/pins_arduino.h
variants/m5stack_core_esp32/pins_arduino.h
variants/m5stack_fire/pins_arduino.h
variants/m5stick_c/pins_arduino.h
variants/mhetesp32devkit/pins_arduino.h
variants/mhetesp32minikit/pins_arduino.h
variants/nano32/pins_arduino.h
variants/nina_w10/pins_arduino.h
variants/node32s/pins_arduino.h
variants/nodemcu-32s/pins_arduino.h
variants/odroid_esp32/pins_arduino.h
variants/onehorse32dev/pins_arduino.h
variants/oroca_edubot/pins_arduino.h
variants/pico32/pins_arduino.h
variants/pocket_32/pins_arduino.h
variants/quantum/pins_arduino.h
variants/sparkfun_lora_gateway_1-channel/pins_arduino.h
variants/t-beam/pins_arduino.h
variants/ttgo-lora32-v1/pins_arduino.h
variants/ttgo-t1/pins_arduino.h
variants/turta_iot_node/pins_arduino.h
variants/twatch/pins_arduino.h
variants/wesp32/pins_arduino.h
variants/widora-air/pins_arduino.h
variants/wipy3/pins_arduino.h
variants/xinabox/pins_arduino.h |