Prvni ulozeni z chegewara githubu
This commit is contained in:
		
							
								
								
									
										263
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| # Check ESP-IDF version and error out if it is not in the supported range. | ||||
| # | ||||
| # Note for arduino-esp32 developers: to bypass the version check locally, | ||||
| # set ARDUINO_SKIP_IDF_VERSION_CHECK environment variable to 1. For example: | ||||
| #   export ARDUINO_SKIP_IDF_VERSION_CHECK=1 | ||||
| #   idf.py build | ||||
|  | ||||
| set(min_supported_idf_version "4.4.0") | ||||
| set(max_supported_idf_version "4.4.99") | ||||
| set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") | ||||
|  | ||||
| if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}") | ||||
|   if (idf_version VERSION_LESS min_supported_idf_version) | ||||
|     message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions " | ||||
|                         "between ${min_supported_idf_version} and ${max_supported_idf_version}, " | ||||
|                         "but an older version is detected: ${idf_version}.") | ||||
|   endif() | ||||
|   if (idf_version VERSION_GREATER max_supported_idf_version) | ||||
|     message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions " | ||||
|                         "between ${min_supported_idf_version} and ${max_supported_idf_version}, " | ||||
|                         "but a newer version is detected: ${idf_version}.") | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| 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-i2c-slave.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-rgb-led.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-tinyusb.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/Tone.cpp | ||||
|   cores/esp32/HWCDC.cpp | ||||
|   cores/esp32/USB.cpp | ||||
|   cores/esp32/USBCDC.cpp | ||||
|   cores/esp32/USBMSC.cpp | ||||
|   cores/esp32/FirmwareMSC.cpp | ||||
|   cores/esp32/firmware_msc_fat.c | ||||
|   cores/esp32/wiring_pulse.c | ||||
|   cores/esp32/wiring_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/BluetoothSerial/src/BTAddress.cpp | ||||
|   libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp | ||||
|   libraries/BluetoothSerial/src/BTScanResultsSet.cpp | ||||
|   libraries/DNSServer/src/DNSServer.cpp | ||||
|   libraries/EEPROM/src/EEPROM.cpp | ||||
|   libraries/ESPmDNS/src/ESPmDNS.cpp | ||||
|   libraries/Ethernet/src/ETH.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/LittleFS/src/LittleFS.cpp | ||||
|   libraries/I2S/src/I2S.cpp | ||||
|   libraries/NetBIOS/src/NetBIOS.cpp | ||||
|   libraries/Preferences/src/Preferences.cpp | ||||
|   libraries/RainMaker/src/RMaker.cpp | ||||
|   libraries/RainMaker/src/RMakerNode.cpp | ||||
|   libraries/RainMaker/src/RMakerParam.cpp | ||||
|   libraries/RainMaker/src/RMakerDevice.cpp | ||||
|   libraries/RainMaker/src/RMakerType.cpp | ||||
|   libraries/RainMaker/src/RMakerQR.cpp | ||||
|   libraries/RainMaker/src/RMakerUtils.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/Update/src/HttpsOTAUpdate.cpp | ||||
|   libraries/USB/src/USBHID.cpp | ||||
|   libraries/USB/src/USBHIDMouse.cpp | ||||
|   libraries/USB/src/USBHIDKeyboard.cpp | ||||
|   libraries/USB/src/USBHIDGamepad.cpp | ||||
|   libraries/USB/src/USBHIDConsumerControl.cpp | ||||
|   libraries/USB/src/USBHIDSystemControl.cpp | ||||
|   libraries/USB/src/USBHIDVendor.cpp | ||||
|   libraries/USB/src/USBVendor.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/esp_crt_bundle.c | ||||
|   libraries/WiFiClientSecure/src/WiFiClientSecure.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/WiFiProv/src/WiFiProv.cpp | ||||
|   libraries/Wire/src/Wire.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(includedirs | ||||
|   variants/${CONFIG_ARDUINO_VARIANT}/ | ||||
|   cores/esp32/ | ||||
|   libraries/ArduinoOTA/src | ||||
|   libraries/AsyncUDP/src | ||||
|   libraries/BLE/src | ||||
|   libraries/BluetoothSerial/src | ||||
|   libraries/DNSServer/src | ||||
|   libraries/EEPROM/src | ||||
|   libraries/ESP32/src | ||||
|   libraries/ESPmDNS/src | ||||
|   libraries/Ethernet/src | ||||
|   libraries/FFat/src | ||||
|   libraries/FS/src | ||||
|   libraries/HTTPClient/src | ||||
|   libraries/HTTPUpdate/src | ||||
|   libraries/LittleFS/src | ||||
|   libraries/I2S/src | ||||
|   libraries/NetBIOS/src | ||||
|   libraries/Preferences/src | ||||
|   libraries/RainMaker/src | ||||
|   libraries/SD_MMC/src | ||||
|   libraries/SD/src | ||||
|   libraries/SimpleBLE/src | ||||
|   libraries/SPIFFS/src | ||||
|   libraries/SPI/src | ||||
|   libraries/Ticker/src | ||||
|   libraries/Update/src | ||||
|   libraries/USB/src | ||||
|   libraries/WebServer/src | ||||
|   libraries/WiFiClientSecure/src | ||||
|   libraries/WiFi/src | ||||
|   libraries/WiFiProv/src | ||||
|   libraries/Wire/src | ||||
|   ) | ||||
|  | ||||
| set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS}) | ||||
| set(priv_includes cores/esp32/libb64) | ||||
| set(requires spi_flash mbedtls mdns esp_adc_cal wifi_provisioning nghttp wpa_supplicant) | ||||
| set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_ipc esp_hid) | ||||
|  | ||||
| idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires}) | ||||
|  | ||||
| if(NOT CONFIG_FREERTOS_HZ EQUAL 1000 AND NOT "$ENV{ARDUINO_SKIP_TICK_CHECK}") | ||||
|     # See delay() in cores/esp32/esp32-hal-misc.c. | ||||
|     message(FATAL_ERROR "esp32-arduino requires CONFIG_FREERTOS_HZ=1000 " | ||||
|                         "(currently ${CONFIG_FREERTOS_HZ})") | ||||
| endif() | ||||
|  | ||||
| string(TOUPPER ${CONFIG_ARDUINO_VARIANT} idf_target_caps) | ||||
| target_compile_options(${COMPONENT_TARGET} PUBLIC | ||||
|     -DARDUINO=10812 | ||||
|     -DARDUINO_${idf_target_caps}_DEV | ||||
|     -DARDUINO_ARCH_ESP32 | ||||
|     -DARDUINO_BOARD="${idf_target_caps}_DEV" | ||||
|     -DARDUINO_VARIANT="${CONFIG_ARDUINO_VARIANT}" | ||||
|     -DESP32) | ||||
|  | ||||
| if(CONFIG_AUTOSTART_ARDUINO) | ||||
|     # in autostart mode, arduino-esp32 contains app_main() function and needs to | ||||
|     # reference setup() and loop() in the main component. If we add main | ||||
|     # component to priv_requires then we create a large circular dependency | ||||
|     # (arduino-esp32 -> main -> arduino-esp32) and can get linker errors, so | ||||
|     # instead we add setup() and loop() to the undefined symbols list so the | ||||
|     # linker will always include them. | ||||
|     # | ||||
|     # (As they are C++ symbol, we need to add the C++ mangled names.) | ||||
|     target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _Z5setupv -u _Z4loopv") | ||||
| endif() | ||||
|  | ||||
| # This function adds a dependency on the given component if the component is included into the build. | ||||
| function(maybe_add_component component_name) | ||||
|     idf_build_get_property(components BUILD_COMPONENTS) | ||||
|     if (${component_name} IN_LIST components) | ||||
|         idf_component_get_property(lib_name ${component_name} COMPONENT_LIB) | ||||
|         target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name}) | ||||
|     endif() | ||||
| endfunction() | ||||
|  | ||||
| maybe_add_component(esp-dsp) | ||||
|  | ||||
| if(CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK) | ||||
|     maybe_add_component(esp_rainmaker) | ||||
|     maybe_add_component(qrcode) | ||||
| endif() | ||||
| if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED) | ||||
|     maybe_add_component(arduino_tinyusb) | ||||
| endif() | ||||
| if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA) | ||||
|     maybe_add_component(esp_https_ota) | ||||
| endif() | ||||
| if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LITTLEFS) | ||||
|     maybe_add_component(esp_littlefs) | ||||
| endif() | ||||
							
								
								
									
										50
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| Contributions Guide | ||||
| =================== | ||||
|  | ||||
| We welcome contributions to the Arduino ESP32 project! | ||||
|  | ||||
| How to Contribute | ||||
| ----------------- | ||||
|  | ||||
| Contributions to Arduino ESP32 - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests <https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests>`_. | ||||
|  | ||||
| Before Contributing | ||||
| ------------------- | ||||
|  | ||||
| Before sending us a Pull Request, please consider this list of points: | ||||
|  | ||||
| * Is the contribution entirely your own work, or already licensed under an LGPL 2.1 compatible Open Source License? If not then we unfortunately cannot accept it. | ||||
|  | ||||
| * Is the code adequately commented for people to understand how it is structured? | ||||
|  | ||||
| * Is there documentation or examples that go with code contributions?  | ||||
|  | ||||
| * Are comments and documentation written in clear English, with no spelling or grammar errors? | ||||
|  | ||||
| * Example contributions are also welcome. | ||||
|  | ||||
| * If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits <https://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/>`_? | ||||
|  | ||||
| * If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback. | ||||
|  | ||||
| Pull Request Process | ||||
| -------------------- | ||||
|  | ||||
| After you open the Pull Request, there will probably be some discussion in the comments field of the request itself. | ||||
|  | ||||
| Once the Pull Request is ready to merge, it will first be merged into our internal git system for in-house automated testing. | ||||
|  | ||||
| If this process passes, it will be merged onto the public github repository. | ||||
|  | ||||
| Legal Part | ||||
| ---------- | ||||
|  | ||||
| Before a contribution can be accepted, you will need to sign our :doc:`contributor-agreement`. You will be prompted for this automatically as part of the Pull Request process. | ||||
|  | ||||
| Related Documents | ||||
| ----------------- | ||||
|  | ||||
| .. toctree:: | ||||
|     :maxdepth: 1 | ||||
|  | ||||
|         contributor-agreement | ||||
							
								
								
									
										412
									
								
								Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,412 @@ | ||||
| menu "Arduino Configuration" | ||||
|  | ||||
| config ARDUINO_VARIANT | ||||
|     string "Arduino target variant (board)" | ||||
|     default IDF_TARGET | ||||
|     help | ||||
|         The name of a target variant (e.g., a specific board) in the variants/ | ||||
|         folder, e.g.  "heltec_wifi_lora_32_V2". The name is case sensitive. | ||||
|         Specifying a variant name different from the target enables additional | ||||
|         customization, for example the definition of GPIO pins. | ||||
|  | ||||
| config ENABLE_ARDUINO_DEPENDS | ||||
|     bool | ||||
|     select LWIP_SO_RCVBUF | ||||
|     select ETHERNET | ||||
|     select WIFI_ENABLED | ||||
|     select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE if IDF_TARGET_ESP32 | ||||
|     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_CORE0 if FREERTOS_UNICORE | ||||
|     default ARDUINO_RUN_CORE1 if !FREERTOS_UNICORE | ||||
|     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" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|     config ARDUINO_RUN_NO_AFFINITY | ||||
|         bool "BOTH" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|  | ||||
| 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 | ||||
|  | ||||
| config ARDUINO_LOOP_STACK_SIZE | ||||
|     int "Loop thread stack size" | ||||
|     default 8192 | ||||
|     help | ||||
|         Amount of stack available for the Arduino task. | ||||
|  | ||||
| choice ARDUINO_EVENT_RUNNING_CORE | ||||
|     bool "Core on which Arduino's event handler is running" | ||||
|     default ARDUINO_EVENT_RUN_CORE0 if FREERTOS_UNICORE | ||||
|     default ARDUINO_EVENT_RUN_CORE1 if !FREERTOS_UNICORE | ||||
|     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" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|     config ARDUINO_EVENT_RUN_NO_AFFINITY | ||||
|         bool "BOTH" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|  | ||||
| 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_SERIAL_EVENT_TASK_RUNNING_CORE | ||||
|     bool "Core on which Arduino's Serial Event task is running" | ||||
|     default ARDUINO_SERIAL_EVENT_RUN_CORE0 if FREERTOS_UNICORE | ||||
|     default ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY if !FREERTOS_UNICORE | ||||
|     help | ||||
|         Select on which core Arduino's Serial Event task run | ||||
|  | ||||
|     config ARDUINO_SERIAL_EVENT_RUN_CORE0 | ||||
|         bool "CORE 0" | ||||
|     config ARDUINO_SERIAL_EVENT_RUN_CORE1 | ||||
|         bool "CORE 1" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|     config ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY | ||||
|         bool "BOTH" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|  | ||||
| endchoice | ||||
|  | ||||
| config ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE | ||||
|     int | ||||
|     default 0 if ARDUINO_SERIAL_EVENT_RUN_CORE0 | ||||
|     default 1 if ARDUINO_SERIAL_EVENT_RUN_CORE1 | ||||
|     default -1 if ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY | ||||
|  | ||||
| config ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE | ||||
|     int "Serial Event task stack size" | ||||
|     default 2048 | ||||
|     help | ||||
|         Amount of stack available for the Serial Event task. | ||||
|  | ||||
| config ARDUINO_SERIAL_EVENT_TASK_PRIORITY | ||||
|     int "Priority of the Serial Event task" | ||||
|     default 24 | ||||
|     help | ||||
|         Select at what priority you want the Serial Event task to run. | ||||
|  | ||||
| choice ARDUINO_UDP_RUNNING_CORE | ||||
|     bool "Core on which Arduino's UDP is running" | ||||
|     default ARDUINO_UDP_RUN_CORE0 | ||||
|     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" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|     config ARDUINO_UDP_RUN_NO_AFFINITY | ||||
|         bool "BOTH" | ||||
|         depends on !FREERTOS_UNICORE | ||||
|  | ||||
| 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 ARDUINO_UDP_TASK_PRIORITY | ||||
|     int "Priority of the UDP task" | ||||
|     default 3 | ||||
|     help | ||||
|         Select at what priority you want the UDP task to run. | ||||
|  | ||||
| config ARDUINO_ISR_IRAM | ||||
|     bool "Run interrupts in IRAM" | ||||
|     default "n" | ||||
|     help | ||||
|         Enabling this option will Attach all interrupts with the IRAm flag. | ||||
|         It will also make some HAL function, like, digitalRead/Write and more | ||||
| 				be loaded into IRAM for access inside ISRs. | ||||
| 				Beware that this is a very dangerous setting. Enable it only if you | ||||
| 				are fully aware of the consequences. | ||||
|  | ||||
| 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_FFat | ||||
|     bool "Enable FFat" | ||||
|     depends on ARDUINO_SELECTIVE_COMPILATION | ||||
|     select ARDUINO_SELECTIVE_FS | ||||
|     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_LITTLEFS | ||||
|     bool "Enable LITTLEFS" | ||||
|     depends on ARDUINO_SELECTIVE_COMPILATION | ||||
|     select ARDUINO_SELECTIVE_FS | ||||
|     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_WiFiProv | ||||
|     bool "Enable WiFiProv" | ||||
|     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 | ||||
|  | ||||
							
								
								
									
										503
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,503 @@ | ||||
| ### 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! | ||||
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| # Arduino core for the ESP32, ESP32-S2, ESP32-S3 and ESP32-C3 | ||||
|  | ||||
|  [](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest) | ||||
|  | ||||
| ### 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) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions) | ||||
|  | ||||
| ## Contents | ||||
|  | ||||
|   - [Development Status](#development-status) | ||||
|   - [Development Planning](#development-planning) | ||||
|   - [Documentation](#documentation) | ||||
|   - [Supported Chips](#supported-chips) | ||||
|   - [Decoding exceptions](#decoding-exceptions) | ||||
|   - [Issue/Bug report template](#issuebug-report-template) | ||||
|   - [Contributing](#contributing) | ||||
|  | ||||
| ### Development Status | ||||
|  | ||||
| Latest Stable Release  [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) | ||||
|  | ||||
| Latest Development Release  [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/) | ||||
|  | ||||
| ### Development Planning | ||||
|  | ||||
| Our Development is fully tracked on this public **[Roadmap 🎉](https://github.com/orgs/espressif/projects/3)**  | ||||
|  | ||||
| For even more information you can take a look at [Sprint Meeting notes](https://github.com/espressif/arduino-esp32/discussions/categories/sprints-meeting-notes) or join [Monthly Community Meetings 🔔](https://github.com/espressif/arduino-esp32/discussions/categories/monthly-community-meetings) | ||||
|  | ||||
| ### Documentation | ||||
|  | ||||
| You can use the [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project. | ||||
|  | ||||
| * [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html) | ||||
| * [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html) | ||||
| * [Libraries](https://docs.espressif.com/projects/arduino-esp32/en/latest/libraries.html) | ||||
| * [ESP-IDF as Component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) | ||||
| * [FAQ](https://docs.espressif.com/projects/arduino-esp32/en/latest/faq.html) | ||||
| * [Troubleshooting](https://docs.espressif.com/projects/arduino-esp32/en/latest/troubleshooting.html) | ||||
|  | ||||
| ### Supported Chips | ||||
|  | ||||
| Visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html#supported-soc-s) documentation to see the list of current supported ESP32 SoCs. | ||||
|  | ||||
| ### 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 [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+). | ||||
|  | ||||
| Finally, if you are sure no one else had the issue, follow the **Issue template** or **Feature request template** while reporting any [new Issue](https://github.com/espressif/arduino-esp32/issues/new/choose). | ||||
|  | ||||
| ### Contributing | ||||
|  | ||||
| We welcome contributions to the Arduino ESP32 project! | ||||
|  | ||||
| See [contributing](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html) in the documentation for more information on how to contribute to the project. | ||||
							
								
								
									
										19017
									
								
								boards.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19017
									
								
								boards.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										216
									
								
								cores/esp32/Arduino.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								cores/esp32/Arduino.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| /* | ||||
|  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 "esp_arduino_version.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 | ||||
|  | ||||
| // can't define max() / min() because of conflicts with C++ | ||||
| #define _min(a,b) ((a)<(b)?(a):(b))   | ||||
| #define _max(a,b) ((a)>(b)?(a):(b)) | ||||
| #define _abs(x) ((x)>0?(x):-(x))  // abs() comes from STL | ||||
| #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) | ||||
| #define _round(x)     ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))  // round() comes from STL | ||||
| #define radians(deg) ((deg)*DEG_TO_RAD) | ||||
| #define degrees(rad) ((rad)*RAD_TO_DEG) | ||||
| #define sq(x) ((x)*(x)) | ||||
|  | ||||
| // ESP32xx runs FreeRTOS... disabling interrupts can lead to issues, such as Watchdog Timeout | ||||
| #define sei() portENABLE_INTERRUPTS() | ||||
| #define cli() portDISABLE_INTERRUPTS() | ||||
| #define interrupts() sei() | ||||
| #define noInterrupts() cli() | ||||
|  | ||||
| #define clockCyclesPerMicrosecond() ( (long int)getCpuFrequencyMhz() ) | ||||
| #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 bitToggle(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 digitalPinToTimer(pin)      (0) | ||||
| #define analogInPinToBit(P)         (P) | ||||
| #if SOC_GPIO_PIN_COUNT <= 32 | ||||
| #define digitalPinToPort(pin)       (0) | ||||
| #define digitalPinToBitMask(pin)    (1UL << (pin)) | ||||
| #define portOutputRegister(port)    ((volatile uint32_t*)GPIO_OUT_REG) | ||||
| #define portInputRegister(port)     ((volatile uint32_t*)GPIO_IN_REG) | ||||
| #define portModeRegister(port)      ((volatile uint32_t*)GPIO_ENABLE_REG) | ||||
| #elif SOC_GPIO_PIN_COUNT <= 64 | ||||
| #define digitalPinToPort(pin)       (((pin)>31)?1:0) | ||||
| #define digitalPinToBitMask(pin)    (1UL << (((pin)>31)?((pin)-32):(pin))) | ||||
| #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)) | ||||
| #else | ||||
| #error SOC_GPIO_PIN_COUNT > 64 not implemented | ||||
| #endif | ||||
|  | ||||
| #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; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| void setup(void); | ||||
| void loop(void); | ||||
|  | ||||
| long random(long, long); | ||||
| #endif | ||||
| 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" | ||||
| #include "esp32/spiram.h" | ||||
|  | ||||
| // Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries | ||||
| using std::abs; | ||||
| using std::isinf; | ||||
| using std::isnan; | ||||
| using std::max; | ||||
| using std::min; | ||||
| using std::round; | ||||
|  | ||||
| uint16_t makeWord(uint16_t w); | ||||
| uint16_t makeWord(uint8_t h, uint8_t l); | ||||
|  | ||||
| #define word(...) makeWord(__VA_ARGS__) | ||||
|  | ||||
| size_t getArduinoLoopTaskStackSize(void); | ||||
| #define SET_LOOP_TASK_STACK_SIZE(sz) size_t getArduinoLoopTaskStackSize() { return sz;} | ||||
|  | ||||
| // allows user to bypass esp_spiram_test() | ||||
| #define BYPASS_SPIRAM_TEST(bypass) bool testSPIRAM(void) { if (bypass) return true; else return esp_spiram_test(); } | ||||
|  | ||||
| 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); | ||||
|  | ||||
| void setToneChannel(uint8_t channel = 0); | ||||
| void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); | ||||
| void noTone(uint8_t _pin); | ||||
|  | ||||
| // WMath prototypes | ||||
| long random(long); | ||||
| #endif /* __cplusplus */ | ||||
|  | ||||
| #include "pins_arduino.h" | ||||
|  | ||||
| #endif /* _ESP32_CORE_ARDUINO_H_ */ | ||||
							
								
								
									
										48
									
								
								cores/esp32/Client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								cores/esp32/Client.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| /* | ||||
|  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 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 | ||||
							
								
								
									
										442
									
								
								cores/esp32/Esp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										442
									
								
								cores/esp32/Esp.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,442 @@ | ||||
| /* | ||||
|  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 "esp_sleep.h" | ||||
| #include "esp_spi_flash.h" | ||||
| #include <memory> | ||||
| #include <soc/soc.h> | ||||
| #include <esp_partition.h> | ||||
| extern "C" { | ||||
| #include "esp_ota_ops.h" | ||||
| #include "esp_image_format.h" | ||||
| } | ||||
| #include <MD5Builder.h> | ||||
|  | ||||
| #include "soc/spi_reg.h" | ||||
| #include "esp_system.h" | ||||
| #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #include "esp32/rom/spi_flash.h" | ||||
| #include "soc/efuse_reg.h" | ||||
| #define ESP_FLASH_IMAGE_BASE 0x1000     // Flash offset containing flash size and spi mode | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "esp32s2/rom/spi_flash.h" | ||||
| #include "soc/efuse_reg.h" | ||||
| #define ESP_FLASH_IMAGE_BASE 0x1000 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "esp32s3/rom/spi_flash.h" | ||||
| #include "soc/efuse_reg.h" | ||||
| #define ESP_FLASH_IMAGE_BASE 0x0000     // Esp32s3 is located at 0x0000 | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #include "esp32c3/rom/spi_flash.h" | ||||
| #define ESP_FLASH_IMAGE_BASE 0x0000     // Esp32c3 is located at 0x0000 | ||||
| #else  | ||||
| #error Target CONFIG_IDF_TARGET is not supported | ||||
| #endif | ||||
| #else // ESP32 Before IDF 4.0 | ||||
| #include "rom/spi_flash.h" | ||||
| #define ESP_FLASH_IMAGE_BASE 0x1000 | ||||
| #endif | ||||
|  | ||||
| // REG_SPI_BASE is not defined for S3/C3 ?? | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 | ||||
|   #ifndef REG_SPI_BASE | ||||
|   #define REG_SPI_BASE(i)     (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) | ||||
|   #endif // REG_SPI_BASE | ||||
| #endif // TARGET | ||||
|  | ||||
| /** | ||||
|  * 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); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	if(psramFound()){ | ||||
| 	    multi_heap_info_t info; | ||||
| 	    heap_caps_get_info(&info, MALLOC_CAP_SPIRAM); | ||||
| 	    return info.total_free_bytes + info.total_allocated_bytes; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| uint32_t EspClass::getFreePsram(void) | ||||
| { | ||||
| 	if(psramFound()){ | ||||
| 	    return heap_caps_get_free_size(MALLOC_CAP_SPIRAM); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| uint32_t EspClass::getMinFreePsram(void) | ||||
| { | ||||
| 	if(psramFound()){ | ||||
| 	    return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| uint32_t EspClass::getMaxAllocPsram(void) | ||||
| { | ||||
| 	if(psramFound()){ | ||||
| 	    return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| 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::getChipModel(void) | ||||
| { | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); | ||||
|     uint32_t pkg_ver = chip_ver & 0x7; | ||||
|     switch (pkg_ver) { | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6 : | ||||
|             return "ESP32-D0WDQ6"; | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5 : | ||||
|             return "ESP32-D0WDQ5"; | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 : | ||||
|             return "ESP32-D2WDQ5"; | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 : | ||||
|             return "ESP32-PICO-D2"; | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 : | ||||
|             return "ESP32-PICO-D4"; | ||||
|         case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302 : | ||||
|             return "ESP32-PICO-V3-02"; | ||||
|         default: | ||||
|             return "Unknown"; | ||||
|     } | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
|     uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION); | ||||
|     switch (pkg_ver) { | ||||
|     case 0: | ||||
|       return "ESP32-S2"; | ||||
|     case 1: | ||||
|       return "ESP32-S2FH16"; | ||||
|     case 2: | ||||
|       return "ESP32-S2FH32"; | ||||
|     default: | ||||
|       return "ESP32-S2 (Unknown)"; | ||||
|     } | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
|     return "ESP32-S3"; | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
|     return "ESP32-C3"; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| uint8_t EspClass::getChipCores(void) | ||||
| { | ||||
|     esp_chip_info_t chip_info; | ||||
|     esp_chip_info(&chip_info); | ||||
|     return chip_info.cores; | ||||
| } | ||||
|  | ||||
| const char * EspClass::getSdkVersion(void) | ||||
| { | ||||
|     return esp_get_idf_version(); | ||||
| } | ||||
|  | ||||
| uint32_t ESP_getFlashChipId(void) | ||||
| { | ||||
|   uint32_t id = g_rom_flashchip.device_id; | ||||
|   id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); | ||||
|   return id; | ||||
| } | ||||
|  | ||||
| uint32_t EspClass::getFlashChipSize(void) | ||||
| { | ||||
|   uint32_t id = (ESP_getFlashChipId() >> 16) & 0xFF; | ||||
|   return 2 << (id - 1); | ||||
| } | ||||
|  | ||||
| uint32_t EspClass::getFlashChipSpeed(void) | ||||
| { | ||||
|     esp_image_header_t fhdr; | ||||
|     if(flashRead(ESP_FLASH_IMAGE_BASE, (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) | ||||
| { | ||||
|    #if CONFIG_IDF_TARGET_ESP32S2 | ||||
|    uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL); | ||||
|    #else | ||||
|    uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); | ||||
|    #endif | ||||
|    /* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/ | ||||
|    if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO | ||||
|        return (FM_QIO); | ||||
|    } else if (spi_ctrl & BIT(20)) { //SPI_FREAD_QUAD | ||||
|        return (FM_QOUT); | ||||
|    } else if (spi_ctrl &  BIT(23)) { //SPI_FREAD_DIO | ||||
|        return (FM_DIO); | ||||
|    } else if (spi_ctrl & BIT(14)) { // SPI_FREAD_DUAL | ||||
|        return (FM_DOUT); | ||||
|    } else if (spi_ctrl & BIT(13)) { //SPI_FASTRD_MODE | ||||
|        return (FM_FAST_READ); | ||||
|    } else { | ||||
|        return (FM_SLOW_READ); | ||||
|    } | ||||
|    return (FM_DOUT); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| bool EspClass::partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size)  | ||||
| { | ||||
|     return esp_partition_erase_range(partition, offset, size) == ESP_OK; | ||||
| } | ||||
|  | ||||
| bool EspClass::partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)  | ||||
| { | ||||
|     return esp_partition_write(partition, offset, data, size) == ESP_OK; | ||||
| } | ||||
|  | ||||
| bool EspClass::partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)  | ||||
| { | ||||
|     return esp_partition_read(partition, offset, data, size) == ESP_OK; | ||||
| } | ||||
|  | ||||
| uint64_t EspClass::getEfuseMac(void) | ||||
| { | ||||
|     uint64_t _chipmacid = 0LL; | ||||
|     esp_efuse_mac_get_default((uint8_t*) (&_chipmacid)); | ||||
|     return _chipmacid; | ||||
| } | ||||
							
								
								
									
										119
									
								
								cores/esp32/Esp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								cores/esp32/Esp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| /* | ||||
|  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> | ||||
| #include <esp_partition.h> | ||||
| #include <hal/cpu_hal.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(); | ||||
|     const char * getChipModel(); | ||||
|     uint8_t getChipCores(); | ||||
|     uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); } | ||||
|     inline uint32_t getCycleCount() __attribute__((always_inline)); | ||||
|     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); | ||||
|  | ||||
|     bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size); | ||||
|     bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size); | ||||
|     bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size); | ||||
|  | ||||
|     uint64_t getEfuseMac(); | ||||
|  | ||||
| }; | ||||
|  | ||||
| uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount() | ||||
| { | ||||
|     return cpu_hal_get_cycle_count(); | ||||
| } | ||||
|  | ||||
| extern EspClass ESP; | ||||
|  | ||||
| #endif //ESP_H | ||||
							
								
								
									
										424
									
								
								cores/esp32/FirmwareMSC.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								cores/esp32/FirmwareMSC.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,424 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #include "FirmwareMSC.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_MSC_ENABLED | ||||
|  | ||||
| #include <cstring> | ||||
| #include "esp_partition.h" | ||||
| #include "esp_ota_ops.h" | ||||
| #include "esp32-hal.h" | ||||
| #include "pins_arduino.h" | ||||
| #include "firmware_msc_fat.h" | ||||
|  | ||||
| #ifndef USB_FW_MSC_VENDOR_ID | ||||
| #define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars | ||||
| #endif | ||||
| #ifndef USB_FW_MSC_PRODUCT_ID | ||||
| #define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars | ||||
| #endif | ||||
| #ifndef USB_FW_MSC_PRODUCT_REVISION | ||||
| #define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars | ||||
| #endif | ||||
| #ifndef USB_FW_MSC_VOLUME_NAME | ||||
| #define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars | ||||
| #endif | ||||
| #ifndef USB_FW_MSC_SERIAL_NUMBER | ||||
| #define USB_FW_MSC_SERIAL_NUMBER 0x00000000 | ||||
| #endif | ||||
|  | ||||
| ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); | ||||
| esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); | ||||
| esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); | ||||
|  | ||||
| //General Variables | ||||
| static uint8_t * msc_ram_disk = NULL; | ||||
| static fat_boot_sector_t * msc_boot = NULL; | ||||
| static uint8_t * msc_table = NULL; | ||||
| static uint16_t msc_table_sectors = 0; | ||||
| static uint16_t msc_total_sectors = 0; | ||||
| static bool mcs_is_fat16 = false; | ||||
|  | ||||
| //Firmware Read | ||||
| static const esp_partition_t* msc_run_partition = NULL; | ||||
| static uint16_t fw_start_sector = 0; | ||||
| static uint16_t fw_end_sector = 0; | ||||
| static size_t fw_size = 0; | ||||
| static fat_dir_entry_t * fw_entry = NULL; | ||||
|  | ||||
| //Firmware Write | ||||
| typedef enum { | ||||
|   MSC_UPDATE_IDLE, | ||||
|   MSC_UPDATE_STARTING, | ||||
|   MSC_UPDATE_RUNNING, | ||||
|   MSC_UPDATE_END | ||||
| } msc_update_state_t; | ||||
|  | ||||
| static const esp_partition_t* msc_ota_partition = NULL; | ||||
| static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE; | ||||
| static uint16_t msc_update_start_sector = 0; | ||||
| static uint32_t msc_update_bytes_written = 0; | ||||
| static fat_dir_entry_t * msc_update_entry = NULL; | ||||
|  | ||||
| static uint32_t get_firmware_size(const esp_partition_t* partition){ | ||||
|   esp_image_metadata_t data; | ||||
|   const esp_partition_pos_t running_pos  = { | ||||
|       .offset = partition->address, | ||||
|       .size = partition->size, | ||||
|   }; | ||||
|   data.start_addr = running_pos.offset; | ||||
|   esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data); | ||||
|   return data.image_len; | ||||
| } | ||||
|  | ||||
| //Get number of sectors required based on the size of the firmware and OTA partition | ||||
| static size_t msc_update_get_required_disk_sectors(){ | ||||
|   size_t data_sectors = 16; | ||||
|   size_t total_sectors = 0; | ||||
|   msc_run_partition = esp_ota_get_running_partition(); | ||||
|   msc_ota_partition = esp_ota_get_next_update_partition(NULL); | ||||
|   if(msc_run_partition){ | ||||
|     fw_size = get_firmware_size(msc_run_partition); | ||||
|     data_sectors += FAT_SIZE_TO_SECTORS(fw_size); | ||||
|     log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size)); | ||||
|   } else { | ||||
|     log_w("APP partition not found. Reading disabled"); | ||||
|   } | ||||
|   if(msc_ota_partition){ | ||||
|     data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size); | ||||
|     log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size)); | ||||
|   } else { | ||||
|     log_w("OTA partition not found. Writing disabled"); | ||||
|   } | ||||
|   msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false); | ||||
|   total_sectors = data_sectors + msc_table_sectors + 2; | ||||
|   if(total_sectors > 0xFF4){ | ||||
|     log_d("USING FAT16"); | ||||
|     mcs_is_fat16 = true; | ||||
|     total_sectors -= msc_table_sectors; | ||||
|     msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true); | ||||
|     total_sectors += msc_table_sectors; | ||||
|   } else { | ||||
|     log_d("USING FAT12"); | ||||
|     mcs_is_fat16 = false; | ||||
|   } | ||||
|   log_d("FAT sector size: %u", DISK_SECTOR_SIZE); | ||||
|   log_d("FAT data sectors: %u", data_sectors); | ||||
|   log_d("FAT table sectors: %u", msc_table_sectors); | ||||
|   log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024); | ||||
|   return total_sectors; | ||||
| } | ||||
|  | ||||
| //setup the ramdisk and add the firmware download file | ||||
| static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){ | ||||
|   msc_total_sectors = msc_update_get_required_disk_sectors(); | ||||
|   uint8_t ram_sectors = msc_table_sectors + 2; | ||||
|   msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE); | ||||
|   if(!msc_ram_disk){ | ||||
|     log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE); | ||||
|     return false; | ||||
|   } | ||||
|   fw_start_sector = ram_sectors; | ||||
|   fw_end_sector = fw_start_sector; | ||||
|   msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number); | ||||
|   msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16); | ||||
|   //fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label); | ||||
|   if(msc_run_partition){ | ||||
|     fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16); | ||||
|     fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static void msc_update_delete_disk(){ | ||||
|   fw_entry = NULL; | ||||
|   fw_size = 0; | ||||
|   fw_end_sector = 0; | ||||
|   fw_start_sector = 0; | ||||
|   msc_table = NULL; | ||||
|   msc_boot = NULL; | ||||
|   msc_table_sectors = 0; | ||||
|   msc_total_sectors = 0; | ||||
|   msc_run_partition = NULL; | ||||
|   msc_ota_partition = NULL; | ||||
|   msc_update_state = MSC_UPDATE_IDLE; | ||||
|   msc_update_start_sector = 0; | ||||
|   msc_update_bytes_written = 0; | ||||
|   msc_update_entry = NULL; | ||||
|   free(msc_ram_disk); | ||||
|   msc_ram_disk = NULL; | ||||
| } | ||||
|  | ||||
| //filter out entries to only include BINs in the root folder | ||||
| static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){ | ||||
|   fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); | ||||
|   fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry; | ||||
|  | ||||
|   //empty entry | ||||
|   if(entry->file_magic == 0){ | ||||
|     return NULL; | ||||
|   } | ||||
|   //long file name | ||||
|   if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){ | ||||
|     return NULL; | ||||
|   } | ||||
|   //only files marked as archives | ||||
|   if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){ | ||||
|     return NULL; | ||||
|   } | ||||
|   //deleted | ||||
|   if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){ | ||||
|     return NULL; | ||||
|   } | ||||
|   //not bins | ||||
|   if(memcmp("BIN", entry->file_extension, 3)){ | ||||
|     return NULL; | ||||
|   } | ||||
|   return entry; | ||||
| } | ||||
|  | ||||
| //get an empty bin (the host will add an entry for file about to be written with size of zero) | ||||
| static fat_dir_entry_t * msc_update_find_new_bin(){ | ||||
|   for(uint8_t i=16; i;){ | ||||
|     i--; | ||||
|     fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); | ||||
|     if(entry && entry->file_size == 0){ | ||||
|       return entry; | ||||
|     } | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| //get a bin starting from particular sector | ||||
| static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){ | ||||
|   for(uint8_t i=16; i; ){ | ||||
|     i--; | ||||
|     fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); | ||||
|     if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){ | ||||
|       return entry; | ||||
|     } | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| //write the new data and erase the flash blocks when necessary | ||||
| static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){ | ||||
|   esp_err_t err = ESP_OK; | ||||
|   if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){ | ||||
|     err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE); | ||||
|     log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK"); | ||||
|     if(err != ESP_OK){ | ||||
|       return err; | ||||
|     } | ||||
|   } | ||||
|   return esp_partition_write(partition, offset, data, size); | ||||
| } | ||||
|  | ||||
| //called when error was encountered while updating | ||||
| static void msc_update_error(){ | ||||
|   log_e("UPDATE_ERROR: %u", msc_update_bytes_written); | ||||
|   arduino_firmware_msc_event_data_t p; | ||||
|   p.error.size = msc_update_bytes_written; | ||||
|   arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
|   msc_update_state = MSC_UPDATE_IDLE; | ||||
|   msc_update_entry = NULL; | ||||
|   msc_update_bytes_written = 0; | ||||
|   msc_update_start_sector = 0; | ||||
| } | ||||
|  | ||||
| //called when all firmware bytes have been received | ||||
| static void msc_update_end(){ | ||||
|   log_d("UPDATE_END: %u", msc_update_entry->file_size); | ||||
|   msc_update_state = MSC_UPDATE_END; | ||||
|   size_t ota_size = get_firmware_size(msc_ota_partition); | ||||
|   if(ota_size != msc_update_entry->file_size){ | ||||
|     log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size); | ||||
|     msc_update_error(); | ||||
|     return; | ||||
|   } | ||||
|   if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){ | ||||
|     log_e("ENABLING OTA PARTITION FAILED"); | ||||
|     msc_update_error(); | ||||
|     return; | ||||
|   } | ||||
|   arduino_firmware_msc_event_data_t p; | ||||
|   p.end.size = msc_update_entry->file_size; | ||||
|   arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){ | ||||
|   //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); | ||||
|   if(lba < fw_start_sector){ | ||||
|     //write to sectors that are in RAM | ||||
|     memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize); | ||||
|     if(msc_ota_partition && lba == (fw_start_sector - 1)){ | ||||
|       //monitor the root folder table | ||||
|       if(msc_update_state <= MSC_UPDATE_RUNNING){ | ||||
|         fat_dir_entry_t * update_entry = msc_update_find_new_bin(); | ||||
|         if(update_entry) { | ||||
|           if(msc_update_entry) { | ||||
|             log_v("REPLACING ENTRY"); | ||||
|           } else { | ||||
|             log_v("ASSIGNING ENTRY"); | ||||
|           } | ||||
|           if(msc_update_state <= MSC_UPDATE_STARTING){ | ||||
|             msc_update_state = MSC_UPDATE_STARTING; | ||||
|             msc_update_bytes_written = 0; | ||||
|             msc_update_start_sector = 0; | ||||
|           } | ||||
|           msc_update_entry = update_entry; | ||||
|         } else if(msc_update_state == MSC_UPDATE_RUNNING){ | ||||
|           if(!msc_update_entry && msc_update_start_sector){ | ||||
|             msc_update_entry = msc_update_find_bin(msc_update_start_sector); | ||||
|           } | ||||
|           if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){ | ||||
|             msc_update_end(); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } else if(msc_ota_partition && lba >= msc_update_start_sector){ | ||||
|     //handle writes to the region where the new firmware will be uploaded | ||||
|     arduino_firmware_msc_event_data_t p; | ||||
|     if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){ | ||||
|       msc_update_state = MSC_UPDATE_RUNNING; | ||||
|       msc_update_start_sector = lba; | ||||
|       msc_update_bytes_written = 0; | ||||
|       log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table); | ||||
|       arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
|       if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ | ||||
|         log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); | ||||
|         msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; | ||||
|         p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; | ||||
|         p.write.size = bufsize; | ||||
|         arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
|       } else { | ||||
|         msc_update_error(); | ||||
|         return 0; | ||||
|       } | ||||
|     } else if(msc_update_state == MSC_UPDATE_RUNNING){ | ||||
|       if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){ | ||||
|         bufsize = msc_update_entry->file_size - msc_update_bytes_written; | ||||
|       } | ||||
|       if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ | ||||
|         log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); | ||||
|         msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; | ||||
|         p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; | ||||
|         p.write.size = bufsize; | ||||
|         arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
|         if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){ | ||||
|           msc_update_end(); | ||||
|         } | ||||
|       } else { | ||||
|         msc_update_error(); | ||||
|         return 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return bufsize; | ||||
| } | ||||
|  | ||||
| static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){ | ||||
|   //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); | ||||
|   if(lba < fw_start_sector){ | ||||
|     memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize); | ||||
|   } else if(msc_run_partition && lba < fw_end_sector){ | ||||
|     //read the currently running firmware | ||||
|     if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){ | ||||
|       return 0; | ||||
|     } | ||||
|   } else { | ||||
|     memset(buffer, 0, bufsize); | ||||
|   } | ||||
|   return bufsize; | ||||
| } | ||||
|  | ||||
| static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){ | ||||
|   //log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject); | ||||
|   arduino_firmware_msc_event_data_t p; | ||||
|   p.power.power_condition = power_condition; | ||||
|   p.power.start = start; | ||||
|   p.power.load_eject = load_eject; | ||||
|   arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static volatile TaskHandle_t msc_task_handle = NULL; | ||||
| static void msc_task(void *pvParameters){ | ||||
|   for (;;) { | ||||
|     if(msc_update_state == MSC_UPDATE_END){ | ||||
|       delay(100); | ||||
|       esp_restart(); | ||||
|     } | ||||
|     delay(100); | ||||
|   } | ||||
|   msc_task_handle = NULL; | ||||
|   vTaskDelete(NULL); | ||||
| } | ||||
|  | ||||
| FirmwareMSC::FirmwareMSC():msc(){} | ||||
|  | ||||
| FirmwareMSC::~FirmwareMSC(){ | ||||
|   end(); | ||||
| } | ||||
|  | ||||
| bool FirmwareMSC::begin(){ | ||||
|   if(msc_ram_disk){ | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){ | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if(!msc_task_handle){ | ||||
|     xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0); | ||||
|     if(!msc_task_handle){ | ||||
|       msc_update_delete_disk(); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   msc.vendorID(USB_FW_MSC_VENDOR_ID); | ||||
|   msc.productID(USB_FW_MSC_PRODUCT_ID); | ||||
|   msc.productRevision(USB_FW_MSC_PRODUCT_REVISION); | ||||
|   msc.onStartStop(msc_start_stop); | ||||
|   msc.onRead(msc_read); | ||||
|   msc.onWrite(msc_write); | ||||
|   msc.mediaPresent(true); | ||||
|   msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void FirmwareMSC::end(){ | ||||
|   msc.end(); | ||||
|   if(msc_task_handle){ | ||||
|     vTaskDelete(msc_task_handle); | ||||
|     msc_task_handle = NULL; | ||||
|   } | ||||
|   msc_update_delete_disk(); | ||||
| } | ||||
|  | ||||
| void FirmwareMSC::onEvent(esp_event_handler_t callback){ | ||||
|     onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback); | ||||
| } | ||||
| void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){ | ||||
|     arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this); | ||||
| } | ||||
|  | ||||
| #if ARDUINO_USB_MSC_ON_BOOT | ||||
| FirmwareMSC MSC_Update; | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_USB_MSC_ENABLED */ | ||||
							
								
								
									
										70
									
								
								cores/esp32/FirmwareMSC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								cores/esp32/FirmwareMSC.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #pragma once | ||||
| #include <stdbool.h> | ||||
| #include "USBMSC.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_MSC_ENABLED | ||||
|  | ||||
| #include "esp_event.h" | ||||
|  | ||||
| ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); | ||||
|  | ||||
| typedef enum { | ||||
|     ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID, | ||||
|     ARDUINO_FIRMWARE_MSC_START_EVENT = 0, | ||||
|     ARDUINO_FIRMWARE_MSC_WRITE_EVENT, | ||||
|     ARDUINO_FIRMWARE_MSC_END_EVENT, | ||||
|     ARDUINO_FIRMWARE_MSC_ERROR_EVENT, | ||||
|     ARDUINO_FIRMWARE_MSC_POWER_EVENT, | ||||
|     ARDUINO_FIRMWARE_MSC_MAX_EVENT, | ||||
| } arduino_firmware_msc_event_t; | ||||
|  | ||||
| typedef union { | ||||
|     struct { | ||||
|             size_t offset; | ||||
|             size_t size; | ||||
|     } write; | ||||
|     struct { | ||||
|             uint8_t power_condition; | ||||
|             bool start; | ||||
|             bool load_eject; | ||||
|     } power; | ||||
|     struct { | ||||
|             size_t size; | ||||
|     } end; | ||||
|     struct { | ||||
|             size_t size; | ||||
|     } error; | ||||
| } arduino_firmware_msc_event_data_t; | ||||
|  | ||||
| class FirmwareMSC { | ||||
| private: | ||||
|   USBMSC msc; | ||||
|  | ||||
| public: | ||||
|   FirmwareMSC(); | ||||
|   ~FirmwareMSC(); | ||||
|   bool begin(); | ||||
|   void end(); | ||||
|   void onEvent(esp_event_handler_t callback); | ||||
|   void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback); | ||||
| }; | ||||
|  | ||||
| #if ARDUINO_USB_MSC_ON_BOOT | ||||
| extern FirmwareMSC MSC_Update; | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_MSC_ENABLED */ | ||||
							
								
								
									
										44
									
								
								cores/esp32/FunctionalInterrupt.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								cores/esp32/FunctionalInterrupt.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| /* | ||||
|  * 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 ARDUINO_ISR_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; | ||||
|    } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										20
									
								
								cores/esp32/FunctionalInterrupt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								cores/esp32/FunctionalInterrupt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| /* | ||||
|  * 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_ */ | ||||
							
								
								
									
										392
									
								
								cores/esp32/HWCDC.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								cores/esp32/HWCDC.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,392 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #include "USB.h" | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
|  | ||||
| #include "esp32-hal.h" | ||||
| #include "HWCDC.h" | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/semphr.h" | ||||
| #include "freertos/queue.h" | ||||
| #include "freertos/ringbuf.h" | ||||
| #include "esp_intr_alloc.h" | ||||
| #include "soc/periph_defs.h" | ||||
| #include "hal/usb_serial_jtag_ll.h" | ||||
|  | ||||
| ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS); | ||||
|  | ||||
| static RingbufHandle_t tx_ring_buf = NULL; | ||||
| static xQueueHandle rx_queue = NULL; | ||||
| static uint8_t rx_data_buf[64]; | ||||
| static intr_handle_t intr_handle = NULL; | ||||
| static volatile bool initial_empty = false; | ||||
| static xSemaphoreHandle tx_lock = NULL; | ||||
| static uint32_t tx_timeout_ms = 200; | ||||
| static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL; | ||||
|  | ||||
| static esp_err_t arduino_hw_cdc_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, BaseType_t *task_unblocked){ | ||||
|     if(arduino_hw_cdc_event_loop_handle == NULL){ | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     return esp_event_isr_post_to(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_data, event_data_size, task_unblocked); | ||||
| } | ||||
|  | ||||
| static esp_err_t arduino_hw_cdc_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){ | ||||
|     if (!arduino_hw_cdc_event_loop_handle) { | ||||
|         esp_event_loop_args_t event_task_args = { | ||||
|             .queue_size = 5, | ||||
|             .task_name = "arduino_hw_cdc_events", | ||||
|             .task_priority = 5, | ||||
|             .task_stack_size = 2048, | ||||
|             .task_core_id = tskNO_AFFINITY | ||||
|         }; | ||||
|         if (esp_event_loop_create(&event_task_args, &arduino_hw_cdc_event_loop_handle) != ESP_OK) { | ||||
|             log_e("esp_event_loop_create failed"); | ||||
|         } | ||||
|     } | ||||
|     if(arduino_hw_cdc_event_loop_handle == NULL){ | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     return esp_event_handler_register_with(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_handler, event_handler_arg); | ||||
| } | ||||
|  | ||||
| static void hw_cdc_isr_handler(void *arg) { | ||||
|     portBASE_TYPE xTaskWoken = 0; | ||||
|     uint32_t usbjtag_intr_status = 0; | ||||
|     arduino_hw_cdc_event_data_t event = {0}; | ||||
|     usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); | ||||
|  | ||||
|     if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { | ||||
|         // Interrupt tells us the host picked up the data we sent. | ||||
|         if (usb_serial_jtag_ll_txfifo_writable() == 1) { | ||||
|             // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. | ||||
|             usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|  | ||||
|             if(!initial_empty){ | ||||
|                 initial_empty = true; | ||||
|                 //send event? | ||||
|                 //ets_printf("CONNECTED\n"); | ||||
|                 arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); | ||||
|             } | ||||
|             size_t queued_size; | ||||
|             uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64); | ||||
|             // If the hardware fifo is avaliable, write in it. Otherwise, do nothing. | ||||
|             if (queued_buff != NULL) {  //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called. | ||||
|                 //Copy the queued buffer into the TX FIFO | ||||
|                 usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|                 usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size); | ||||
|                 usb_serial_jtag_ll_txfifo_flush(); | ||||
|                 vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken); | ||||
|                 usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|                 //send event? | ||||
|                 //ets_printf("TX:%u\n", queued_size); | ||||
|                 event.tx.len = queued_size; | ||||
|                 arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_TX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); | ||||
|             } | ||||
|         } else { | ||||
|             usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { | ||||
|         // read rx buffer(max length is 64), and send avaliable data to ringbuffer. | ||||
|         // Ensure the rx buffer size is larger than RX_MAX_SIZE. | ||||
|         usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); | ||||
|         uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rx_data_buf, 64); | ||||
|         uint32_t i=0; | ||||
|         for(i=0; i<rx_fifo_len; i++){ | ||||
|             if(rx_queue == NULL || !xQueueSendFromISR(rx_queue, rx_data_buf+i, &xTaskWoken)){ | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         //send event? | ||||
|         //ets_printf("RX:%u/%u\n", i, rx_fifo_len); | ||||
|         event.rx.len = i; | ||||
|         arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_RX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); | ||||
|     } | ||||
|  | ||||
|     if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) { | ||||
|         usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_BUS_RESET); | ||||
|         initial_empty = false; | ||||
|         usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|         //ets_printf("BUS_RESET\n"); | ||||
|         arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_BUS_RESET_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); | ||||
|     } | ||||
|  | ||||
|     if (xTaskWoken == pdTRUE) { | ||||
|         portYIELD_FROM_ISR(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void ARDUINO_ISR_ATTR cdc0_write_char(char c) { | ||||
|     if(xPortInIsrContext()){ | ||||
|         xRingbufferSendFromISR(tx_ring_buf, (void*) (&c), 1, NULL); | ||||
|     } else { | ||||
|         xRingbufferSend(tx_ring_buf, (void*) (&c), 1, tx_timeout_ms / portTICK_PERIOD_MS); | ||||
|     } | ||||
|     usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
| } | ||||
|  | ||||
| HWCDC::HWCDC() { | ||||
|  | ||||
| } | ||||
|  | ||||
| HWCDC::~HWCDC(){ | ||||
|     end(); | ||||
| } | ||||
|  | ||||
| HWCDC::operator bool() const | ||||
| { | ||||
|     return initial_empty; | ||||
| } | ||||
|  | ||||
| void HWCDC::onEvent(esp_event_handler_t callback){ | ||||
|     onEvent(ARDUINO_HW_CDC_ANY_EVENT, callback); | ||||
| } | ||||
|  | ||||
| void HWCDC::onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback){ | ||||
|     arduino_hw_cdc_event_handler_register_with(ARDUINO_HW_CDC_EVENTS, event, callback, this); | ||||
| } | ||||
|  | ||||
| void HWCDC::begin(unsigned long baud) | ||||
| { | ||||
|     if(tx_lock == NULL) { | ||||
|         tx_lock = xSemaphoreCreateMutex(); | ||||
|     } | ||||
|     setRxBufferSize(256);//default if not preset | ||||
|     setTxBufferSize(256);//default if not preset | ||||
|  | ||||
|     usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|     usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|     usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_BUS_RESET); | ||||
|     if(!intr_handle && esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_isr_handler, NULL, &intr_handle) != ESP_OK){ | ||||
|         isr_log_e("HW USB CDC failed to init interrupts"); | ||||
|         end(); | ||||
|         return; | ||||
|     } | ||||
|     usb_serial_jtag_ll_txfifo_flush(); | ||||
| } | ||||
|  | ||||
| void HWCDC::end() | ||||
| { | ||||
|     //Disable tx/rx interrupt. | ||||
|     usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|     esp_intr_free(intr_handle); | ||||
|     intr_handle = NULL; | ||||
|     if(tx_lock != NULL) { | ||||
|         vSemaphoreDelete(tx_lock); | ||||
|     } | ||||
|     setRxBufferSize(0); | ||||
|     setTxBufferSize(0); | ||||
|     if (arduino_hw_cdc_event_loop_handle) { | ||||
|         esp_event_loop_delete(arduino_hw_cdc_event_loop_handle); | ||||
|         arduino_hw_cdc_event_loop_handle = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void HWCDC::setTxTimeoutMs(uint32_t timeout){ | ||||
|     tx_timeout_ms = timeout; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * WRITING | ||||
| */ | ||||
|  | ||||
| size_t HWCDC::setTxBufferSize(size_t tx_queue_len){ | ||||
|     if(tx_ring_buf){ | ||||
|         if(!tx_queue_len){ | ||||
|             vRingbufferDelete(tx_ring_buf); | ||||
|             tx_ring_buf = NULL; | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|     tx_ring_buf = xRingbufferCreate(tx_queue_len, RINGBUF_TYPE_BYTEBUF); | ||||
|     if(!tx_ring_buf){ | ||||
|         return 0; | ||||
|     } | ||||
|     return tx_queue_len; | ||||
| } | ||||
|  | ||||
| int HWCDC::availableForWrite(void) | ||||
| { | ||||
|     if(tx_ring_buf == NULL || tx_lock == NULL){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return 0; | ||||
|     } | ||||
|     size_t a = xRingbufferGetCurFreeSize(tx_ring_buf); | ||||
|     xSemaphoreGive(tx_lock); | ||||
|     return a; | ||||
| } | ||||
|  | ||||
| size_t HWCDC::write(const uint8_t *buffer, size_t size) | ||||
| { | ||||
|     if(buffer == NULL || size == 0 || tx_ring_buf == NULL || tx_lock == NULL){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return 0; | ||||
|     } | ||||
|     size_t max_size = xRingbufferGetMaxItemSize(tx_ring_buf); | ||||
|     size_t space = xRingbufferGetCurFreeSize(tx_ring_buf); | ||||
|     size_t to_send = size, so_far = 0; | ||||
|  | ||||
|     if(space > size){ | ||||
|         space = size; | ||||
|     } | ||||
|     // Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR. | ||||
|     if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){ | ||||
|         size = 0; | ||||
|     } else { | ||||
|         to_send -= space; | ||||
|         so_far += space; | ||||
|         // Now trigger the ISR to read data from the ring buffer. | ||||
|         usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|  | ||||
|         while(to_send){ | ||||
|             if(max_size > to_send){ | ||||
|                 max_size = to_send; | ||||
|             } | ||||
|             // Blocking method, Sending data to ringbuffer, and handle the data in ISR. | ||||
|             if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ | ||||
|                 size = so_far; | ||||
|                 break; | ||||
|             } | ||||
|             so_far += max_size; | ||||
|             to_send -= max_size; | ||||
|             // Now trigger the ISR to read data from the ring buffer. | ||||
|             usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|         } | ||||
|     } | ||||
|     xSemaphoreGive(tx_lock); | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| size_t HWCDC::write(uint8_t c) | ||||
| { | ||||
|     return write(&c, 1); | ||||
| } | ||||
|  | ||||
| void HWCDC::flush(void) | ||||
| { | ||||
|     if(tx_ring_buf == NULL || tx_lock == NULL){ | ||||
|         return; | ||||
|     } | ||||
|     if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return; | ||||
|     } | ||||
|     UBaseType_t uxItemsWaiting = 0; | ||||
|     vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); | ||||
|     if(uxItemsWaiting){ | ||||
|         // Now trigger the ISR to read data from the ring buffer. | ||||
|         usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); | ||||
|     } | ||||
|     while(uxItemsWaiting){ | ||||
|         delay(5); | ||||
|         vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); | ||||
|     } | ||||
|     xSemaphoreGive(tx_lock); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * READING | ||||
| */ | ||||
|  | ||||
| size_t HWCDC::setRxBufferSize(size_t rx_queue_len){ | ||||
|     if(rx_queue){ | ||||
|         if(!rx_queue_len){ | ||||
|             vQueueDelete(rx_queue); | ||||
|             rx_queue = NULL; | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|     rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); | ||||
|     if(!rx_queue){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(!tx_ring_buf){ | ||||
|         tx_ring_buf = xRingbufferCreate(rx_queue_len, RINGBUF_TYPE_BYTEBUF); | ||||
|     } | ||||
|     return rx_queue_len; | ||||
| } | ||||
|  | ||||
| int HWCDC::available(void) | ||||
| { | ||||
|     if(rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     return uxQueueMessagesWaiting(rx_queue); | ||||
| } | ||||
|  | ||||
| int HWCDC::peek(void) | ||||
| { | ||||
|     if(rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c; | ||||
|     if(xQueuePeek(rx_queue, &c, 0)) { | ||||
|         return c; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int HWCDC::read(void) | ||||
| { | ||||
|     if(rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|     if(xQueueReceive(rx_queue, &c, 0)) { | ||||
|         return c; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| size_t HWCDC::read(uint8_t *buffer, size_t size) | ||||
| { | ||||
|     if(rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|     size_t count = 0; | ||||
|     while(count < size && xQueueReceive(rx_queue, &c, 0)){ | ||||
|         buffer[count++] = c; | ||||
|     } | ||||
|     return count; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * DEBUG | ||||
| */ | ||||
|  | ||||
| void HWCDC::setDebugOutput(bool en) | ||||
| { | ||||
|     if(en) { | ||||
|         uartSetDebug(NULL); | ||||
|         ets_install_putc1((void (*)(char)) &cdc0_write_char); | ||||
|     } else { | ||||
|         ets_install_putc1(NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #if ARDUINO_USB_MODE | ||||
| #if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC | ||||
| HWCDC Serial; | ||||
| #else | ||||
| HWCDC USBSerial; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_CDC_ENABLED */ | ||||
							
								
								
									
										109
									
								
								cores/esp32/HWCDC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								cores/esp32/HWCDC.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
|  | ||||
| #include <inttypes.h> | ||||
| #include "esp_event.h" | ||||
| #include "Stream.h" | ||||
|  | ||||
| ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS); | ||||
|  | ||||
| typedef enum { | ||||
|     ARDUINO_HW_CDC_ANY_EVENT = ESP_EVENT_ANY_ID, | ||||
|     ARDUINO_HW_CDC_CONNECTED_EVENT = 0, | ||||
|     ARDUINO_HW_CDC_BUS_RESET_EVENT, | ||||
|     ARDUINO_HW_CDC_RX_EVENT, | ||||
|     ARDUINO_HW_CDC_TX_EVENT, | ||||
|     ARDUINO_HW_CDC_MAX_EVENT, | ||||
| } arduino_hw_cdc_event_t; | ||||
|  | ||||
| typedef union { | ||||
|     struct { | ||||
|             size_t len; | ||||
|     } rx; | ||||
|     struct { | ||||
|             size_t len; | ||||
|     } tx; | ||||
| } arduino_hw_cdc_event_data_t; | ||||
|  | ||||
| class HWCDC: public Stream | ||||
| { | ||||
| public: | ||||
|     HWCDC(); | ||||
|     ~HWCDC(); | ||||
|  | ||||
|     void onEvent(esp_event_handler_t callback); | ||||
|     void onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback); | ||||
|  | ||||
|     size_t setRxBufferSize(size_t); | ||||
|     size_t setTxBufferSize(size_t); | ||||
|     void setTxTimeoutMs(uint32_t timeout); | ||||
|     void begin(unsigned long baud=0); | ||||
|     void end(); | ||||
|      | ||||
|     int available(void); | ||||
|     int availableForWrite(void); | ||||
|     int peek(void); | ||||
|     int read(void); | ||||
|     size_t read(uint8_t *buffer, size_t size); | ||||
|     size_t write(uint8_t); | ||||
|     size_t write(const uint8_t *buffer, size_t size); | ||||
|     void flush(void); | ||||
|      | ||||
|     inline size_t read(char * buffer, size_t size) | ||||
|     { | ||||
|         return read((uint8_t*) buffer, size); | ||||
|     } | ||||
|     inline size_t write(const char * buffer, size_t size) | ||||
|     { | ||||
|         return write((uint8_t*) buffer, size); | ||||
|     } | ||||
|     inline size_t write(const char * s) | ||||
|     { | ||||
|         return write((uint8_t*) s, strlen(s)); | ||||
|     } | ||||
|     inline size_t write(unsigned long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(unsigned int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     operator bool() const; | ||||
|     void setDebugOutput(bool); | ||||
|     uint32_t baudRate(){return 115200;} | ||||
|  | ||||
| }; | ||||
|  | ||||
| #if ARDUINO_USB_MODE | ||||
| #if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC | ||||
| extern HWCDC Serial; | ||||
| #else | ||||
| extern HWCDC USBSerial; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_IDF_TARGET_ESP32C3 */ | ||||
							
								
								
									
										552
									
								
								cores/esp32/HardwareSerial.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										552
									
								
								cores/esp32/HardwareSerial.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,552 @@ | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <inttypes.h> | ||||
|  | ||||
| #include "pins_arduino.h" | ||||
| #include "HardwareSerial.h" | ||||
| #include "soc/soc_caps.h" | ||||
| #include "driver/uart.h" | ||||
| #include "freertos/queue.h" | ||||
|  | ||||
| #ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE | ||||
| #define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 | ||||
| #endif | ||||
|  | ||||
| #ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY | ||||
| #define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1) | ||||
| #endif | ||||
|  | ||||
| #ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE | ||||
| #define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1 | ||||
| #endif | ||||
|  | ||||
| #ifndef SOC_RX0 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define SOC_RX0 3 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define SOC_RX0 44 | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #define SOC_RX0 20 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifndef SOC_TX0 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define SOC_TX0 1 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define SOC_TX0 43 | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #define SOC_TX0 21 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| void serialEvent(void) __attribute__((weak)); | ||||
| void serialEvent(void) {} | ||||
|  | ||||
| #if SOC_UART_NUM > 1 | ||||
|  | ||||
| #ifndef RX1 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define RX1 9 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #define RX1 18 | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #define RX1 18 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define RX1 15 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifndef TX1 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define TX1 10 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #define TX1 17 | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #define TX1 19 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define TX1 16 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| void serialEvent1(void) __attribute__((weak)); | ||||
| void serialEvent1(void) {} | ||||
| #endif /* SOC_UART_NUM > 1 */ | ||||
|  | ||||
| #if SOC_UART_NUM > 2 | ||||
| #ifndef RX2 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define RX2 16 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define RX2 19  | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifndef TX2 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define TX2 17 | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define TX2 20 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| void serialEvent2(void) __attribute__((weak)); | ||||
| void serialEvent2(void) {} | ||||
| #endif /* SOC_UART_NUM > 2 */ | ||||
|  | ||||
| #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) | ||||
| #if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC | ||||
| HardwareSerial Serial0(0); | ||||
| #else | ||||
| HardwareSerial Serial(0); | ||||
| #endif | ||||
| #if SOC_UART_NUM > 1 | ||||
| HardwareSerial Serial1(1); | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
| HardwareSerial Serial2(2); | ||||
| #endif | ||||
|  | ||||
| void serialEventRun(void) | ||||
| { | ||||
| #if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC | ||||
|     if(Serial0.available()) serialEvent(); | ||||
| #else | ||||
|     if(Serial.available()) serialEvent(); | ||||
| #endif | ||||
| #if SOC_UART_NUM > 1 | ||||
|     if(Serial1.available()) serialEvent1(); | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
|     if(Serial2.available()) serialEvent2(); | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
| #define HSERIAL_MUTEX_LOCK()    do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS) | ||||
| #define HSERIAL_MUTEX_UNLOCK()  xSemaphoreGive(_lock) | ||||
| #else | ||||
| #define HSERIAL_MUTEX_LOCK()     | ||||
| #define HSERIAL_MUTEX_UNLOCK()   | ||||
| #endif | ||||
|  | ||||
| HardwareSerial::HardwareSerial(int uart_nr) :  | ||||
| _uart_nr(uart_nr),  | ||||
| _uart(NULL), | ||||
| _rxBufferSize(256), | ||||
| _txBufferSize(0),  | ||||
| _onReceiveCB(NULL),  | ||||
| _onReceiveErrorCB(NULL), | ||||
| _onReceiveTimeout(true), | ||||
| _rxTimeout(2), | ||||
| _eventTask(NULL) | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     ,_lock(NULL) | ||||
| #endif | ||||
| { | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(_lock == NULL){ | ||||
|         _lock = xSemaphoreCreateMutex(); | ||||
|         if(_lock == NULL){ | ||||
|             log_e("xSemaphoreCreateMutex failed"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| HardwareSerial::~HardwareSerial() | ||||
| { | ||||
|     end(); | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(_lock != NULL){ | ||||
|         vSemaphoreDelete(_lock); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| void HardwareSerial::_createEventTask(void *args) | ||||
| { | ||||
|     // Creating UART event Task | ||||
|     xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE); | ||||
|     if (_eventTask == NULL) { | ||||
|         log_e(" -- UART%d Event Task not Created!", _uart_nr); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void HardwareSerial::_destroyEventTask(void) | ||||
| { | ||||
|     if (_eventTask != NULL) { | ||||
|         vTaskDelete(_eventTask); | ||||
|         _eventTask = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void HardwareSerial::onReceiveError(OnReceiveErrorCb function)  | ||||
| { | ||||
|     HSERIAL_MUTEX_LOCK(); | ||||
|     // function may be NULL to cancel onReceive() from its respective task  | ||||
|     _onReceiveErrorCB = function; | ||||
|     // this can be called after Serial.begin(), therefore it shall create the event task | ||||
|     if (function != NULL && _uart != NULL && _eventTask == NULL) { | ||||
|         _createEventTask(this); | ||||
|     } | ||||
|     HSERIAL_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) | ||||
| { | ||||
|     HSERIAL_MUTEX_LOCK(); | ||||
|     // function may be NULL to cancel onReceive() from its respective task  | ||||
|     _onReceiveCB = function; | ||||
|     // When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes | ||||
|     _onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false; | ||||
|  | ||||
|     // this can be called after Serial.begin(), therefore it shall create the event task | ||||
|     if (function != NULL && _uart != NULL && _eventTask == NULL) { | ||||
|         _createEventTask(this); // Create event task | ||||
|     } | ||||
|     HSERIAL_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| // This function allow the user to define how many bytes will trigger an Interrupt that will copy RX FIFO to the internal RX Ringbuffer | ||||
| // ISR will also move data from FIFO to RX Ringbuffer after a RX Timeout defined in HardwareSerial::setRxTimeout(uint8_t symbols_timeout) | ||||
| // A low value of FIFO Full bytes will consume more CPU time within the ISR | ||||
| // A high value of FIFO Full bytes will make the application wait longer to have byte available for the Stkech in a streaming scenario | ||||
| // Both RX FIFO Full and RX Timeout may affect when onReceive() will be called | ||||
| void HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) | ||||
| { | ||||
|     HSERIAL_MUTEX_LOCK(); | ||||
|     uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout | ||||
|     HSERIAL_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| // timout is calculates in time to receive UART symbols at the UART baudrate. | ||||
| // the estimation is about 11 bits per symbol (SERIAL_8N1) | ||||
| void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) | ||||
| { | ||||
|     HSERIAL_MUTEX_LOCK(); | ||||
|      | ||||
|     // Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes | ||||
|     // Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol  | ||||
|     _rxTimeout = symbols_timeout;    | ||||
|     if (!symbols_timeout) _onReceiveTimeout = false;  // only when RX timeout is disabled, we also must disable this flag  | ||||
|  | ||||
|     uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout | ||||
|      | ||||
|     HSERIAL_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::eventQueueReset() | ||||
| { | ||||
|     QueueHandle_t uartEventQueue = NULL; | ||||
|     if (_uart == NULL) { | ||||
| 	    return; | ||||
|     } | ||||
|     uartGetEventQueue(_uart, &uartEventQueue); | ||||
|     if (uartEventQueue != NULL) { | ||||
|         xQueueReset(uartEventQueue); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void HardwareSerial::_uartEventTask(void *args) | ||||
| { | ||||
|     HardwareSerial *uart = (HardwareSerial *)args; | ||||
|     uart_event_t event; | ||||
|     QueueHandle_t uartEventQueue = NULL; | ||||
|     uartGetEventQueue(uart->_uart, &uartEventQueue); | ||||
|     if (uartEventQueue != NULL) { | ||||
|         for(;;) { | ||||
|             //Waiting for UART event. | ||||
|             if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) { | ||||
|                 hardwareSerial_error_t currentErr = UART_NO_ERROR; | ||||
|                 switch(event.type) { | ||||
|                     case UART_DATA: | ||||
|                         if(uart->_onReceiveCB && uart->available() > 0 &&  | ||||
|                             ((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) )  | ||||
|                                 uart->_onReceiveCB(); | ||||
|                         break; | ||||
|                     case UART_FIFO_OVF: | ||||
|                         log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); | ||||
|                         currentErr = UART_FIFO_OVF_ERROR; | ||||
|                         break; | ||||
|                     case UART_BUFFER_FULL: | ||||
|                         log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr); | ||||
|                         currentErr = UART_BUFFER_FULL_ERROR; | ||||
|                         break; | ||||
|                     case UART_BREAK: | ||||
|                         log_w("UART%d RX break.", uart->_uart_nr); | ||||
|                         currentErr = UART_BREAK_ERROR; | ||||
|                         break; | ||||
|                     case UART_PARITY_ERR: | ||||
|                         log_w("UART%d parity error.", uart->_uart_nr); | ||||
|                         currentErr = UART_PARITY_ERROR; | ||||
|                         break; | ||||
|                     case UART_FRAME_ERR: | ||||
|                         log_w("UART%d frame error.", uart->_uart_nr); | ||||
|                         currentErr = UART_FRAME_ERROR; | ||||
|                         break; | ||||
|                     default: | ||||
|                         log_w("UART%d unknown event type %d.", uart->_uart_nr, event.type); | ||||
|                         break; | ||||
|                 } | ||||
|                 if (currentErr != UART_NO_ERROR) { | ||||
|                     if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(currentErr); | ||||
|                     if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB();   // forces User Callback too | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     vTaskDelete(NULL); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd) | ||||
| { | ||||
|     if(0 > _uart_nr || _uart_nr >= SOC_UART_NUM) { | ||||
|         log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(_lock == NULL){ | ||||
|         log_e("MUTEX Lock failed. Can't begin."); | ||||
|         return; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     HSERIAL_MUTEX_LOCK(); | ||||
|     // First Time or after end() --> set default Pins | ||||
|     if (!uartIsDriverInstalled(_uart)) { | ||||
|         switch (_uart_nr) { | ||||
|             case UART_NUM_0: | ||||
|                 if (rxPin < 0 && txPin < 0) { | ||||
|                     rxPin = SOC_RX0; | ||||
|                     txPin = SOC_TX0; | ||||
|                 } | ||||
|             break; | ||||
| #if SOC_UART_NUM > 1                   // may save some flash bytes... | ||||
|             case UART_NUM_1: | ||||
|                if (rxPin < 0 && txPin < 0) { | ||||
|                     rxPin = RX1; | ||||
|                     txPin = TX1; | ||||
|                 } | ||||
|             break; | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2                   // may save some flash bytes... | ||||
|             case UART_NUM_2: | ||||
|                if (rxPin < 0 && txPin < 0) { | ||||
|                     rxPin = RX2; | ||||
|                     txPin = TX2; | ||||
|                 } | ||||
|             break; | ||||
| #endif | ||||
|             default: | ||||
|                 log_e("Bad UART Number"); | ||||
|                 return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if(_uart) { | ||||
|         // in this case it is a begin() over a previous begin() - maybe to change baud rate | ||||
|         // thus do not disable debug output | ||||
|         end(false); | ||||
|     } | ||||
|  | ||||
|     // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. | ||||
|     _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); | ||||
|     if (!baud) { | ||||
|         // using baud rate as zero, forces it to try to detect the current baud rate in place | ||||
|         uartStartDetectBaudrate(_uart); | ||||
|         time_t startMillis = millis(); | ||||
|         unsigned long detectedBaudRate = 0; | ||||
|         while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) { | ||||
|             yield(); | ||||
|         } | ||||
|  | ||||
|         end(false); | ||||
|  | ||||
|         if(detectedBaudRate) { | ||||
|             delay(100); // Give some time... | ||||
|             _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); | ||||
|         } else { | ||||
|             log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible"); | ||||
|             _uart = NULL; | ||||
|         } | ||||
|     } | ||||
|     // create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate, | ||||
|     // or when setting the callback before calling begin()  | ||||
|     if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) { | ||||
|         _createEventTask(this); | ||||
|     } | ||||
|  | ||||
|     // Set UART RX timeout | ||||
|     uartSetRxTimeout(_uart, _rxTimeout); | ||||
|  | ||||
|     HSERIAL_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::updateBaudRate(unsigned long baud) | ||||
| { | ||||
| 	uartSetBaudRate(_uart, baud); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::end(bool fullyTerminate) | ||||
| { | ||||
|     // default Serial.end() will completely disable HardwareSerial,  | ||||
|     // including any tasks or debug message channel (log_x()) - but not for IDF log messages! | ||||
|     if(fullyTerminate) { | ||||
|         _onReceiveCB = NULL; | ||||
|         _onReceiveErrorCB = NULL; | ||||
|         if (uartGetDebug() == _uart_nr) { | ||||
|             uartSetDebug(0); | ||||
|         } | ||||
|     } | ||||
|     delay(10); | ||||
|     uartEnd(_uart); | ||||
|     _uart = 0; | ||||
|     _destroyEventTask(); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::setDebugOutput(bool en) | ||||
| { | ||||
|     if(_uart == 0) { | ||||
|         return; | ||||
|     } | ||||
|     if(en) { | ||||
|         uartSetDebug(_uart); | ||||
|     } else { | ||||
|         if(uartGetDebug() == _uart_nr) { | ||||
|             uartSetDebug(NULL); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| // read characters into buffer | ||||
| // terminates if size characters have been read, or no further are pending | ||||
| // returns the number of characters placed in the buffer | ||||
| // the buffer is NOT null terminated. | ||||
| size_t HardwareSerial::read(uint8_t *buffer, size_t size) | ||||
| { | ||||
|     size_t avail = available(); | ||||
|     if (size < avail) { | ||||
|         avail = size; | ||||
|     } | ||||
|     size_t count = 0; | ||||
|     while(count < avail) { | ||||
|         *buffer++ = uartRead(_uart); | ||||
|         count++; | ||||
|     } | ||||
|     return count; | ||||
| } | ||||
|  | ||||
| void HardwareSerial::flush(void) | ||||
| { | ||||
|     uartFlush(_uart); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::flush(bool txOnly) | ||||
| { | ||||
|     uartFlushTxOnly(_uart, txOnly); | ||||
| } | ||||
|  | ||||
| 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 uartIsDriverInstalled(_uart); | ||||
| } | ||||
|  | ||||
| void HardwareSerial::setRxInvert(bool invert) | ||||
| { | ||||
|     uartSetRxInvert(_uart, invert); | ||||
| } | ||||
|  | ||||
| // negative Pin value will keep it unmodified | ||||
| void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) | ||||
| { | ||||
|     if(_uart == NULL) { | ||||
|         log_e("setPins() shall be called after begin() - nothing done"); | ||||
|         return; | ||||
|     } | ||||
|     uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin); | ||||
| } | ||||
|  | ||||
| // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) | ||||
| void HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) | ||||
| { | ||||
|     uartSetHwFlowCtrlMode(_uart, mode, threshold); | ||||
| } | ||||
|  | ||||
| size_t HardwareSerial::setRxBufferSize(size_t new_size) { | ||||
|  | ||||
|     if (_uart) { | ||||
|         log_e("RX Buffer can't be resized when Serial is already running.\n"); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (new_size <= SOC_UART_FIFO_LEN) { | ||||
|         log_e("RX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN);  // ESP32, S2, S3 and C3 means higher than 128 | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     _rxBufferSize = new_size; | ||||
|     return _rxBufferSize; | ||||
| } | ||||
|  | ||||
| size_t HardwareSerial::setTxBufferSize(size_t new_size) { | ||||
|  | ||||
|     if (_uart) { | ||||
|         log_e("TX Buffer can't be resized when Serial is already running.\n"); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (new_size <= SOC_UART_FIFO_LEN) { | ||||
|         log_e("TX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN);  // ESP32, S2, S3 and C3 means higher than 128 | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     _txBufferSize = new_size; | ||||
|     return _txBufferSize; | ||||
| } | ||||
							
								
								
									
										208
									
								
								cores/esp32/HardwareSerial.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								cores/esp32/HardwareSerial.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,208 @@ | ||||
| /* | ||||
|  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 <functional> | ||||
| #include "Stream.h" | ||||
| #include "esp32-hal.h" | ||||
| #include "soc/soc_caps.h" | ||||
| #include "HWCDC.h" | ||||
|  | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "freertos/semphr.h" | ||||
|  | ||||
| typedef enum { | ||||
|     UART_NO_ERROR, | ||||
|     UART_BREAK_ERROR, | ||||
|     UART_BUFFER_FULL_ERROR, | ||||
|     UART_FIFO_OVF_ERROR, | ||||
|     UART_FRAME_ERROR, | ||||
|     UART_PARITY_ERROR | ||||
| } hardwareSerial_error_t; | ||||
|  | ||||
| typedef std::function<void(void)> OnReceiveCb; | ||||
| typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb; | ||||
|  | ||||
| class HardwareSerial: public Stream | ||||
| { | ||||
| public: | ||||
|     HardwareSerial(int uart_nr); | ||||
|     ~HardwareSerial(); | ||||
|  | ||||
|     // setRxTimeout sets the timeout after which onReceive callback will be called (after receiving data, it waits for this time of UART rx inactivity to call the callback fnc) | ||||
|     // param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. | ||||
|     //                       Maximum timeout setting is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console). | ||||
|     //                       Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). | ||||
|     //                       For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate.  | ||||
|     //                       For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms | ||||
|     void setRxTimeout(uint8_t symbols_timeout); | ||||
|  | ||||
|     // setRxFIFOFull(uint8_t fifoBytes) will set the number of bytes that will trigger UART_INTR_RXFIFO_FULL interrupt and fill up RxRingBuffer | ||||
|     // This affects some functions such as Serial::available() and Serial.read() because, in a UART flow of receiving data, Serial internal  | ||||
|     // RxRingBuffer will be filled only after these number of bytes arrive or a RX Timeout happens. | ||||
|     // This parameter can be set to 1 in order to receive byte by byte, but it will also consume more CPU time as the ISR will be activates often. | ||||
|     void setRxFIFOFull(uint8_t fifoBytes); | ||||
|  | ||||
|     // onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT) | ||||
|     // UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF) | ||||
|     // UART_INTR_RXFIFO_TOUT interrupt triggers at UART_TOUT_THRESH_DEFAULT symbols passed without any reception (defined as 10 symbos by default in IDF) | ||||
|     // onlyOnTimeout parameter will define how onReceive will behave: | ||||
|     // Default: true -- The callback will only be called when RX Timeout happens.  | ||||
|     //                  Whole stream of bytes will be ready for being read on the callback function at once. | ||||
|     //                  This option may lead to Rx Overflow depending on the Rx Buffer Size and number of bytes received in the streaming | ||||
|     //         false -- The callback will be called when FIFO reaches 120 bytes and also on RX Timeout. | ||||
|     //                  The stream of incommig bytes will be "split" into blocks of 120 bytes on each callback. | ||||
|     //                  This option avoid any sort of Rx Overflow, but leaves the UART packet reassembling work to the Application. | ||||
|     void onReceive(OnReceiveCb function, bool onlyOnTimeout = false); | ||||
|  | ||||
|     // onReceive will be called on error events (see hardwareSerial_error_t) | ||||
|     void onReceiveError(OnReceiveErrorCb function); | ||||
|  | ||||
|     // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases | ||||
|     void eventQueueReset(); | ||||
|   | ||||
|     void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112); | ||||
|     void end(bool fullyTerminate = true); | ||||
|     void updateBaudRate(unsigned long baud); | ||||
|     int available(void); | ||||
|     int availableForWrite(void); | ||||
|     int peek(void); | ||||
|     int read(void); | ||||
|     size_t read(uint8_t *buffer, size_t size); | ||||
|     inline size_t read(char * buffer, size_t size) | ||||
|     { | ||||
|         return read((uint8_t*) buffer, size); | ||||
|     } | ||||
|     void flush(void); | ||||
|     void flush( bool txOnly); | ||||
|     size_t write(uint8_t); | ||||
|     size_t write(const uint8_t *buffer, size_t size); | ||||
|     inline size_t write(const char * buffer, size_t size) | ||||
|     { | ||||
|         return write((uint8_t*) buffer, size); | ||||
|     } | ||||
|     inline size_t write(const char * s) | ||||
|     { | ||||
|         return write((uint8_t*) s, strlen(s)); | ||||
|     } | ||||
|     inline size_t write(unsigned long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(unsigned int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     uint32_t baudRate(); | ||||
|     operator bool() const; | ||||
|  | ||||
|     void setDebugOutput(bool); | ||||
|      | ||||
|     void setRxInvert(bool); | ||||
|  | ||||
|     // Negative Pin Number will keep it unmodified, thus this function can set individual pins | ||||
|     // SetPins shall be called after Serial begin() | ||||
|     void setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); | ||||
|     // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) | ||||
|     void setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64);   // 64 is half FIFO Length | ||||
|  | ||||
|     size_t setRxBufferSize(size_t new_size); | ||||
|     size_t setTxBufferSize(size_t new_size); | ||||
|  | ||||
| protected: | ||||
|     int _uart_nr; | ||||
|     uart_t* _uart; | ||||
|     size_t _rxBufferSize; | ||||
|     size_t _txBufferSize; | ||||
|     OnReceiveCb _onReceiveCB; | ||||
|     OnReceiveErrorCb _onReceiveErrorCB; | ||||
|     // _onReceive and _rxTimeout have be consistent when timeout is disabled | ||||
|     bool _onReceiveTimeout; | ||||
|     uint8_t _rxTimeout; | ||||
|     TaskHandle_t _eventTask; | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     SemaphoreHandle_t _lock; | ||||
| #endif | ||||
|  | ||||
|     void _createEventTask(void *args); | ||||
|     void _destroyEventTask(void); | ||||
|     static void _uartEventTask(void *args); | ||||
| }; | ||||
|  | ||||
| extern void serialEventRun(void) __attribute__((weak)); | ||||
|  | ||||
| #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) | ||||
| #ifndef ARDUINO_USB_CDC_ON_BOOT | ||||
| #define ARDUINO_USB_CDC_ON_BOOT 0 | ||||
| #endif | ||||
| #if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC | ||||
| #if !ARDUINO_USB_MODE | ||||
| #include "USB.h" | ||||
| #include "USBCDC.h" | ||||
| #endif | ||||
| extern HardwareSerial Serial0; | ||||
| #else | ||||
| extern HardwareSerial Serial; | ||||
| #endif | ||||
| #if SOC_UART_NUM > 1 | ||||
| extern HardwareSerial Serial1; | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
| extern HardwareSerial Serial2; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #endif // HardwareSerial_h | ||||
							
								
								
									
										125
									
								
								cores/esp32/IPAddress.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								cores/esp32/IPAddress.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| /* | ||||
|  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; | ||||
| } | ||||
|  | ||||
| // declared one time - as external in IPAddress.h | ||||
| IPAddress INADDR_NONE(0, 0, 0, 0); | ||||
							
								
								
									
										96
									
								
								cores/esp32/IPAddress.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								cores/esp32/IPAddress.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  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; | ||||
| }; | ||||
|  | ||||
| // changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it | ||||
| extern IPAddress INADDR_NONE; | ||||
| #endif | ||||
							
								
								
									
										90
									
								
								cores/esp32/IPv6Address.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								cores/esp32/IPv6Address.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| /* | ||||
|  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; | ||||
| } | ||||
							
								
								
									
										94
									
								
								cores/esp32/IPv6Address.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								cores/esp32/IPv6Address.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| /* | ||||
|  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 | ||||
							
								
								
									
										117
									
								
								cores/esp32/MD5Builder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								cores/esp32/MD5Builder.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| /*  | ||||
|   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> | ||||
|  | ||||
| static 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, ESP_ROM_MD5_DIGEST_LEN); | ||||
|     esp_rom_md5_init(&_ctx); | ||||
| } | ||||
|  | ||||
| void MD5Builder::add(uint8_t * data, uint16_t len) | ||||
| { | ||||
|     esp_rom_md5_update(&_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 | ||||
|         esp_rom_md5_update(&_ctx, buf, numBytesRead); | ||||
|  | ||||
|         // update available number of bytes | ||||
|         maxLengthLeft -= numBytesRead; | ||||
|         bytesAvailable = stream.available(); | ||||
|     } | ||||
|     free(buf); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void MD5Builder::calculate(void) | ||||
| { | ||||
|     esp_rom_md5_final(_buf, &_ctx); | ||||
| } | ||||
|  | ||||
| void MD5Builder::getBytes(uint8_t * output) | ||||
| { | ||||
|     memcpy(output, _buf, ESP_ROM_MD5_DIGEST_LEN); | ||||
| } | ||||
|  | ||||
| void MD5Builder::getChars(char * output) | ||||
| { | ||||
|     for(uint8_t i = 0; i < ESP_ROM_MD5_DIGEST_LEN; i++) { | ||||
|         sprintf(output + (i * 2), "%02x", _buf[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| String MD5Builder::toString(void) | ||||
| { | ||||
|     char out[(ESP_ROM_MD5_DIGEST_LEN * 2) + 1]; | ||||
|     getChars(out); | ||||
|     return String(out); | ||||
| } | ||||
							
								
								
									
										65
									
								
								cores/esp32/MD5Builder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								cores/esp32/MD5Builder.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /*  | ||||
|   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 "esp_system.h" | ||||
| #include "esp_rom_md5.h" | ||||
|  | ||||
| class MD5Builder | ||||
| { | ||||
| private: | ||||
|     md5_context_t _ctx; | ||||
|     uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN]; | ||||
| 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 | ||||
							
								
								
									
										374
									
								
								cores/esp32/Print.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								cores/esp32/Print.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,374 @@ | ||||
| /* | ||||
|  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); | ||||
|     int len = vsnprintf(temp, sizeof(loc_buf), format, copy); | ||||
|     va_end(copy); | ||||
|     if(len < 0) { | ||||
|         va_end(arg); | ||||
|         return 0; | ||||
|     }; | ||||
|     if(len >= sizeof(loc_buf)){ | ||||
|         temp = (char*) malloc(len+1); | ||||
|         if(temp == NULL) { | ||||
|             va_end(arg); | ||||
|             return 0; | ||||
|         } | ||||
|         len = vsnprintf(temp, len+1, format, arg); | ||||
|     } | ||||
|     va_end(arg); | ||||
|     len = write((uint8_t*)temp, len); | ||||
|     if(temp != loc_buf){ | ||||
|         free(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) | ||||
| { | ||||
|     int t = 0; | ||||
|     if (base == 10 && n < 0) { | ||||
|         t = print('-'); | ||||
|         n = -n; | ||||
|     } | ||||
|     return printNumber(static_cast<unsigned long>(n), base) + t; | ||||
| } | ||||
|  | ||||
| size_t Print::print(unsigned long n, int base) | ||||
| { | ||||
|     if(base == 0) { | ||||
|         return write(n); | ||||
|     } else { | ||||
|         return printNumber(n, base); | ||||
|     } | ||||
| } | ||||
|  | ||||
| size_t Print::print(long long n, int base) | ||||
| { | ||||
|     int t = 0; | ||||
|     if (base == 10 && n < 0) { | ||||
|         t = print('-'); | ||||
|         n = -n; | ||||
|     } | ||||
|     return printNumber(static_cast<unsigned long long>(n), base) + t; | ||||
| } | ||||
|  | ||||
| size_t Print::print(unsigned long 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); | ||||
|     if(written == 0){ | ||||
|         return written; | ||||
|     } | ||||
|     return print(buf); | ||||
| } | ||||
|  | ||||
| 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(long long num, int base) | ||||
| { | ||||
|     size_t n = print(num, base); | ||||
|     n += println(); | ||||
|     return n; | ||||
| } | ||||
|  | ||||
| size_t Print::println(unsigned long 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(n) + 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 { | ||||
|         char c = n % base; | ||||
|         n /= base; | ||||
|  | ||||
|         *--str = c < 10 ? c + '0' : c + 'A' - 10; | ||||
|     } while (n); | ||||
|  | ||||
|     return write(str); | ||||
| } | ||||
|  | ||||
| size_t Print::printNumber(unsigned long long n, uint8_t base) | ||||
| { | ||||
|     char buf[8 * sizeof(n) + 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 { | ||||
|         auto 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; | ||||
| } | ||||
							
								
								
									
										116
									
								
								cores/esp32/Print.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								cores/esp32/Print.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| /* | ||||
|  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 printNumber(unsigned long 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))); | ||||
|  | ||||
|     // add availableForWrite to make compatible with Arduino Print.h | ||||
|     // default to zero, meaning "a single write may block" | ||||
|     // should be overriden by subclasses with buffering | ||||
|     virtual int availableForWrite() { return 0; } | ||||
|     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(long long, int = DEC); | ||||
|     size_t print(unsigned long 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(long long, int = DEC); | ||||
|     size_t println(unsigned long 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); | ||||
|      | ||||
|     virtual void flush() { /* Empty implementation for backward compatibility */ } | ||||
|      | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										41
									
								
								cores/esp32/Printable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								cores/esp32/Printable.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  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 | ||||
|  | ||||
							
								
								
									
										31
									
								
								cores/esp32/Server.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								cores/esp32/Server.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  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 | ||||
							
								
								
									
										337
									
								
								cores/esp32/Stream.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										337
									
								
								cores/esp32/Stream.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,337 @@ | ||||
| /* | ||||
|  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, strlen(target), NULL, 0); | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| { | ||||
|   if (terminator == NULL) { | ||||
|     MultiTarget t[1] = {{target, targetLen, 0}}; | ||||
|     return findMulti(t, 1) == 0 ? true : false; | ||||
|   } else { | ||||
|     MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; | ||||
|     return findMulti(t, 2) == 0 ? true : false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { | ||||
|   // any zero length target string automatically matches and would make | ||||
|   // a mess of the rest of the algorithm. | ||||
|   for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { | ||||
|     if (t->len <= 0) | ||||
|       return t - targets; | ||||
|   } | ||||
|  | ||||
|   while (1) { | ||||
|     int c = timedRead(); | ||||
|     if (c < 0) | ||||
|       return -1; | ||||
|  | ||||
|     for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { | ||||
|       // the simple case is if we match, deal with that first. | ||||
|       if (c == t->str[t->index]) { | ||||
|         if (++t->index == t->len) | ||||
|           return t - targets; | ||||
|         else | ||||
|           continue; | ||||
|       } | ||||
|  | ||||
|       // if not we need to walk back and see if we could have matched further | ||||
|       // down the stream (ie '1112' doesn't match the first position in '11112' | ||||
|       // but it will match the second position so we can't just reset the current | ||||
|       // index to 0 when we find a mismatch. | ||||
|       if (t->index == 0) | ||||
|         continue; | ||||
|  | ||||
|       int origIndex = t->index; | ||||
|       do { | ||||
|         --t->index; | ||||
|         // first check if current char works against the new current index | ||||
|         if (c != t->str[t->index]) | ||||
|           continue; | ||||
|  | ||||
|         // if it's the only char then we're good, nothing more to check | ||||
|         if (t->index == 0) { | ||||
|           t->index++; | ||||
|           break; | ||||
|         } | ||||
|  | ||||
|         // otherwise we need to check the rest of the found string | ||||
|         int diff = origIndex - t->index; | ||||
|         size_t i; | ||||
|         for (i = 0; i < t->index; ++i) { | ||||
|           if (t->str[i] != t->str[i + diff]) | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         // if we successfully got through the previous loop then our current | ||||
|         // index is good. | ||||
|         if (i == t->index) { | ||||
|           t->index++; | ||||
|           break; | ||||
|         } | ||||
|  | ||||
|         // otherwise we just try the next index | ||||
|       } while (t->index); | ||||
|     } | ||||
|   } | ||||
|   // unreachable | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| // 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.1f; | ||||
|             } | ||||
|         } | ||||
|         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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										139
									
								
								cores/esp32/Stream.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								cores/esp32/Stream.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| /* | ||||
|  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; | ||||
|  | ||||
|     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 | ||||
|    | ||||
|     struct MultiTarget { | ||||
|       const char *str;  // string you're searching for | ||||
|       size_t len;       // length of string you're searching for | ||||
|       size_t index;     // index used by the search routine. | ||||
|     }; | ||||
|  | ||||
|   // This allows you to search for an arbitrary number of strings. | ||||
|   // Returns index of the target that is found first or -1 if timeout occurs. | ||||
|   int findMulti(struct MultiTarget *targets, int tCount); | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										67
									
								
								cores/esp32/StreamString.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								cores/esp32/StreamString.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| /** | ||||
|  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() { | ||||
| } | ||||
|  | ||||
							
								
								
									
										39
									
								
								cores/esp32/StreamString.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								cores/esp32/StreamString.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /** | ||||
|  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_ */ | ||||
							
								
								
									
										135
									
								
								cores/esp32/Tone.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								cores/esp32/Tone.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| #include <Arduino.h> | ||||
| #include "esp32-hal-ledc.h" | ||||
| #include "freertos/task.h" | ||||
| #include "freertos/queue.h" | ||||
| #include "freertos/semphr.h" | ||||
|  | ||||
| static TaskHandle_t _tone_task = NULL; | ||||
| static QueueHandle_t _tone_queue = NULL; | ||||
| static uint8_t _channel = 0; | ||||
|  | ||||
| typedef enum{ | ||||
|   TONE_START, | ||||
|   TONE_END, | ||||
|   TONE_SET_CHANNEL | ||||
| } tone_cmd_t; | ||||
|  | ||||
| typedef struct{ | ||||
|   tone_cmd_t tone_cmd; | ||||
|   uint8_t pin; | ||||
|   unsigned int frequency; | ||||
|   unsigned long duration; | ||||
|   uint8_t channel; | ||||
| } tone_msg_t; | ||||
|  | ||||
| static void tone_task(void*){ | ||||
|   tone_msg_t tone_msg; | ||||
|   while(1){ | ||||
|     xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY); | ||||
|     switch(tone_msg.tone_cmd){ | ||||
|       case TONE_START: | ||||
|         log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%lu ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration); | ||||
|  | ||||
|         log_d("Setup LED controll on channel %d", _channel); | ||||
|         ledcAttachPin(tone_msg.pin, _channel); | ||||
|         ledcWriteTone(_channel, tone_msg.frequency); | ||||
|  | ||||
|         if(tone_msg.duration){ | ||||
|           delay(tone_msg.duration); | ||||
|           ledcDetachPin(tone_msg.pin); | ||||
|           ledcWriteTone(_channel, 0); | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|       case TONE_END: | ||||
|         log_d("Task received from queue TONE_END: pin=%d", tone_msg.pin); | ||||
|         ledcDetachPin(tone_msg.pin); | ||||
|         ledcWriteTone(_channel, 0); | ||||
|         break; | ||||
|  | ||||
|       case TONE_SET_CHANNEL: | ||||
|         log_d("Task received from queue TONE_SET_CHANNEL: channel=%d", tone_msg.channel); | ||||
|         _channel = tone_msg.channel; | ||||
|         break; | ||||
|  | ||||
|       default: ; // do nothing | ||||
|     } // switch | ||||
|   } // infinite loop | ||||
| } | ||||
|  | ||||
| static int tone_init(){ | ||||
|   if(_tone_queue == NULL){ | ||||
|     log_v("Creating tone queue"); | ||||
|     _tone_queue = xQueueCreate(128, sizeof(tone_msg_t)); | ||||
|     if(_tone_queue == NULL){ | ||||
|       log_e("Could not create tone queue"); | ||||
|       return 0; // ERR | ||||
|     } | ||||
|     log_v("Tone queue created"); | ||||
|   } | ||||
|  | ||||
|   if(_tone_task == NULL){ | ||||
|     log_v("Creating tone task"); | ||||
|     xTaskCreate( | ||||
|       tone_task, // Function to implement the task | ||||
|       "toneTask", // Name of the task | ||||
|       3500,  // Stack size in words | ||||
|       NULL,  // Task input parameter | ||||
|       1,  // Priority of the task | ||||
|       &_tone_task  // Task handle. | ||||
|       ); | ||||
|     if(_tone_task == NULL){ | ||||
|       log_e("Could not create tone task"); | ||||
|       return 0; // ERR | ||||
|     } | ||||
|     log_v("Tone task created"); | ||||
|   } | ||||
|   return 1; // OK | ||||
| } | ||||
|  | ||||
| void setToneChannel(uint8_t channel){ | ||||
|   log_d("channel=%d", channel); | ||||
|   if(tone_init()){ | ||||
|     tone_msg_t tone_msg = { | ||||
|       .tone_cmd = TONE_SET_CHANNEL, | ||||
|       .pin = 0, // Ignored | ||||
|       .frequency = 0, // Ignored | ||||
|       .duration = 0, // Ignored | ||||
|       .channel = channel | ||||
|     }; | ||||
|     xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void noTone(uint8_t _pin){ | ||||
|   log_d("noTone was called"); | ||||
|   if(tone_init()){ | ||||
|     tone_msg_t tone_msg = { | ||||
|       .tone_cmd = TONE_END, | ||||
|       .pin = _pin, | ||||
|       .frequency = 0, // Ignored | ||||
|       .duration = 0, // Ignored | ||||
|       .channel = 0 // Ignored | ||||
|     }; | ||||
|     xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // parameters: | ||||
| // _pin - pin number which will output the signal | ||||
| // frequency - PWM frequency in Hz | ||||
| // duration - time in ms - how long will the signal be outputted. | ||||
| //   If not provided, or 0 you must manually call noTone to end output | ||||
| void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){ | ||||
|   log_d("_pin=%d, frequency=%u Hz, duration=%lu ms", _pin, frequency, duration); | ||||
|   if(tone_init()){ | ||||
|     tone_msg_t tone_msg = { | ||||
|       .tone_cmd = TONE_START, | ||||
|       .pin = _pin, | ||||
|       .frequency = frequency, | ||||
|       .duration = duration, | ||||
|       .channel = 0 // Ignored | ||||
|     }; | ||||
|     xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										357
									
								
								cores/esp32/USB.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								cores/esp32/USB.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,357 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #include "USB.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_ENABLED | ||||
|  | ||||
| #include "pins_arduino.h" | ||||
| #include "esp32-hal.h" | ||||
| #include "esp32-hal-tinyusb.h" | ||||
| #include "common/tusb_common.h" | ||||
| #include "StreamString.h" | ||||
|  | ||||
| #ifndef USB_VID | ||||
| #define USB_VID USB_ESPRESSIF_VID | ||||
| #endif | ||||
| #ifndef USB_PID | ||||
| #define USB_PID 0x0002 | ||||
| #endif | ||||
| #ifndef USB_MANUFACTURER | ||||
| #define USB_MANUFACTURER "Espressif Systems" | ||||
| #endif | ||||
| #ifndef USB_PRODUCT | ||||
| #define USB_PRODUCT ARDUINO_BOARD | ||||
| #endif | ||||
| #ifndef USB_SERIAL | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define USB_SERIAL "__MAC__" | ||||
| #else | ||||
| #define USB_SERIAL "0" | ||||
| #endif | ||||
| #endif | ||||
| #ifndef USB_WEBUSB_ENABLED | ||||
| #define USB_WEBUSB_ENABLED false | ||||
| #endif | ||||
| #ifndef USB_WEBUSB_URL | ||||
| #define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html" | ||||
| #endif | ||||
|  | ||||
| #if CFG_TUD_DFU_RUNTIME | ||||
| static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf) | ||||
| { | ||||
| #define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) | ||||
|  | ||||
|     uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT"); | ||||
|     uint8_t descriptor[TUD_DFU_RT_DESC_LEN] = { | ||||
|             // Interface number, string index, attributes, detach timeout, transfer size */ | ||||
|             TUD_DFU_RT_DESCRIPTOR(*itf, str_index, DFU_ATTRS, 700, 64) | ||||
|     }; | ||||
|     *itf+=1; | ||||
|     memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN); | ||||
|     return TUD_DFU_RT_DESC_LEN; | ||||
| } | ||||
| // Invoked on DFU_DETACH request to reboot to the bootloader | ||||
| void tud_dfu_runtime_reboot_to_dfu_cb(void) | ||||
| { | ||||
|     usb_persist_restart(RESTART_BOOTLOADER_DFU); | ||||
| } | ||||
| #endif /* CFG_TUD_DFU_RUNTIME */ | ||||
|  | ||||
| ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS); | ||||
|  | ||||
| static esp_event_loop_handle_t arduino_usb_event_loop_handle = NULL; | ||||
|  | ||||
| esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait){ | ||||
|     if(arduino_usb_event_loop_handle == NULL){ | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     return esp_event_post_to(arduino_usb_event_loop_handle, event_base, event_id, event_data, event_data_size, ticks_to_wait); | ||||
| } | ||||
| esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){ | ||||
|     if(arduino_usb_event_loop_handle == NULL){ | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     return esp_event_handler_register_with(arduino_usb_event_loop_handle, event_base, event_id, event_handler, event_handler_arg); | ||||
| } | ||||
|  | ||||
| static bool tinyusb_device_mounted = false; | ||||
| static bool tinyusb_device_suspended = false; | ||||
|  | ||||
| // Invoked when device is mounted (configured) | ||||
| void tud_mount_cb(void){ | ||||
|     tinyusb_device_mounted = true; | ||||
|     arduino_usb_event_data_t p; | ||||
|     arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| // Invoked when device is unmounted | ||||
| void tud_umount_cb(void){ | ||||
|     tinyusb_device_mounted = false; | ||||
|     arduino_usb_event_data_t p; | ||||
|     arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| // Invoked when usb bus is suspended | ||||
| // Within 7ms, device must draw an average of current less than 2.5 mA from bus | ||||
| void tud_suspend_cb(bool remote_wakeup_en){ | ||||
|     tinyusb_device_suspended = true; | ||||
|     arduino_usb_event_data_t p; | ||||
|     p.suspend.remote_wakeup_en = remote_wakeup_en; | ||||
|     arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| // Invoked when usb bus is resumed | ||||
| void tud_resume_cb(void){ | ||||
|     tinyusb_device_suspended = false; | ||||
|     arduino_usb_event_data_t p; | ||||
|     arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority) | ||||
| :vid(USB_VID) | ||||
| ,pid(USB_PID) | ||||
| ,product_name(USB_PRODUCT) | ||||
| ,manufacturer_name(USB_MANUFACTURER) | ||||
| ,serial_number(USB_SERIAL) | ||||
| ,fw_version(0x0100) | ||||
| ,usb_version(0x0200)// at least 2.1 or 3.x for BOS & webUSB | ||||
| ,usb_class(TUSB_CLASS_MISC) | ||||
| ,usb_subclass(MISC_SUBCLASS_COMMON) | ||||
| ,usb_protocol(MISC_PROTOCOL_IAD) | ||||
| ,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED) | ||||
| ,usb_power_ma(500) | ||||
| ,webusb_enabled(USB_WEBUSB_ENABLED) | ||||
| ,webusb_url(USB_WEBUSB_URL) | ||||
| ,_started(false) | ||||
| ,_task_stack_size(task_stack_size) | ||||
| ,_event_task_priority(event_task_priority) | ||||
| { | ||||
|     if (!arduino_usb_event_loop_handle) { | ||||
|         esp_event_loop_args_t event_task_args = { | ||||
|             .queue_size = 5, | ||||
|             .task_name = "arduino_usb_events", | ||||
|             .task_priority = _event_task_priority, | ||||
|             .task_stack_size = _task_stack_size, | ||||
|             .task_core_id = tskNO_AFFINITY | ||||
|         }; | ||||
|         if (esp_event_loop_create(&event_task_args, &arduino_usb_event_loop_handle) != ESP_OK) { | ||||
|             log_e("esp_event_loop_create failed"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| ESPUSB::~ESPUSB(){ | ||||
|     if (arduino_usb_event_loop_handle) { | ||||
|         esp_event_loop_delete(arduino_usb_event_loop_handle); | ||||
|         arduino_usb_event_loop_handle = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool ESPUSB::begin(){ | ||||
|     if(!_started){ | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 | ||||
|         if(serial_number == "__MAC__"){ | ||||
|             StreamString s; | ||||
|             uint8_t m[6]; | ||||
|             esp_efuse_mac_get_default(m); | ||||
|             s.printf("%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]); | ||||
|             serial_number = s; | ||||
|         } | ||||
| #endif | ||||
|         tinyusb_device_config_t tinyusb_device_config = { | ||||
|                 .vid = vid, | ||||
|                 .pid = pid, | ||||
|                 .product_name = product_name.c_str(), | ||||
|                 .manufacturer_name = manufacturer_name.c_str(), | ||||
|                 .serial_number = serial_number.c_str(), | ||||
|                 .fw_version = fw_version, | ||||
|                 .usb_version = usb_version, | ||||
|                 .usb_class = usb_class, | ||||
|                 .usb_subclass = usb_subclass, | ||||
|                 .usb_protocol = usb_protocol, | ||||
|                 .usb_attributes = usb_attributes, | ||||
|                 .usb_power_ma = usb_power_ma, | ||||
|                 .webusb_enabled = webusb_enabled, | ||||
|                 .webusb_url = webusb_url.c_str() | ||||
|         }; | ||||
|         _started = tinyusb_init(&tinyusb_device_config) == ESP_OK;  | ||||
|     } | ||||
|     return _started; | ||||
| } | ||||
|  | ||||
| void ESPUSB::onEvent(esp_event_handler_t callback){ | ||||
|     onEvent(ARDUINO_USB_ANY_EVENT, callback); | ||||
| } | ||||
| void ESPUSB::onEvent(arduino_usb_event_t event, esp_event_handler_t callback){ | ||||
|     arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, event, callback, this); | ||||
| } | ||||
|  | ||||
| ESPUSB::operator bool() const | ||||
| { | ||||
|     return _started && tinyusb_device_mounted; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::enableDFU(){ | ||||
| #if CFG_TUD_DFU_RUNTIME | ||||
|     return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK; | ||||
| #endif /* CFG_TUD_DFU_RUNTIME */ | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::VID(uint16_t v){ | ||||
|     if(!_started){ | ||||
|         vid = v; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint16_t ESPUSB::VID(void){ | ||||
|     return vid; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::PID(uint16_t p){ | ||||
|     if(!_started){ | ||||
|         pid = p; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint16_t ESPUSB::PID(void){ | ||||
|     return pid; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::firmwareVersion(uint16_t version){ | ||||
|     if(!_started){ | ||||
|         fw_version = version; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint16_t ESPUSB::firmwareVersion(void){ | ||||
|     return fw_version; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbVersion(uint16_t version){ | ||||
|     if(!_started){ | ||||
|         usb_version = version; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint16_t ESPUSB::usbVersion(void){ | ||||
|     return usb_version; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbPower(uint16_t mA){ | ||||
|     if(!_started){ | ||||
|         usb_power_ma = mA; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint16_t ESPUSB::usbPower(void){ | ||||
|     return usb_power_ma; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbClass(uint8_t _class){ | ||||
|     if(!_started){ | ||||
|         usb_class = _class; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint8_t ESPUSB::usbClass(void){ | ||||
|     return usb_class; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbSubClass(uint8_t subClass){ | ||||
|     if(!_started){ | ||||
|         usb_subclass = subClass; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint8_t ESPUSB::usbSubClass(void){ | ||||
|     return usb_subclass; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbProtocol(uint8_t protocol){ | ||||
|     if(!_started){ | ||||
|         usb_protocol = protocol; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint8_t ESPUSB::usbProtocol(void){ | ||||
|     return usb_protocol; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::usbAttributes(uint8_t attr){ | ||||
|     if(!_started){ | ||||
|         usb_attributes = attr; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| uint8_t ESPUSB::usbAttributes(void){ | ||||
|     return usb_attributes; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::webUSB(bool enabled){ | ||||
|     if(!_started){ | ||||
|         webusb_enabled = enabled; | ||||
|         if(enabled && usb_version < 0x0210){ | ||||
|             usb_version = 0x0210; | ||||
|         } | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| bool ESPUSB::webUSB(void){ | ||||
|     return webusb_enabled; | ||||
| } | ||||
|  | ||||
| bool ESPUSB::productName(const char * name){ | ||||
|     if(!_started){ | ||||
|         product_name = name; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| const char * ESPUSB::productName(void){ | ||||
|     return product_name.c_str(); | ||||
| } | ||||
|  | ||||
| bool ESPUSB::manufacturerName(const char * name){ | ||||
|     if(!_started){ | ||||
|         manufacturer_name = name; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| const char * ESPUSB::manufacturerName(void){ | ||||
|     return manufacturer_name.c_str(); | ||||
| } | ||||
|  | ||||
| bool ESPUSB::serialNumber(const char * name){ | ||||
|     if(!_started){ | ||||
|         serial_number = name; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| const char * ESPUSB::serialNumber(void){ | ||||
|     return serial_number.c_str(); | ||||
| } | ||||
|  | ||||
| bool ESPUSB::webUSBURL(const char * name){ | ||||
|     if(!_started){ | ||||
|         webusb_url = name; | ||||
|     } | ||||
|     return !_started; | ||||
| } | ||||
| const char * ESPUSB::webUSBURL(void){ | ||||
|     return webusb_url.c_str(); | ||||
| } | ||||
|  | ||||
| ESPUSB USB; | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_ENABLED */ | ||||
							
								
								
									
										119
									
								
								cores/esp32/USB.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								cores/esp32/USB.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_ENABLED | ||||
|  | ||||
| #include "esp_event.h" | ||||
| #include "USBCDC.h" | ||||
|  | ||||
| #define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) | ||||
|  | ||||
| ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS); | ||||
|  | ||||
| typedef enum { | ||||
|     ARDUINO_USB_ANY_EVENT = ESP_EVENT_ANY_ID, | ||||
|     ARDUINO_USB_STARTED_EVENT = 0, | ||||
|     ARDUINO_USB_STOPPED_EVENT, | ||||
|     ARDUINO_USB_SUSPEND_EVENT, | ||||
|     ARDUINO_USB_RESUME_EVENT, | ||||
|     ARDUINO_USB_MAX_EVENT, | ||||
| } arduino_usb_event_t; | ||||
|  | ||||
| typedef union { | ||||
|     struct { | ||||
|         bool remote_wakeup_en; | ||||
|     } suspend; | ||||
| } arduino_usb_event_data_t; | ||||
|  | ||||
| class ESPUSB { | ||||
|     public: | ||||
|         ESPUSB(size_t event_task_stack_size=2048, uint8_t event_task_priority=5); | ||||
|         ~ESPUSB(); | ||||
|          | ||||
|         void onEvent(esp_event_handler_t callback); | ||||
|         void onEvent(arduino_usb_event_t event, esp_event_handler_t callback); | ||||
|          | ||||
|         bool VID(uint16_t v); | ||||
|         uint16_t VID(void); | ||||
|  | ||||
|         bool PID(uint16_t p); | ||||
|         uint16_t PID(void); | ||||
|  | ||||
|         bool firmwareVersion(uint16_t version); | ||||
|         uint16_t firmwareVersion(void); | ||||
|  | ||||
|         bool usbVersion(uint16_t version); | ||||
|         uint16_t usbVersion(void); | ||||
|  | ||||
|         bool usbPower(uint16_t mA); | ||||
|         uint16_t usbPower(void); | ||||
|  | ||||
|         bool usbClass(uint8_t _class); | ||||
|         uint8_t usbClass(void); | ||||
|  | ||||
|         bool usbSubClass(uint8_t subClass); | ||||
|         uint8_t usbSubClass(void); | ||||
|  | ||||
|         bool usbProtocol(uint8_t protocol); | ||||
|         uint8_t usbProtocol(void); | ||||
|  | ||||
|         bool usbAttributes(uint8_t attr); | ||||
|         uint8_t usbAttributes(void); | ||||
|  | ||||
|         bool webUSB(bool enabled); | ||||
|         bool webUSB(void); | ||||
|          | ||||
|         bool productName(const char * name); | ||||
|         const char * productName(void); | ||||
|  | ||||
|         bool manufacturerName(const char * name); | ||||
|         const char * manufacturerName(void); | ||||
|  | ||||
|         bool serialNumber(const char * name); | ||||
|         const char * serialNumber(void); | ||||
|  | ||||
|         bool webUSBURL(const char * name); | ||||
|         const char * webUSBURL(void); | ||||
|  | ||||
|         bool enableDFU(); | ||||
|         bool begin(); | ||||
|         operator bool() const; | ||||
|          | ||||
|     private: | ||||
|         uint16_t vid; | ||||
|         uint16_t pid; | ||||
|         String product_name; | ||||
|         String manufacturer_name; | ||||
|         String serial_number; | ||||
|         uint16_t fw_version; | ||||
|         uint16_t usb_version; | ||||
|         uint8_t usb_class; | ||||
|         uint8_t usb_subclass; | ||||
|         uint8_t usb_protocol; | ||||
|         uint8_t usb_attributes; | ||||
|         uint16_t usb_power_ma; | ||||
|         bool webusb_enabled; | ||||
|         String webusb_url; | ||||
|          | ||||
|         bool _started; | ||||
|         size_t _task_stack_size; | ||||
|         uint8_t _event_task_priority; | ||||
| }; | ||||
|  | ||||
| extern ESPUSB USB; | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_ENABLED */ | ||||
							
								
								
									
										453
									
								
								cores/esp32/USBCDC.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										453
									
								
								cores/esp32/USBCDC.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,453 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #include "USB.h" | ||||
| #if CONFIG_TINYUSB_CDC_ENABLED | ||||
|  | ||||
| #include "USBCDC.h" | ||||
| #include "esp32-hal-tinyusb.h" | ||||
|  | ||||
| ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS); | ||||
| esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); | ||||
| esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); | ||||
|  | ||||
| #define MAX_USB_CDC_DEVICES 2 | ||||
| USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; | ||||
|  | ||||
| static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) | ||||
| { | ||||
|     uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); | ||||
|     uint8_t descriptor[TUD_CDC_DESC_LEN] = { | ||||
|             // Interface number, string index, EP notification address and size, EP data address (out, in) and size. | ||||
|             TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64) | ||||
|     }; | ||||
|     *itf+=2; | ||||
|     memcpy(dst, descriptor, TUD_CDC_DESC_LEN); | ||||
|     return TUD_CDC_DESC_LEN; | ||||
| } | ||||
|  | ||||
| // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE | ||||
| void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) | ||||
| { | ||||
|     if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ | ||||
|         devices[itf]->_onLineState(dtr, rts); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Invoked when line coding is change via SET_LINE_CODING | ||||
| void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) | ||||
| { | ||||
|     if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ | ||||
|         devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Invoked when received new data | ||||
| void tud_cdc_rx_cb(uint8_t itf) | ||||
| { | ||||
|     if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ | ||||
|         devices[itf]->_onRX(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Invoked when received send break | ||||
| void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){ | ||||
|     //log_v("itf: %u, duration_ms: %u", itf, duration_ms); | ||||
| } | ||||
|  | ||||
| // Invoked when space becomes available in TX buffer | ||||
| void tud_cdc_tx_complete_cb(uint8_t itf){ | ||||
|     if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ | ||||
|         devices[itf]->_onTX(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void ARDUINO_ISR_ATTR cdc0_write_char(char c){ | ||||
|     if(devices[0] != NULL){ | ||||
|         devices[0]->write(c); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ | ||||
|     ((USBCDC*)arg)->_onUnplugged(); | ||||
| } | ||||
|  | ||||
| USBCDC::USBCDC(uint8_t itfn)  | ||||
| : itf(itfn) | ||||
| , bit_rate(0) | ||||
| , stop_bits(0) | ||||
| , parity(0) | ||||
| , data_bits(0) | ||||
| , dtr(false) | ||||
| , rts(false) | ||||
| , connected(false) | ||||
| , reboot_enable(true) | ||||
| , rx_queue(NULL) | ||||
| , tx_lock(NULL) | ||||
| , tx_timeout_ms(250) | ||||
| { | ||||
|     tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor); | ||||
|     if(itf < MAX_USB_CDC_DEVICES){ | ||||
|         arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this); | ||||
|     } | ||||
| } | ||||
|  | ||||
| USBCDC::~USBCDC(){ | ||||
|     end(); | ||||
| } | ||||
|  | ||||
| void USBCDC::onEvent(esp_event_handler_t callback){ | ||||
|     onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback); | ||||
| } | ||||
| void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback){ | ||||
|     arduino_usb_event_handler_register_with(ARDUINO_USB_CDC_EVENTS, event, callback, this); | ||||
| } | ||||
|  | ||||
| size_t USBCDC::setRxBufferSize(size_t rx_queue_len){ | ||||
|     size_t currentQueueSize = rx_queue ?  | ||||
|             uxQueueSpacesAvailable(rx_queue) + uxQueueMessagesWaiting(rx_queue) : 0; | ||||
|  | ||||
|     if (rx_queue_len != currentQueueSize) { | ||||
|         xQueueHandle new_rx_queue = NULL; | ||||
|         if (rx_queue_len) { | ||||
|             new_rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); | ||||
|             if(!new_rx_queue){ | ||||
|                 log_e("CDC Queue creation failed."); | ||||
|                 return 0; | ||||
|             } | ||||
|             if (rx_queue) { | ||||
|                 size_t copySize = uxQueueMessagesWaiting(rx_queue); | ||||
|                 if (copySize > 0) { | ||||
|                     for(size_t i = 0; i < copySize; i++) { | ||||
|                         uint8_t ch = 0; | ||||
|                         xQueueReceive(rx_queue, &ch, 0); | ||||
|                         if (!xQueueSend(new_rx_queue, &ch, 0)) { | ||||
|                             arduino_usb_cdc_event_data_t p; | ||||
|                             p.rx_overflow.dropped_bytes = copySize - i; | ||||
|                             arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|                             log_e("CDC RX Overflow."); | ||||
|                             break; | ||||
|                         } | ||||
|                     }     | ||||
|                 } | ||||
|                 vQueueDelete(rx_queue); | ||||
|             } | ||||
|             rx_queue = new_rx_queue; | ||||
|             return rx_queue_len; | ||||
|         } else { | ||||
|             if (rx_queue) { | ||||
|                     vQueueDelete(rx_queue); | ||||
|                     rx_queue = NULL; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return rx_queue_len; | ||||
| } | ||||
|  | ||||
| void USBCDC::begin(unsigned long baud) | ||||
| { | ||||
|     if(tx_lock == NULL) { | ||||
|         tx_lock = xSemaphoreCreateMutex(); | ||||
|     } | ||||
|     // if rx_queue was set before begin(), keep it | ||||
|     if (!rx_queue) setRxBufferSize(256); //default if not preset | ||||
|     devices[itf] = this; | ||||
| } | ||||
|  | ||||
| void USBCDC::end() | ||||
| { | ||||
|     connected = false; | ||||
|     devices[itf] = NULL; | ||||
|     setRxBufferSize(0); | ||||
|     if(tx_lock != NULL) { | ||||
|         vSemaphoreDelete(tx_lock); | ||||
|         tx_lock = NULL; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void USBCDC::setTxTimeoutMs(uint32_t timeout){ | ||||
|     tx_timeout_ms = timeout; | ||||
| } | ||||
|  | ||||
| void USBCDC::_onUnplugged(void){ | ||||
|     if(connected){ | ||||
|         connected = false; | ||||
|         dtr = false; | ||||
|         rts = false; | ||||
|         arduino_usb_cdc_event_data_t p; | ||||
|         arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|     } | ||||
| } | ||||
|  | ||||
| enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 }; | ||||
| void USBCDC::_onLineState(bool _dtr, bool _rts){ | ||||
|     static uint8_t lineState = CDC_LINE_IDLE; | ||||
|  | ||||
|     if(dtr == _dtr && rts == _rts){ | ||||
|         return; // Skip duplicate events | ||||
|     } | ||||
|  | ||||
|     dtr = _dtr; | ||||
|     rts = _rts; | ||||
|  | ||||
|     if(reboot_enable){ | ||||
|         if(!dtr && rts){ | ||||
|             if(lineState == CDC_LINE_IDLE){ | ||||
|                 lineState++; | ||||
|                 if(connected){ | ||||
|                     connected = false; | ||||
|                     arduino_usb_cdc_event_data_t p; | ||||
|                     arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|                 } | ||||
|             } else { | ||||
|                 lineState = CDC_LINE_IDLE; | ||||
|             } | ||||
|         } else if(dtr && rts){ | ||||
|             if(lineState == CDC_LINE_1){ | ||||
|                 lineState++; | ||||
|             } else { | ||||
|                 lineState = CDC_LINE_IDLE; | ||||
|             } | ||||
|         } else if(dtr && !rts){ | ||||
|             if(lineState == CDC_LINE_2){ | ||||
|                 lineState++; | ||||
|             } else { | ||||
|                 lineState = CDC_LINE_IDLE; | ||||
|             } | ||||
|         } else if(!dtr && !rts){ | ||||
|             if(lineState == CDC_LINE_3){ | ||||
|                 usb_persist_restart(RESTART_BOOTLOADER); | ||||
|             } else { | ||||
|                 lineState = CDC_LINE_IDLE; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     if(lineState == CDC_LINE_IDLE){ | ||||
|         if(dtr && rts && !connected){ | ||||
|             connected = true; | ||||
|             arduino_usb_cdc_event_data_t p; | ||||
|             arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|         } else if(!dtr && connected){ | ||||
|             connected = false; | ||||
|             arduino_usb_cdc_event_data_t p; | ||||
|             arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|         } | ||||
|         arduino_usb_cdc_event_data_t l; | ||||
|         l.line_state.dtr = dtr; | ||||
|         l.line_state.rts = rts; | ||||
|         arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){ | ||||
|     if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){ | ||||
|         // ArduinoIDE sends LineCoding with 1200bps baud to reset the device | ||||
|         if(reboot_enable && _bit_rate == 1200){ | ||||
|             usb_persist_restart(RESTART_BOOTLOADER); | ||||
|         } else { | ||||
|             bit_rate = _bit_rate; | ||||
|             data_bits = _data_bits; | ||||
|             stop_bits = _stop_bits; | ||||
|             parity = _parity; | ||||
|             arduino_usb_cdc_event_data_t p; | ||||
|             p.line_coding.bit_rate = bit_rate; | ||||
|             p.line_coding.data_bits = data_bits; | ||||
|             p.line_coding.stop_bits = stop_bits; | ||||
|             p.line_coding.parity = parity; | ||||
|             arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void USBCDC::_onRX(){ | ||||
|     arduino_usb_cdc_event_data_t p; | ||||
|     uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE+1]; | ||||
|     uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE); | ||||
|     for(uint32_t i=0; i<count; i++){ | ||||
|         if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 10)) { | ||||
|             p.rx_overflow.dropped_bytes = count - i; | ||||
|             arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|             log_e("CDC RX Overflow."); | ||||
|             count = i; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if (count) { | ||||
|         p.rx.len = count; | ||||
|         arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void USBCDC::_onTX(){ | ||||
|     arduino_usb_cdc_event_data_t p; | ||||
|     arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_TX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); | ||||
| } | ||||
|  | ||||
| void  USBCDC::enableReboot(bool enable){ | ||||
|     reboot_enable = enable; | ||||
| } | ||||
| bool  USBCDC::rebootEnabled(void){ | ||||
|     return reboot_enable; | ||||
| } | ||||
|  | ||||
| int USBCDC::available(void) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     return uxQueueMessagesWaiting(rx_queue); | ||||
| } | ||||
|  | ||||
| int USBCDC::peek(void) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c; | ||||
|     if(xQueuePeek(rx_queue, &c, 0)) { | ||||
|         return c; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int USBCDC::read(void) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|     if(xQueueReceive(rx_queue, &c, 0)) { | ||||
|         return c; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| size_t USBCDC::read(uint8_t *buffer, size_t size) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|     size_t count = 0; | ||||
|     while(count < size && xQueueReceive(rx_queue, &c, 0)){ | ||||
|         buffer[count++] = c; | ||||
|     } | ||||
|     return count; | ||||
| } | ||||
|  | ||||
| void USBCDC::flush(void) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ | ||||
|         return; | ||||
|     } | ||||
|     if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return; | ||||
|     } | ||||
|     tud_cdc_n_write_flush(itf); | ||||
|     xSemaphoreGive(tx_lock); | ||||
| } | ||||
|  | ||||
| int USBCDC::availableForWrite(void) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return 0; | ||||
|     } | ||||
|     size_t a = tud_cdc_n_write_available(itf); | ||||
|     xSemaphoreGive(tx_lock); | ||||
|     return a; | ||||
| } | ||||
|  | ||||
| size_t USBCDC::write(const uint8_t *buffer, size_t size) | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(xPortInIsrContext()){ | ||||
|         BaseType_t taskWoken = false; | ||||
|         if(xSemaphoreTakeFromISR(tx_lock, &taskWoken) != pdPASS){ | ||||
|             return 0; | ||||
|         } | ||||
|     } else if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ | ||||
|         return 0; | ||||
|     } | ||||
|     size_t to_send = size, so_far = 0; | ||||
|     while(to_send){ | ||||
|         if(!tud_cdc_n_connected(itf)){ | ||||
|             size = so_far; | ||||
|             break; | ||||
|         } | ||||
|         size_t space = tud_cdc_n_write_available(itf); | ||||
|         if(!space){ | ||||
|             tud_cdc_n_write_flush(itf); | ||||
|             continue; | ||||
|         } | ||||
|         if(space > to_send){ | ||||
|             space = to_send; | ||||
|         } | ||||
|         size_t sent = tud_cdc_n_write(itf, buffer+so_far, space); | ||||
|         if(sent){ | ||||
|             so_far += sent; | ||||
|             to_send -= sent; | ||||
|             tud_cdc_n_write_flush(itf); | ||||
|         } else { | ||||
|             size = so_far; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(xPortInIsrContext()){ | ||||
|         BaseType_t taskWoken = false; | ||||
|         xSemaphoreGiveFromISR(tx_lock, &taskWoken); | ||||
|     } else { | ||||
|         xSemaphoreGive(tx_lock); | ||||
|     } | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| size_t USBCDC::write(uint8_t c) | ||||
| { | ||||
|     return write(&c, 1); | ||||
| } | ||||
|  | ||||
| uint32_t  USBCDC::baudRate() | ||||
| { | ||||
|     return bit_rate; | ||||
| } | ||||
|  | ||||
| void USBCDC::setDebugOutput(bool en) | ||||
| { | ||||
|     if(en) { | ||||
|         uartSetDebug(NULL); | ||||
|         ets_install_putc1((void (*)(char)) &cdc0_write_char); | ||||
|     } else { | ||||
|         ets_install_putc1(NULL); | ||||
|     } | ||||
| } | ||||
|  | ||||
| USBCDC::operator bool() const | ||||
| { | ||||
|     if(itf >= MAX_USB_CDC_DEVICES){ | ||||
|         return false; | ||||
|     } | ||||
|     return connected; | ||||
| } | ||||
|  | ||||
| #if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC | ||||
| USBCDC Serial(0); | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_CDC_ENABLED */ | ||||
							
								
								
									
										145
									
								
								cores/esp32/USBCDC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								cores/esp32/USBCDC.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
| #if CONFIG_TINYUSB_CDC_ENABLED | ||||
|  | ||||
| #include <inttypes.h> | ||||
| #include "esp_event.h" | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/queue.h" | ||||
| #include "freertos/semphr.h" | ||||
| #include "Stream.h" | ||||
|  | ||||
| ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS); | ||||
|  | ||||
| typedef enum { | ||||
|     ARDUINO_USB_CDC_ANY_EVENT = ESP_EVENT_ANY_ID, | ||||
|     ARDUINO_USB_CDC_CONNECTED_EVENT = 0, | ||||
|     ARDUINO_USB_CDC_DISCONNECTED_EVENT, | ||||
|     ARDUINO_USB_CDC_LINE_STATE_EVENT, | ||||
|     ARDUINO_USB_CDC_LINE_CODING_EVENT, | ||||
|     ARDUINO_USB_CDC_RX_EVENT, | ||||
|     ARDUINO_USB_CDC_TX_EVENT, | ||||
|     ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, | ||||
|     ARDUINO_USB_CDC_MAX_EVENT, | ||||
| } arduino_usb_cdc_event_t; | ||||
|  | ||||
| typedef union { | ||||
|     struct { | ||||
|             bool dtr; | ||||
|             bool rts; | ||||
|     } line_state; | ||||
|     struct { | ||||
|             uint32_t bit_rate; | ||||
|             uint8_t  stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits | ||||
|             uint8_t  parity;    ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space | ||||
|             uint8_t  data_bits; ///< can be 5, 6, 7, 8 or 16 | ||||
|     } line_coding; | ||||
|     struct { | ||||
|             size_t len; | ||||
|     } rx; | ||||
|     struct { | ||||
|             size_t dropped_bytes; | ||||
|     } rx_overflow; | ||||
| } arduino_usb_cdc_event_data_t; | ||||
|  | ||||
| class USBCDC: public Stream | ||||
| { | ||||
| public: | ||||
|     USBCDC(uint8_t itf=0); | ||||
|     ~USBCDC(); | ||||
|  | ||||
|     void onEvent(esp_event_handler_t callback); | ||||
|     void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback); | ||||
|  | ||||
|     size_t setRxBufferSize(size_t size); | ||||
|     void setTxTimeoutMs(uint32_t timeout); | ||||
|     void begin(unsigned long baud=0); | ||||
|     void end(); | ||||
|      | ||||
|     int available(void); | ||||
|     int availableForWrite(void); | ||||
|     int peek(void); | ||||
|     int read(void); | ||||
|     size_t read(uint8_t *buffer, size_t size); | ||||
|     size_t write(uint8_t); | ||||
|     size_t write(const uint8_t *buffer, size_t size); | ||||
|     void flush(void); | ||||
|      | ||||
|     inline size_t read(char * buffer, size_t size) | ||||
|     { | ||||
|         return read((uint8_t*) buffer, size); | ||||
|     } | ||||
|     inline size_t write(const char * buffer, size_t size) | ||||
|     { | ||||
|         return write((uint8_t*) buffer, size); | ||||
|     } | ||||
|     inline size_t write(const char * s) | ||||
|     { | ||||
|         return write((uint8_t*) s, strlen(s)); | ||||
|     } | ||||
|     inline size_t write(unsigned long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(long n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(unsigned int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     inline size_t write(int n) | ||||
|     { | ||||
|         return write((uint8_t) n); | ||||
|     } | ||||
|     uint32_t baudRate(); | ||||
|     void setDebugOutput(bool); | ||||
|     operator bool() const; | ||||
|  | ||||
|     void enableReboot(bool enable); | ||||
|     bool rebootEnabled(void); | ||||
|  | ||||
|     //internal methods | ||||
|     void _onDFU(void); | ||||
|     void _onLineState(bool _dtr, bool _rts); | ||||
|     void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits); | ||||
|     void _onRX(void); | ||||
|     void _onTX(void); | ||||
|     void _onUnplugged(void); | ||||
|      | ||||
| protected: | ||||
|     uint8_t  itf; | ||||
|     uint32_t bit_rate; | ||||
|     uint8_t  stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits | ||||
|     uint8_t  parity;    ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space | ||||
|     uint8_t  data_bits; ///< can be 5, 6, 7, 8 or 16 | ||||
|     bool     dtr; | ||||
|     bool     rts; | ||||
|     bool     connected; | ||||
|     bool     reboot_enable; | ||||
|     xQueueHandle rx_queue; | ||||
|     xSemaphoreHandle tx_lock; | ||||
|     uint32_t tx_timeout_ms; | ||||
|      | ||||
| }; | ||||
|  | ||||
| #if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC | ||||
| extern USBCDC Serial; | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_CDC_ENABLED */ | ||||
							
								
								
									
										260
									
								
								cores/esp32/USBMSC.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								cores/esp32/USBMSC.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #include "USBMSC.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_MSC_ENABLED | ||||
|  | ||||
| #include "esp32-hal-tinyusb.h" | ||||
|  | ||||
| extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf) | ||||
| { | ||||
|     uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); | ||||
|     uint8_t ep_num = tinyusb_get_free_duplex_endpoint(); | ||||
|     TU_VERIFY (ep_num != 0); | ||||
|     uint8_t descriptor[TUD_MSC_DESC_LEN] = { | ||||
|         // Interface number, string index, EP Out & EP In address, EP size | ||||
|         TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) | ||||
|     }; | ||||
|     *itf+=1; | ||||
|     memcpy(dst, descriptor, TUD_MSC_DESC_LEN); | ||||
|     return TUD_MSC_DESC_LEN; | ||||
| } | ||||
|  | ||||
| typedef struct { | ||||
|     bool media_present; | ||||
|     uint8_t vendor_id[8]; | ||||
|     uint8_t product_id[16]; | ||||
|     uint8_t product_rev[4]; | ||||
|     uint16_t block_size; | ||||
|     uint32_t block_count; | ||||
|     bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject); | ||||
|     int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); | ||||
|     int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); | ||||
| } msc_lun_t; | ||||
|  | ||||
| static const uint8_t MSC_MAX_LUN = 3; | ||||
| static uint8_t MSC_ACTIVE_LUN = 0; | ||||
| static msc_lun_t msc_luns[MSC_MAX_LUN]; | ||||
|  | ||||
| static void cplstr(void *dst, const void * src, size_t max_len){ | ||||
|     if(!src || !dst || !max_len){ | ||||
|         return; | ||||
|     } | ||||
|     size_t l = strlen((const char *)src); | ||||
|     if(l > max_len){ | ||||
|         l = max_len; | ||||
|     } | ||||
|     memcpy(dst, src, l); | ||||
| } | ||||
|  | ||||
| // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation | ||||
| uint8_t tud_msc_get_maxlun_cb(void) | ||||
| { | ||||
|     log_v("%u", MSC_ACTIVE_LUN); | ||||
|     return MSC_ACTIVE_LUN; | ||||
| } | ||||
|  | ||||
| // Invoked when received SCSI_CMD_INQUIRY | ||||
| // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively | ||||
| void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) | ||||
| { | ||||
|     log_v("[%u]", lun); | ||||
|     cplstr(vendor_id  , msc_luns[lun].vendor_id, 8); | ||||
|     cplstr(product_id , msc_luns[lun].product_id, 16); | ||||
|     cplstr(product_rev, msc_luns[lun].product_rev, 4); | ||||
| } | ||||
|  | ||||
| // Invoked when received Test Unit Ready command. | ||||
| // return true allowing host to read/write this LUN e.g SD card inserted | ||||
| bool tud_msc_test_unit_ready_cb(uint8_t lun) | ||||
| { | ||||
|     log_v("[%u]: %u", lun, msc_luns[lun].media_present); | ||||
|     return msc_luns[lun].media_present; // RAM disk is always ready | ||||
| } | ||||
|  | ||||
| // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size | ||||
| // Application update block count and block size | ||||
| void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) | ||||
| { | ||||
|     log_v("[%u]", lun); | ||||
|     if(!msc_luns[lun].media_present){ | ||||
|         *block_count = 0; | ||||
|         *block_size  = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     *block_count = msc_luns[lun].block_count; | ||||
|     *block_size  = msc_luns[lun].block_size; | ||||
| } | ||||
|  | ||||
| // Invoked when received Start Stop Unit command | ||||
| // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage | ||||
| // - Start = 1 : active mode, if load_eject = 1 : load disk storage | ||||
| bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) | ||||
| { | ||||
|     log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject); | ||||
|     if(msc_luns[lun].start_stop){ | ||||
|         return msc_luns[lun].start_stop(power_condition, start, load_eject); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| // Callback invoked when received READ10 command. | ||||
| // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. | ||||
| int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) | ||||
| { | ||||
|     log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); | ||||
|     if(!msc_luns[lun].media_present){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(msc_luns[lun].read){ | ||||
|         return msc_luns[lun].read(lba, offset, buffer, bufsize); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| // Callback invoked when received WRITE10 command. | ||||
| // Process data in buffer to disk's storage and return number of written bytes | ||||
| int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) | ||||
| { | ||||
|     log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); | ||||
|     if(!msc_luns[lun].media_present){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(msc_luns[lun].write){ | ||||
|         return msc_luns[lun].write(lba, offset, buffer, bufsize); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| // Callback invoked when received an SCSI command not in built-in list below | ||||
| // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE | ||||
| // - READ10 and WRITE10 has their own callbacks | ||||
| int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) | ||||
| { | ||||
|     // read10 & write10 has their own callback and MUST not be handled here | ||||
|     log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize); | ||||
|  | ||||
|     void const* response = NULL; | ||||
|     uint16_t resplen = 0; | ||||
|  | ||||
|     // most scsi handled is input | ||||
|     bool in_xfer = true; | ||||
|      | ||||
|     if(!msc_luns[lun].media_present){ | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     switch (scsi_cmd[0]) { | ||||
|         case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: | ||||
|             // Host is about to read/write etc ... better not to disconnect disk | ||||
|             resplen = 0; | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             // Set Sense = Invalid Command Operation | ||||
|             tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); | ||||
|  | ||||
|             // negative means error -> tinyusb could stall and/or response with failed status | ||||
|             resplen = -1; | ||||
|             break; | ||||
|     } | ||||
|  | ||||
|     // return resplen must not larger than bufsize | ||||
|     if (resplen > bufsize) resplen = bufsize; | ||||
|  | ||||
|     if (response && (resplen > 0)) { | ||||
|         if (in_xfer) { | ||||
|             memcpy(buffer, response, resplen); | ||||
|         } else { | ||||
|             // SCSI output | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return resplen; | ||||
| } | ||||
|  | ||||
| USBMSC::USBMSC(){ | ||||
|     if(MSC_ACTIVE_LUN < MSC_MAX_LUN){ | ||||
|         _lun = MSC_ACTIVE_LUN; | ||||
|         MSC_ACTIVE_LUN++; | ||||
|         msc_luns[_lun].media_present = false; | ||||
|         msc_luns[_lun].vendor_id[0] = 0; | ||||
|         msc_luns[_lun].product_id[0] = 0; | ||||
|         msc_luns[_lun].product_rev[0] = 0; | ||||
|         msc_luns[_lun].block_size = 0; | ||||
|         msc_luns[_lun].block_count = 0; | ||||
|         msc_luns[_lun].start_stop = NULL; | ||||
|         msc_luns[_lun].read = NULL; | ||||
|         msc_luns[_lun].write = NULL; | ||||
|     } | ||||
|     if(_lun == 0){ | ||||
|         tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor); | ||||
|     } | ||||
| } | ||||
|  | ||||
| USBMSC::~USBMSC(){ | ||||
|   end(); | ||||
| } | ||||
|  | ||||
| bool USBMSC::begin(uint32_t block_count, uint16_t block_size){ | ||||
|     msc_luns[_lun].block_size = block_size; | ||||
|     msc_luns[_lun].block_count = block_count; | ||||
|     if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){ | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void USBMSC::end(){ | ||||
|     msc_luns[_lun].media_present = false; | ||||
|     msc_luns[_lun].vendor_id[0] = 0; | ||||
|     msc_luns[_lun].product_id[0] = 0; | ||||
|     msc_luns[_lun].product_rev[0] = 0; | ||||
|     msc_luns[_lun].block_size = 0; | ||||
|     msc_luns[_lun].block_count = 0; | ||||
|     msc_luns[_lun].start_stop = NULL; | ||||
|     msc_luns[_lun].read = NULL; | ||||
|     msc_luns[_lun].write = NULL; | ||||
| } | ||||
|  | ||||
| void USBMSC::vendorID(const char * vid){ | ||||
|     cplstr(msc_luns[_lun].vendor_id, vid, 8); | ||||
| } | ||||
|  | ||||
| void USBMSC::productID(const char * pid){ | ||||
|     cplstr(msc_luns[_lun].product_id, pid, 16); | ||||
| } | ||||
|  | ||||
| void USBMSC::productRevision(const char * rev){ | ||||
|     cplstr(msc_luns[_lun].product_rev, rev, 4); | ||||
| } | ||||
|  | ||||
| void USBMSC::onStartStop(msc_start_stop_cb cb){ | ||||
|     msc_luns[_lun].start_stop = cb; | ||||
| } | ||||
|  | ||||
| void USBMSC::onRead(msc_read_cb cb){ | ||||
|     msc_luns[_lun].read = cb; | ||||
| } | ||||
|  | ||||
| void USBMSC::onWrite(msc_write_cb cb){ | ||||
|     msc_luns[_lun].write = cb; | ||||
| } | ||||
|  | ||||
| void USBMSC::mediaPresent(bool media_present){ | ||||
|     msc_luns[_lun].media_present = media_present; | ||||
| } | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_MSC_ENABLED */ | ||||
							
								
								
									
										51
									
								
								cores/esp32/USBMSC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								cores/esp32/USBMSC.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "sdkconfig.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_MSC_ENABLED | ||||
|  | ||||
| // Invoked when received Start Stop Unit command | ||||
| // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage | ||||
| // - Start = 1 : active mode, if load_eject = 1 : load disk storage | ||||
| typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject); | ||||
|  | ||||
| // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. | ||||
| typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); | ||||
|  | ||||
| // Process data in buffer to disk's storage and return number of written bytes | ||||
| typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); | ||||
|  | ||||
| class USBMSC | ||||
| { | ||||
| public: | ||||
|     USBMSC(); | ||||
|     ~USBMSC(); | ||||
|     bool begin(uint32_t block_count, uint16_t block_size); | ||||
|     void end(); | ||||
|     void vendorID(const char * vid);//max 8 chars | ||||
|     void productID(const char * pid);//max 16 chars | ||||
|     void productRevision(const char * ver);//max 4 chars | ||||
|     void mediaPresent(bool media_present); | ||||
|     void onStartStop(msc_start_stop_cb cb); | ||||
|     void onRead(msc_read_cb cb); | ||||
|     void onWrite(msc_write_cb cb); | ||||
| private: | ||||
| 	uint8_t _lun; | ||||
| }; | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_MSC_ENABLED */ | ||||
							
								
								
									
										93
									
								
								cores/esp32/Udp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								cores/esp32/Udp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| /* | ||||
|  *  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 uint8_t beginMulticast(IPAddress, uint16_t) { return 0; }  // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure | ||||
|     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 | ||||
							
								
								
									
										154
									
								
								cores/esp32/WCharacter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								cores/esp32/WCharacter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| /* | ||||
|  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 | ||||
							
								
								
									
										88
									
								
								cores/esp32/WMath.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								cores/esp32/WMath.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| /* -*- 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" | ||||
| } | ||||
| #include "esp32-hal-log.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) { | ||||
|     const long run = in_max - in_min; | ||||
|     if(run == 0){ | ||||
|         log_e("map(): Invalid input range, min == max"); | ||||
|         return -1; // AVR returns -1, SAM returns 0 | ||||
|     } | ||||
|     const long rise = out_max - out_min; | ||||
|     const long delta = x - in_min; | ||||
|     return (delta * rise) / run + out_min; | ||||
| } | ||||
|  | ||||
| uint16_t makeWord(uint16_t w) | ||||
| { | ||||
|     return w; | ||||
| } | ||||
|  | ||||
| uint16_t makeWord(uint8_t h, uint8_t l) | ||||
| { | ||||
|     return (h << 8) | l; | ||||
| } | ||||
							
								
								
									
										918
									
								
								cores/esp32/WString.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										918
									
								
								cores/esp32/WString.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,918 @@ | ||||
| /* | ||||
|  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" | ||||
| #include "esp32-hal-log.h" | ||||
|  | ||||
| /*********************************************/ | ||||
| /*  Constructors                             */ | ||||
| /*********************************************/ | ||||
|  | ||||
| String::String(const char *cstr) { | ||||
|     init(); | ||||
|     if (cstr) | ||||
|         copy(cstr, strlen(cstr)); | ||||
| } | ||||
|  | ||||
| String::String(const char *cstr, unsigned int length) { | ||||
|     init(); | ||||
|     if (cstr) | ||||
|         copy(cstr, length); | ||||
| } | ||||
|  | ||||
| String::String(const String &value) { | ||||
|     init(); | ||||
|     *this = value; | ||||
| } | ||||
|  | ||||
| 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[] = { c, '\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 int decimalPlaces) { | ||||
|     init(); | ||||
|     char *buf = (char*)malloc(decimalPlaces + 42); | ||||
|     if (buf) { | ||||
|         *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); | ||||
|         free(buf); | ||||
|     } else { | ||||
|         *this = "nan"; | ||||
|         log_e("No enought memory for the operation."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| String::String(double value, unsigned int decimalPlaces) { | ||||
|     init(); | ||||
|     char *buf = (char*)malloc(decimalPlaces + 312); | ||||
|     if (buf) { | ||||
|         *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); | ||||
|         free(buf); | ||||
|     } else { | ||||
|         *this = "nan"; | ||||
|         log_e("No enought memory for the operation."); | ||||
|     } | ||||
| } | ||||
|  | ||||
| String::String(long long value, unsigned char base) { | ||||
|     init(); | ||||
|     char buf[2 + 8 * sizeof(long long)]; | ||||
|     if (base==10) { | ||||
|         sprintf(buf, "%lld", value);   // NOT SURE - NewLib Nano ... does it support %lld?  | ||||
|     } else { | ||||
|         lltoa(value, buf, base); | ||||
|     } | ||||
|     *this = buf; | ||||
| } | ||||
|  | ||||
| String::String(unsigned long long value, unsigned char base) { | ||||
|     init(); | ||||
|     char buf[1 + 8 * sizeof(unsigned long long)]; | ||||
|     ulltoa(value, buf, base); | ||||
|     *this = buf; | ||||
| } | ||||
|  | ||||
| String::~String() { | ||||
|     invalidate(); | ||||
| } | ||||
|  | ||||
| // /*********************************************/ | ||||
| // /*  Memory Management                        */ | ||||
| // /*********************************************/ | ||||
|  | ||||
| inline void String::init(void) { | ||||
|     setSSO(false); | ||||
|     setBuffer(nullptr); | ||||
|     setCapacity(0); | ||||
|     setLen(0); | ||||
| } | ||||
|  | ||||
| void String::invalidate(void) { | ||||
|     if(!isSSO() && 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.buff) - 1) { | ||||
|         if (isSSO() || !buffer()) { | ||||
|             // Already using SSO, nothing to do | ||||
| 	    uint16_t oldLen = len(); | ||||
|             setSSO(true); | ||||
|             setLen(oldLen); | ||||
|             return 1; | ||||
|         } else { // if bufptr && !isSSO() | ||||
|             // Using bufptr, need to shrink into sso.buff | ||||
|             char temp[sizeof(sso.buff)]; | ||||
|             memcpy(temp, buffer(), maxStrLen); | ||||
|             free(wbuffer()); | ||||
|             uint16_t oldLen = len(); | ||||
|             setSSO(true); | ||||
|             memcpy(wbuffer(), temp, maxStrLen); | ||||
|             setLen(oldLen); | ||||
|             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(isSSO() ? nullptr : wbuffer(), newSize); | ||||
|     if (newbuffer) { | ||||
|         size_t oldSize = capacity() + 1; // include NULL. | ||||
|         if (isSSO()) { | ||||
|             // Copy the SSO buffer into allocated space | ||||
|             memmove(newbuffer, sso.buff, sizeof(sso.buff)); | ||||
|         } | ||||
|         if (newSize > oldSize) | ||||
|         { | ||||
|             memset(newbuffer + oldSize, 0, newSize - oldSize); | ||||
|         } | ||||
|         setSSO(false); | ||||
|         setCapacity(newSize - 1); | ||||
|         setBuffer(newbuffer); | ||||
|         setLen(oldLen); // Needed in case of SSO where len() never existed | ||||
|         return 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| // /*********************************************/ | ||||
| // /*  Copy and Move                            */ | ||||
| // /*********************************************/ | ||||
|  | ||||
| String & String::copy(const char *cstr, unsigned int length) { | ||||
|     if(!reserve(length)) { | ||||
|         invalidate(); | ||||
|         return *this; | ||||
|     } | ||||
|     memmove(wbuffer(), cstr, length + 1); | ||||
|     setLen(length); | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { | ||||
|     if (!reserve(length)) { | ||||
|         invalidate(); | ||||
|         return *this; | ||||
|     } | ||||
|     memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here | ||||
|     setLen(length); | ||||
|     return *this; | ||||
| } | ||||
|  | ||||
| #ifdef __GXX_EXPERIMENTAL_CXX0X__ | ||||
| void String::move(String &rhs) { | ||||
|     if(buffer()) { | ||||
|         if(capacity() >= rhs.len()) { | ||||
|             memmove(wbuffer(), rhs.buffer(), rhs.length() + 1); | ||||
|             setLen(rhs.len()); | ||||
| 	    rhs.invalidate(); | ||||
|             return; | ||||
|         } else { | ||||
|             if (!isSSO()) { | ||||
|                 free(wbuffer()); | ||||
|                 setBuffer(nullptr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if (rhs.isSSO()) { | ||||
|         setSSO(true); | ||||
|         memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff)); | ||||
|     } else { | ||||
|         setSSO(false); | ||||
|         setBuffer(rhs.wbuffer()); | ||||
|     } | ||||
|     setCapacity(rhs.capacity()); | ||||
|     setLen(rhs.len()); | ||||
|     rhs.setSSO(false); | ||||
|     rhs.setCapacity(0); | ||||
|     rhs.setBuffer(nullptr); | ||||
|     rhs.setLen(0); | ||||
| } | ||||
| #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; | ||||
|         memmove(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; | ||||
|     if (cstr >= wbuffer() && cstr < wbuffer() + len()) | ||||
|         // compatible with SSO in ram #6155 (case "x += x.c_str()") | ||||
|         memmove(wbuffer() + len(), cstr, length + 1); | ||||
|     else | ||||
|         // compatible with source in flash #6367 | ||||
|         memcpy_P(wbuffer() + len(), cstr, length + 1); | ||||
|     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[] = { c, '\0' }; | ||||
|     return concat(buf, 1); | ||||
| } | ||||
|  | ||||
| unsigned char String::concat(unsigned char num) { | ||||
|     char buf[1 + 3 * sizeof(unsigned char)]; | ||||
|     return concat(buf, sprintf(buf, "%d", num)); | ||||
| } | ||||
|  | ||||
| unsigned char String::concat(int num) { | ||||
|     char buf[2 + 3 * sizeof(int)]; | ||||
|     return concat(buf, sprintf(buf, "%d", num)); | ||||
| } | ||||
|  | ||||
| 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)]; | ||||
|     return concat(buf, sprintf(buf, "%ld", num)); | ||||
| } | ||||
|  | ||||
| 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(long long num) { | ||||
|     char buf[2 + 3 * sizeof(long long)]; | ||||
|     return concat(buf, sprintf(buf, "%lld", num));    // NOT SURE - NewLib Nano ... does it support %lld? | ||||
| } | ||||
|  | ||||
| unsigned char String::concat(unsigned long long num) { | ||||
|     char buf[1 + 3 * sizeof(unsigned long long)]; | ||||
|     ulltoa(num, buf, 10); | ||||
|     return concat(buf, strlen(buf)); | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1); | ||||
|     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, long long num) { | ||||
|     StringSumHelper &a = const_cast<StringSumHelper&>(lhs); | ||||
|     if(!a.concat(num)) | ||||
|         a.invalidate(); | ||||
|     return a; | ||||
| } | ||||
|  | ||||
| StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long 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 lengths 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(); | ||||
|     out.copy(buffer() + left, right - left); | ||||
|     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(); | ||||
|         unsigned int l = len(); | ||||
|         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(); | ||||
|             l += diff; | ||||
|         } | ||||
|         memmove(writeTo, readFrom, strlen(readFrom)+1); | ||||
|         setLen(l); | ||||
|     } 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)) { | ||||
|             log_w("String.Replace() Insufficient space to replace string"); | ||||
|             return; | ||||
|         } | ||||
|         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; | ||||
|     memmove(writeTo, wbuffer() + index + count, newlen - index); | ||||
|     setLen(newlen); | ||||
|     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; | ||||
|     if(begin > buffer()) | ||||
|         memmove(wbuffer(), begin, newlen); | ||||
|     setLen(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; | ||||
							
								
								
									
										401
									
								
								cores/esp32/WString.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								cores/esp32/WString.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,401 @@ | ||||
| /* | ||||
|  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> | ||||
| #include <stdint.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 FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer)) | ||||
| #define F(string_literal) (FPSTR(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 char *cstr, unsigned int length); | ||||
| #ifdef __GXX_EXPERIMENTAL_CXX0X__ | ||||
|         String(const uint8_t *cstr, unsigned int length) : String((const char*)cstr, length) {} | ||||
| #endif | ||||
|         String(const String &str); | ||||
|         String(const __FlashStringHelper *str); | ||||
| #ifdef __GXX_EXPERIMENTAL_CXX0X__ | ||||
|         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 int decimalPlaces = 2); | ||||
|         explicit String(double, unsigned int decimalPlaces = 2); | ||||
|         explicit String(long long, unsigned char base = 10); | ||||
|         explicit String(unsigned long long, unsigned char base = 10); | ||||
|         ~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; | ||||
|             } | ||||
|         } | ||||
|         inline void clear(void) { | ||||
|             setLen(0); | ||||
|         } | ||||
|         inline bool isEmpty(void) const { | ||||
|             return length() == 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 unsuccessful. | ||||
|         unsigned char concat(const String &str); | ||||
|         unsigned char concat(const char *cstr); | ||||
|         unsigned char concat(const char *cstr, unsigned int length); | ||||
|         unsigned char concat(const uint8_t *cstr, unsigned int length) {return concat((const char*)cstr, length);} | ||||
|         unsigned char concat(char c); | ||||
|         unsigned char concat(unsigned char c); | ||||
|         unsigned char concat(int num); | ||||
|         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(long long num); | ||||
|         unsigned char concat(unsigned long long 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 +=(long long num) { | ||||
|             concat(num); | ||||
|             return (*this); | ||||
|         } | ||||
|         String & operator +=(unsigned long long 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); | ||||
|         friend StringSumHelper & operator +(const StringSumHelper &lhs, long long num); | ||||
|         friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num); | ||||
|  | ||||
|         // 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 char *prefix) const { | ||||
|             return this->startsWith(String(prefix)); | ||||
|         } | ||||
|         unsigned char startsWith(const __FlashStringHelper *prefix) const { | ||||
|             return this->startsWith(String(prefix)); | ||||
|         } | ||||
|         unsigned char startsWith(const String &prefix, unsigned int offset) const; | ||||
|         unsigned char endsWith(const String &suffix) const; | ||||
|         unsigned char endsWith(const char *suffix) const { | ||||
|             return this->endsWith(String(suffix)); | ||||
|         } | ||||
|         unsigned char endsWith(const __FlashStringHelper * suffix) const { | ||||
|             return this->endsWith(String(suffix)); | ||||
|         } | ||||
|  | ||||
|         // character access | ||||
|         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 replace(const char *find, const String &replace) { | ||||
|             this->replace(String(find), replace); | ||||
|         } | ||||
|         void replace(const __FlashStringHelper *find, const String &replace) { | ||||
|             this->replace(String(find), replace); | ||||
|         } | ||||
|         void replace(const char *find, const char *replace) { | ||||
|             this->replace(String(find), String(replace)); | ||||
|         } | ||||
|         void replace(const __FlashStringHelper *find, const char *replace) { | ||||
|             this->replace(String(find), String(replace)); | ||||
|         } | ||||
|         void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) { | ||||
|             this->replace(String(find), 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; | ||||
|             uint32_t cap; | ||||
|             uint32_t len; | ||||
|         }; | ||||
|         // This allows strings up up to 11 (10 + \0 termination) without any extra space. | ||||
|         enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more | ||||
|         struct _sso { | ||||
|             char     buff[SSOSIZE]; | ||||
|             unsigned char len   : 7; // Ensure only one byte is allocated by GCC for the bitfields | ||||
|             unsigned char isSSO : 1; | ||||
|         } __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues | ||||
| #ifdef BOARD_HAS_PSRAM | ||||
|         enum { CAPACITY_MAX = 3145728 };  | ||||
| #else | ||||
|         enum { CAPACITY_MAX = 65535 };  | ||||
| #endif | ||||
|         union { | ||||
|             struct _ptr ptr; | ||||
|             struct _sso sso; | ||||
|         }; | ||||
|         // Accessor functions | ||||
|         inline bool isSSO() const { return sso.isSSO; } | ||||
|         inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; } | ||||
|         inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL | ||||
|         inline void setSSO(bool set) { sso.isSSO = set; } | ||||
|         inline void setLen(int len) { | ||||
|             if (isSSO()) { | ||||
|                 sso.len = len; | ||||
|                 sso.buff[len] = 0; | ||||
|             } else { | ||||
|                 ptr.len = len; | ||||
|                 if (ptr.buff) { | ||||
|                     ptr.buff[len] = 0; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; } | ||||
|         inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; } | ||||
|         // Buffer accessor functions | ||||
|         inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); } | ||||
|         inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer | ||||
|  | ||||
|     protected: | ||||
|         void init(void); | ||||
|         void invalidate(void); | ||||
|         unsigned char changeBuffer(unsigned int maxStrLen); | ||||
|  | ||||
|         // 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) { | ||||
|         } | ||||
|         StringSumHelper(long long num) : | ||||
|                 String(num) { | ||||
|         } | ||||
|         StringSumHelper(unsigned long long num) : | ||||
|                 String(num) { | ||||
|         } | ||||
| }; | ||||
|  | ||||
| extern const String emptyString; | ||||
|  | ||||
| #endif  // __cplusplus | ||||
| #endif  // String_class_h | ||||
							
								
								
									
										1
									
								
								cores/esp32/apps/sntp/sntp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cores/esp32/apps/sntp/sntp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| #include "lwip/apps/sntp.h" | ||||
							
								
								
									
										64
									
								
								cores/esp32/base64.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								cores/esp32/base64.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /** | ||||
|  * 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 const uint8_t * | ||||
|  * @param length size_t | ||||
|  * @return String | ||||
|  */ | ||||
| String base64::encode(const 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 const String& | ||||
|  * @return String | ||||
|  */ | ||||
| String base64::encode(const String& text) | ||||
| { | ||||
|     return base64::encode((uint8_t *) text.c_str(), text.length()); | ||||
| } | ||||
|  | ||||
							
								
								
									
										13
									
								
								cores/esp32/base64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								cores/esp32/base64.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #ifndef CORE_BASE64_H_ | ||||
| #define CORE_BASE64_H_ | ||||
|  | ||||
| class base64 | ||||
| { | ||||
| public: | ||||
|     static String encode(const uint8_t * data, size_t length); | ||||
|     static String encode(const String& text); | ||||
| private: | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif /* CORE_BASE64_H_ */ | ||||
							
								
								
									
										534
									
								
								cores/esp32/binary.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										534
									
								
								cores/esp32/binary.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,534 @@ | ||||
| /* | ||||
|  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 | ||||
							
								
								
									
										196
									
								
								cores/esp32/cbuf.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								cores/esp32/cbuf.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | ||||
| /* | ||||
|  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(); | ||||
| } | ||||
							
								
								
									
										79
									
								
								cores/esp32/cbuf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								cores/esp32/cbuf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| /* | ||||
|  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; | ||||
|  | ||||
| protected: | ||||
|     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 | ||||
							
								
								
									
										281
									
								
								cores/esp32/esp32-hal-adc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								cores/esp32/esp32-hal-adc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,281 @@ | ||||
| // 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 "driver/adc.h" | ||||
| #include "esp_adc_cal.h" | ||||
|  | ||||
| #if SOC_DAC_SUPPORTED           //ESP32, ESP32S2 | ||||
| #include "soc/dac_channel.h" | ||||
| #include "soc/sens_reg.h" | ||||
| #include "soc/rtc_io_reg.h" | ||||
| #endif | ||||
|  | ||||
| #define DEFAULT_VREF    1100 | ||||
|  | ||||
| static uint8_t __analogAttenuation = 3;//11db | ||||
| static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2 | ||||
| static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP32C3; 13 for ESP32S2 | ||||
| static uint8_t __analogClockDiv = 1; | ||||
| static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT]; | ||||
|  | ||||
| static uint16_t __analogVRef = 0; | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| static uint8_t __analogVRefPin = 0; | ||||
| #endif | ||||
|  | ||||
| static inline uint16_t mapResolution(uint16_t value) | ||||
| { | ||||
|     uint8_t from = __analogWidth + 9; | ||||
|     if (from == __analogReturnedWidth) { | ||||
|         return value; | ||||
|     } | ||||
|     if (from > __analogReturnedWidth) { | ||||
|         return value >> (from  - __analogReturnedWidth); | ||||
|     } | ||||
|     return value << (__analogReturnedWidth - from); | ||||
| } | ||||
|  | ||||
| void __analogSetClockDiv(uint8_t clockDiv){ | ||||
|     if(!clockDiv){ | ||||
|         clockDiv = 1; | ||||
|     } | ||||
|     __analogClockDiv = clockDiv; | ||||
| #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 | ||||
|     adc_set_clk_div(__analogClockDiv); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void __analogSetAttenuation(adc_attenuation_t attenuation) | ||||
| { | ||||
|     __analogAttenuation = attenuation & 3; | ||||
| } | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| void __analogSetWidth(uint8_t bits){ | ||||
|     if(bits < 9){ | ||||
|         bits = 9; | ||||
|     } else if(bits > 12){ | ||||
|         bits = 12; | ||||
|     } | ||||
|     __analogWidth = bits - 9; | ||||
|     adc1_config_width(__analogWidth); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void __analogInit(){ | ||||
|     static bool initialized = false; | ||||
|     if(initialized){ | ||||
|         return; | ||||
|     } | ||||
|     initialized = true; | ||||
|     __analogSetClockDiv(__analogClockDiv); | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     __analogSetWidth(__analogWidth + 9);//in bits | ||||
| #endif | ||||
|     for(int i=0; i<SOC_GPIO_PIN_COUNT; i++){ | ||||
|         __pin_attenuation[i] = ADC_ATTENDB_MAX; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) | ||||
| { | ||||
|     int8_t channel = digitalPinToAnalogChannel(pin); | ||||
|     if(channel < 0 || attenuation > 3){ | ||||
|         return ; | ||||
|     } | ||||
|     if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ | ||||
|         adc2_config_channel_atten(channel - SOC_ADC_MAX_CHANNEL_NUM, attenuation); | ||||
|     } else { | ||||
|         adc1_config_channel_atten(channel, attenuation); | ||||
|     } | ||||
|     __analogInit(); | ||||
|     if((__pin_attenuation[pin] != ADC_ATTENDB_MAX) || (attenuation != __analogAttenuation)){ | ||||
|         __pin_attenuation[pin] = attenuation; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool __adcAttachPin(uint8_t pin){ | ||||
|     int8_t channel = digitalPinToAnalogChannel(pin); | ||||
|     if(channel < 0){ | ||||
|         log_e("Pin %u is not ADC pin!", pin); | ||||
|         return false; | ||||
|     } | ||||
|     __analogInit(); | ||||
|     int8_t pad = digitalPinToTouchChannel(pin); | ||||
|     if(pad >= 0){ | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|         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); | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
| #if SOC_DAC_SUPPORTED | ||||
|     else if(pin == DAC_CHANNEL_1_GPIO_NUM){ | ||||
|         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 == DAC_CHANNEL_2_GPIO_NUM){ | ||||
|         CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);//stop dac2 | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     pinMode(pin, ANALOG); | ||||
|     __analogSetPinAttenuation(pin, (__pin_attenuation[pin] != ADC_ATTENDB_MAX)?__pin_attenuation[pin]:__analogAttenuation); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| void __analogReadResolution(uint8_t bits) | ||||
| { | ||||
|     if(!bits || bits > 16){ | ||||
|         return; | ||||
|     } | ||||
|     __analogReturnedWidth = bits; | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     __analogSetWidth(bits);         // hadware from 9 to 12 | ||||
| #endif | ||||
| } | ||||
|  | ||||
| uint16_t __analogRead(uint8_t pin) | ||||
| { | ||||
|     int8_t channel = digitalPinToAnalogChannel(pin); | ||||
|     int value = 0; | ||||
|     esp_err_t r = ESP_OK; | ||||
|     if(channel < 0){ | ||||
|         log_e("Pin %u is not ADC pin!", pin); | ||||
|         return value; | ||||
|     } | ||||
|     __adcAttachPin(pin); | ||||
|     if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ | ||||
|         channel -= SOC_ADC_MAX_CHANNEL_NUM; | ||||
|         r = adc2_get_raw( channel, __analogWidth, &value); | ||||
|         if ( r == ESP_OK ) { | ||||
|             return mapResolution(value); | ||||
|         } else if ( r == ESP_ERR_INVALID_STATE ) { | ||||
|             log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r)); | ||||
|         } else if ( r == ESP_ERR_TIMEOUT ) { | ||||
|             log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi. Please see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html#adc-limitations for more info", pin, esp_err_to_name(r)); | ||||
|         } else { | ||||
|             log_e("GPIO%u: %s", pin, esp_err_to_name(r)); | ||||
|         } | ||||
|     } else { | ||||
|         value = adc1_get_raw(channel); | ||||
|         return mapResolution(value); | ||||
|     } | ||||
|     return mapResolution(value); | ||||
| } | ||||
|  | ||||
| uint32_t __analogReadMilliVolts(uint8_t pin){ | ||||
|     int8_t channel = digitalPinToAnalogChannel(pin); | ||||
|     if(channel < 0){ | ||||
|         log_e("Pin %u is not ADC pin!", pin); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if(!__analogVRef){ | ||||
|         if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { | ||||
|             log_d("eFuse Two Point: Supported"); | ||||
|             __analogVRef = DEFAULT_VREF; | ||||
|         } | ||||
|         if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { | ||||
|             log_d("eFuse Vref: Supported"); | ||||
|             __analogVRef = DEFAULT_VREF; | ||||
|         } | ||||
|         if(!__analogVRef){ | ||||
|             __analogVRef = DEFAULT_VREF; | ||||
|  | ||||
|             #if CONFIG_IDF_TARGET_ESP32 | ||||
|             if(__analogVRefPin){ | ||||
|                 esp_adc_cal_characteristics_t chars; | ||||
|                 if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){ | ||||
|                     __analogVRef = __analogRead(__analogVRefPin); | ||||
|                     esp_adc_cal_characterize(1, __analogAttenuation, __analogWidth, DEFAULT_VREF, &chars); | ||||
|                     __analogVRef = esp_adc_cal_raw_to_voltage(__analogVRef, &chars); | ||||
|                     log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef); | ||||
|                 } | ||||
|             } | ||||
|             #endif | ||||
|         } | ||||
|     } | ||||
|     uint8_t unit = 1; | ||||
|     if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){ | ||||
|         unit = 2; | ||||
|     } | ||||
|  | ||||
|     uint16_t adc_reading = __analogRead(pin); | ||||
|  | ||||
|     uint8_t atten = __analogAttenuation; | ||||
|     if (__pin_attenuation[pin] != ADC_ATTENDB_MAX){ | ||||
|         atten = __pin_attenuation[pin]; | ||||
|     } | ||||
|  | ||||
|     esp_adc_cal_characteristics_t chars = {}; | ||||
|     esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, __analogWidth, __analogVRef, &chars); | ||||
|  | ||||
|     static bool print_chars_info = true; | ||||
|     if(print_chars_info) | ||||
|     { | ||||
|         if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { | ||||
|             log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, chars.vref); | ||||
|         }  | ||||
|         else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { | ||||
|             log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, chars.vref); | ||||
|         }  | ||||
|         #if CONFIG_IDF_TARGET_ESP32 | ||||
|         else if(__analogVRef != DEFAULT_VREF){ | ||||
|             log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, chars.vref); | ||||
|         } | ||||
|         #endif | ||||
|         else { | ||||
|             log_i("ADC%u: Characterized using Default Vref: %u\n", unit, chars.vref); | ||||
|         } | ||||
|         print_chars_info = false; | ||||
|     } | ||||
|     return esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, &chars); | ||||
| } | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|  | ||||
| void __analogSetVRefPin(uint8_t pin){ | ||||
|     if(pin <25 || pin > 27){ | ||||
|         pin = 0; | ||||
|     } | ||||
|     __analogVRefPin = pin; | ||||
| } | ||||
|  | ||||
| int __hallRead()    //hall sensor using idf read | ||||
| { | ||||
|     pinMode(36, ANALOG); | ||||
|     pinMode(39, ANALOG); | ||||
|     __analogSetWidth(12); | ||||
|     return hall_sensor_read(); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead"))); | ||||
| extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts"))); | ||||
| extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution"))); | ||||
| 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 bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin"))); | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin"))); | ||||
| extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth"))); | ||||
| extern int hallRead() __attribute__ ((weak, alias("__hallRead"))); | ||||
| #endif | ||||
							
								
								
									
										104
									
								
								cores/esp32/esp32-hal-adc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								cores/esp32/esp32-hal-adc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
|  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_ATTENDB_MAX | ||||
| } adc_attenuation_t; | ||||
|  | ||||
| /* | ||||
|  * Get ADC value for pin | ||||
|  * */ | ||||
| uint16_t analogRead(uint8_t pin); | ||||
|  | ||||
| /* | ||||
|  * Get MilliVolts value for pin | ||||
|  * */ | ||||
| uint32_t analogReadMilliVolts(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); | ||||
|  | ||||
| /* | ||||
|  * 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); | ||||
|  | ||||
| /* | ||||
|  * Attach pin to ADC (will also clear any other analog mode that could be on) | ||||
|  * */ | ||||
| bool adcAttachPin(uint8_t pin); | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| /* | ||||
|  * Sets the sample bits and read resolution | ||||
|  * Default is 12bit (0 - 4095) | ||||
|  * Range is 9 - 12 | ||||
|  * */ | ||||
| void analogSetWidth(uint8_t bits); | ||||
|  | ||||
| /* | ||||
|  * Set pin to use for ADC calibration if the esp is not already calibrated (25, 26 or 27) | ||||
|  * */ | ||||
| void analogSetVRefPin(uint8_t pin); | ||||
|  | ||||
| /* | ||||
|  * Get value for HALL sensor (without LNA) | ||||
|  * connected to pins 36(SVP) and 39(SVN) | ||||
|  * */ | ||||
| int hallRead(); | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* MAIN_ESP32_HAL_ADC_H_ */ | ||||
							
								
								
									
										100
									
								
								cores/esp32/esp32-hal-bt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								cores/esp32/esp32-hal-bt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| // 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; } | ||||
|  | ||||
| #include "esp_bt.h" | ||||
|  | ||||
| #ifdef CONFIG_BTDM_CONTROLLER_MODE_BTDM | ||||
| #define BT_MODE ESP_BT_MODE_BTDM | ||||
| #elif defined(CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY) | ||||
| #define BT_MODE ESP_BT_MODE_CLASSIC_BT | ||||
| #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){ | ||||
|         if (esp_bt_controller_deinit()) { | ||||
| 			log_e("BT deint failed"); | ||||
| 			return false; | ||||
| 		} | ||||
| 		vTaskDelay(1); | ||||
| 		if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {			 | ||||
| 			return false;		 | ||||
| 		} | ||||
|         return true; | ||||
|     } | ||||
|     log_e("BT Stop failed"); | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| #else // CONFIG_BT_ENABLED | ||||
| bool btStarted() | ||||
| { | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool btStart() | ||||
| { | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool btStop() | ||||
| { | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| #endif // CONFIG_BT_ENABLED | ||||
|  | ||||
							
								
								
									
										32
									
								
								cores/esp32/esp32-hal-bt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								cores/esp32/esp32-hal-bt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // 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_ */ | ||||
							
								
								
									
										262
									
								
								cores/esp32/esp32-hal-cpu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								cores/esp32/esp32-hal-cpu.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| // 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 "esp_attr.h" | ||||
| #include "esp_log.h" | ||||
| #include "soc/rtc.h" | ||||
| #include "soc/rtc_cntl_reg.h" | ||||
| #include "soc/apb_ctrl_reg.h" | ||||
| #include "soc/efuse_reg.h" | ||||
| #include "esp32-hal.h" | ||||
| #include "esp32-hal-cpu.h" | ||||
|  | ||||
| #include "esp_system.h" | ||||
| #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #include "freertos/xtensa_timer.h" | ||||
| #include "esp32/rom/rtc.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "freertos/xtensa_timer.h" | ||||
| #include "esp32s2/rom/rtc.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "freertos/xtensa_timer.h" | ||||
| #include "esp32s3/rom/rtc.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #include "esp32c3/rom/rtc.h" | ||||
| #else  | ||||
| #error Target CONFIG_IDF_TARGET is not supported | ||||
| #endif | ||||
| #else // ESP32 Before IDF 4.0 | ||||
| #include "rom/rtc.h" | ||||
| #endif | ||||
|  | ||||
| typedef struct apb_change_cb_s { | ||||
|         struct apb_change_cb_s * prev; | ||||
|         struct apb_change_cb_s * next; | ||||
|         void * arg; | ||||
|         apb_change_cb_t cb; | ||||
| } apb_change_t; | ||||
|  | ||||
|  | ||||
| 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; | ||||
|     if( r != NULL ){ | ||||
|         if(ev_type == APB_BEFORE_CHANGE ) | ||||
|             while(r != NULL){ | ||||
|                 r->cb(r->arg, ev_type, old_apb, new_apb); | ||||
|                 r=r->next; | ||||
|             } | ||||
|         else { // run backwards through chain | ||||
|             while(r->next != NULL) r = r->next; // find first added | ||||
|             while( r != NULL){ | ||||
|                 r->cb(r->arg, ev_type, old_apb, new_apb); | ||||
|                 r=r->prev; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     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->prev = 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; | ||||
|         // look for duplicate callbacks | ||||
|         while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; | ||||
|         if (r) { | ||||
|             log_e("duplicate func=%8p arg=%8p",c->cb,c->arg); | ||||
|             free(c); | ||||
|             xSemaphoreGive(apb_change_lock); | ||||
|             return false; | ||||
|         } | ||||
|         else { | ||||
|             c->next = apb_change_callbacks; | ||||
|             apb_change_callbacks-> prev = c; | ||||
|             apb_change_callbacks = c; | ||||
|         } | ||||
|     } | ||||
|     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; | ||||
|     // look for matching callback | ||||
|     while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; | ||||
|     if ( r == NULL ) { | ||||
|         log_e("not found func=%8p arg=%8p",cb,arg); | ||||
|         xSemaphoreGive(apb_change_lock); | ||||
|         return false; | ||||
|         } | ||||
|     else { | ||||
|         // patch links | ||||
|         if(r->prev) r->prev->next = r->next; | ||||
|         else { // this is first link | ||||
|            apb_change_callbacks = r->next; | ||||
|         } | ||||
|         if(r->next) r->next->prev = r->prev; | ||||
|         free(r); | ||||
|     } | ||||
|     xSemaphoreGive(apb_change_lock); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){ | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
| 	return APB_CLK_FREQ; | ||||
| #else | ||||
|     if(conf->freq_mhz >= 80){ | ||||
|         return 80 * MHZ; | ||||
|     } | ||||
|     return (conf->source_freq_mhz * MHZ) / conf->div; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| 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 CONFIG_IDF_TARGET_ESP32 | ||||
|     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; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|     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; | ||||
|     } | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     //check if cpu supports the frequency | ||||
|     if(cpu_freq_mhz == 240){ | ||||
|         //Check if ESP32 is rated for a CPU frequency of 160MHz only | ||||
|         if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) && | ||||
|             REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_LOW)) { | ||||
|             log_e("Can not switch to 240 MHz! Chip CPU frequency rated for 160MHz."); | ||||
|             cpu_freq_mhz = 160; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|     //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); | ||||
|      | ||||
|     //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 | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 | ||||
|  | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
|  | ||||
| #else | ||||
|     uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb); | ||||
|     _xt_tick_divisor = fcpu / XT_TICK_PER_SEC; | ||||
| #endif | ||||
|     //Call peripheral functions after the APB change | ||||
|     if(apb_change_callbacks){ | ||||
|         triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb); | ||||
|     } | ||||
|     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); | ||||
|     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); | ||||
| } | ||||
							
								
								
									
										48
									
								
								cores/esp32/esp32-hal-cpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								cores/esp32/esp32-hal-cpu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| // 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_ */ | ||||
							
								
								
									
										49
									
								
								cores/esp32/esp32-hal-dac.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								cores/esp32/esp32-hal-dac.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| // 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 "soc/soc_caps.h" | ||||
|  | ||||
| #ifndef SOC_DAC_SUPPORTED            | ||||
| #define NODAC | ||||
| #else | ||||
| #include "soc/dac_channel.h" | ||||
| #include "driver/dac_common.h" | ||||
|  | ||||
| void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value) | ||||
| { | ||||
|     if(pin < DAC_CHANNEL_1_GPIO_NUM || pin > DAC_CHANNEL_2_GPIO_NUM){ | ||||
|         return;//not dac pin | ||||
|     } | ||||
|  | ||||
|     uint8_t channel = pin - DAC_CHANNEL_1_GPIO_NUM; | ||||
|     dac_output_enable(channel); | ||||
|     dac_output_voltage(channel, value); | ||||
|  | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR __dacDisable(uint8_t pin) | ||||
| { | ||||
|     if(pin < DAC_CHANNEL_1_GPIO_NUM || pin > DAC_CHANNEL_2_GPIO_NUM){ | ||||
|         return;//not dac pin | ||||
|     } | ||||
|  | ||||
|     uint8_t channel = pin - DAC_CHANNEL_1_GPIO_NUM; | ||||
|     dac_output_disable(channel); | ||||
| } | ||||
|  | ||||
| extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite"))); | ||||
| extern void dacDisable(uint8_t pin) __attribute__ ((weak, alias("__dacDisable"))); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										37
									
								
								cores/esp32/esp32-hal-dac.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								cores/esp32/esp32-hal-dac.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* | ||||
|  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); | ||||
| void dacDisable(uint8_t pin); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* MAIN_ESP32_HAL_DAC_H_ */ | ||||
							
								
								
									
										233
									
								
								cores/esp32/esp32-hal-gpio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								cores/esp32/esp32-hal-gpio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| // 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 "hal/gpio_hal.h" | ||||
| #include "soc/soc_caps.h" | ||||
|  | ||||
| // It fixes lack of pin definition for S3 and for any future SoC | ||||
| // this function works for ESP32, ESP32-S2 and ESP32-S3 - including the C3, it will return -1 for any pin | ||||
| #if SOC_TOUCH_SENSOR_NUM >  0 | ||||
| #include "soc/touch_sensor_periph.h" | ||||
|  | ||||
| int8_t digitalPinToTouchChannel(uint8_t pin)  | ||||
| { | ||||
|     int8_t ret = -1; | ||||
|     if (pin < SOC_GPIO_PIN_COUNT) { | ||||
|         for (uint8_t i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { | ||||
|             if (touch_sensor_channel_io_map[i] == pin) { | ||||
|                 ret = i; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| #else | ||||
| // No Touch Sensor available | ||||
| int8_t digitalPinToTouchChannel(uint8_t pin)  | ||||
| { | ||||
|     return -1; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef SOC_ADC_SUPPORTED | ||||
| #include "soc/adc_periph.h" | ||||
|  | ||||
| int8_t digitalPinToAnalogChannel(uint8_t pin)  | ||||
| { | ||||
|     uint8_t channel = 0; | ||||
|     if (pin < SOC_GPIO_PIN_COUNT) { | ||||
|         for (uint8_t i = 0; i < SOC_ADC_PERIPH_NUM; i++) { | ||||
|             for (uint8_t j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) { | ||||
|                 if (adc_channel_io_map[i][j] == pin) { | ||||
|                     return channel; | ||||
|                 } | ||||
|                 channel++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int8_t analogChannelToDigitalPin(uint8_t channel)  | ||||
| { | ||||
|     if (channel >= (SOC_ADC_PERIPH_NUM * SOC_ADC_MAX_CHANNEL_NUM)) { | ||||
|         return -1; | ||||
|     } | ||||
|     uint8_t adc_unit = (channel / SOC_ADC_MAX_CHANNEL_NUM); | ||||
|     uint8_t adc_chan = (channel % SOC_ADC_MAX_CHANNEL_NUM); | ||||
|     return adc_channel_io_map[adc_unit][adc_chan]; | ||||
| } | ||||
| #else | ||||
| // No Analog channels availible | ||||
| int8_t analogChannelToDigitalPin(uint8_t channel)  | ||||
| { | ||||
|     return -1; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| typedef void (*voidFuncPtr)(void); | ||||
| typedef void (*voidFuncPtrArg)(void*); | ||||
| typedef struct { | ||||
|     voidFuncPtr fn; | ||||
|     void* arg; | ||||
|     bool functional; | ||||
| } InterruptHandle_t; | ||||
| static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,}; | ||||
|  | ||||
| #include "driver/rtc_io.h" | ||||
|  | ||||
| extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode) | ||||
| { | ||||
| #ifdef RGB_BUILTIN | ||||
|     if (pin == RGB_BUILTIN){ | ||||
|         __pinMode(RGB_BUILTIN-SOC_GPIO_PIN_COUNT, mode); | ||||
|         return; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     if (!GPIO_IS_VALID_GPIO(pin)) { | ||||
|         log_e("Invalid pin selected"); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     gpio_hal_context_t gpiohal; | ||||
|     gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); | ||||
|  | ||||
|     gpio_config_t conf = { | ||||
|         .pin_bit_mask = (1ULL<<pin),                 /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ | ||||
|         .mode = GPIO_MODE_DISABLE,                   /*!< GPIO mode: set input/output mode                     */ | ||||
|         .pull_up_en = GPIO_PULLUP_DISABLE,           /*!< GPIO pull-up                                         */ | ||||
|         .pull_down_en = GPIO_PULLDOWN_DISABLE,       /*!< GPIO pull-down                                       */ | ||||
|         .intr_type = gpiohal.dev->pin[pin].int_type  /*!< GPIO interrupt type - previously set                 */ | ||||
|     }; | ||||
|     if (mode < 0x20) {//io | ||||
|         conf.mode = mode & (INPUT | OUTPUT); | ||||
|         if (mode & OPEN_DRAIN) { | ||||
|             conf.mode |= GPIO_MODE_DEF_OD; | ||||
|         } | ||||
|         if (mode & PULLUP) { | ||||
|             conf.pull_up_en = GPIO_PULLUP_ENABLE; | ||||
|         } | ||||
|         if (mode & PULLDOWN) { | ||||
|             conf.pull_down_en = GPIO_PULLDOWN_ENABLE; | ||||
|         } | ||||
|     } | ||||
|     if(gpio_config(&conf) != ESP_OK) | ||||
|     { | ||||
|         log_e("GPIO config failed"); | ||||
|         return; | ||||
|     } | ||||
| } | ||||
|  | ||||
| extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) | ||||
| { | ||||
|     #ifdef RGB_BUILTIN | ||||
|         if(pin == RGB_BUILTIN){ | ||||
|             //use RMT to set all channels on/off | ||||
|             const uint8_t comm_val = val != 0 ? RGB_BRIGHTNESS : 0; | ||||
|             neopixelWrite(RGB_BUILTIN, comm_val, comm_val, comm_val); | ||||
|             return; | ||||
|         } | ||||
|     #endif | ||||
| 	gpio_set_level((gpio_num_t)pin, val); | ||||
| } | ||||
|  | ||||
| extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) | ||||
| { | ||||
| 	return gpio_get_level((gpio_num_t)pin); | ||||
| } | ||||
|  | ||||
| static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) { | ||||
| 	InterruptHandle_t * isr = (InterruptHandle_t*)arg; | ||||
|     if(isr->fn) { | ||||
|         if(isr->arg){ | ||||
|             ((voidFuncPtrArg)isr->fn)(isr->arg); | ||||
|         } else { | ||||
|         	isr->fn(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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) { | ||||
|     	esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); | ||||
|     	interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); | ||||
|     } | ||||
|     if(!interrupt_initialized) { | ||||
|     	log_e("GPIO ISR Service Failed To Start"); | ||||
|     	return; | ||||
|     } | ||||
|  | ||||
|     // 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; | ||||
|  | ||||
|     gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); | ||||
|     if(intr_type & 0x8){ | ||||
|     	gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); | ||||
|     } | ||||
|     gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); | ||||
|  | ||||
|  | ||||
|     //FIX interrupts on peripherals outputs (eg. LEDC,...) | ||||
|     //Enable input in GPIO register | ||||
|     gpio_hal_context_t gpiohal; | ||||
|     gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); | ||||
|     gpio_hal_input_enable(&gpiohal, pin); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	gpio_isr_handler_remove((gpio_num_t)pin); //remove handle and disable isr for pin | ||||
| 	gpio_wakeup_disable((gpio_num_t)pin); | ||||
|  | ||||
|     if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) | ||||
|     { | ||||
|     	cleanupFunctional(__pinInterruptHandlers[pin].arg); | ||||
|     } | ||||
|     __pinInterruptHandlers[pin].fn = NULL; | ||||
|     __pinInterruptHandlers[pin].arg = NULL; | ||||
|     __pinInterruptHandlers[pin].functional = false; | ||||
|  | ||||
|     gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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"))); | ||||
							
								
								
									
										90
									
								
								cores/esp32/esp32-hal-gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								cores/esp32/esp32-hal-gpio.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| /* | ||||
|  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" | ||||
| #include "soc/soc_caps.h" | ||||
| #include "pins_arduino.h" | ||||
|  | ||||
| #if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) | ||||
| #define NUM_OUPUT_PINS  46 | ||||
| #define PIN_DAC1        17 | ||||
| #define PIN_DAC2        18 | ||||
| #else | ||||
| #define NUM_OUPUT_PINS  34 | ||||
| #define PIN_DAC1        25 | ||||
| #define PIN_DAC2        26 | ||||
| #endif | ||||
|  | ||||
| #define LOW               0x0 | ||||
| #define HIGH              0x1 | ||||
|  | ||||
| //GPIO FUNCTIONS | ||||
| #define INPUT             0x01 | ||||
| // Changed OUTPUT from 0x02 to behave the same as Arduino pinMode(pin,OUTPUT)  | ||||
| // where you can read the state of pin even when it is set as OUTPUT | ||||
| #define OUTPUT            0x03  | ||||
| #define PULLUP            0x04 | ||||
| #define INPUT_PULLUP      0x05 | ||||
| #define PULLDOWN          0x08 | ||||
| #define INPUT_PULLDOWN    0x09 | ||||
| #define OPEN_DRAIN        0x10 | ||||
| #define OUTPUT_OPEN_DRAIN 0x12 | ||||
| #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 | ||||
|  | ||||
|  | ||||
| #define digitalPinIsValid(pin)          GPIO_IS_VALID_GPIO(pin) | ||||
| #define digitalPinCanOutput(pin)        GPIO_IS_VALID_OUTPUT_GPIO(pin) | ||||
|  | ||||
| #define digitalPinToRtcPin(pin)         ((RTC_GPIO_IS_VALID_GPIO(pin))?rtc_io_number_get(pin):-1)  | ||||
| #define digitalPinToDacChannel(pin)     (((pin) == DAC_CHANNEL_1_GPIO_NUM)?0:((pin) == DAC_CHANNEL_2_GPIO_NUM)?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); | ||||
|  | ||||
| int8_t digitalPinToTouchChannel(uint8_t pin); | ||||
| int8_t digitalPinToAnalogChannel(uint8_t pin); | ||||
| int8_t analogChannelToDigitalPin(uint8_t channel); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* MAIN_ESP32_HAL_GPIO_H_ */ | ||||
							
								
								
									
										841
									
								
								cores/esp32/esp32-hal-i2c-slave.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										841
									
								
								cores/esp32/esp32-hal-i2c-slave.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,841 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <inttypes.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
| #include "esp_attr.h" | ||||
| #include "rom/gpio.h" | ||||
| #include "soc/gpio_sig_map.h" | ||||
| #include "hal/gpio_types.h" | ||||
| #include "driver/gpio.h" | ||||
| #include "esp_err.h" | ||||
|  | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "freertos/queue.h" | ||||
| #include "freertos/semphr.h" | ||||
| #include "freertos/ringbuf.h" | ||||
|  | ||||
| #include "esp_intr_alloc.h" | ||||
| #include "driver/periph_ctrl.h" | ||||
| #include "soc/i2c_reg.h" | ||||
| #include "soc/i2c_struct.h" | ||||
| #include "hal/i2c_ll.h" | ||||
| #include "esp32-hal-log.h" | ||||
| #include "esp32-hal-i2c-slave.h" | ||||
|  | ||||
| #define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer | ||||
|  | ||||
| #if SOC_I2C_NUM > 1 | ||||
| #define I2C_SCL_IDX(p)  ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0)) | ||||
| #define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0)) | ||||
| #else | ||||
| #define I2C_SCL_IDX(p)  I2CEXT0_SCL_OUT_IDX | ||||
| #define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX | ||||
| #endif | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     #define I2C_TXFIFO_WM_INT_ENA    I2C_TXFIFO_EMPTY_INT_ENA | ||||
|     #define I2C_RXFIFO_WM_INT_ENA     I2C_RXFIFO_FULL_INT_ENA | ||||
| #endif | ||||
|  | ||||
| enum { | ||||
|     I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX | ||||
| }; | ||||
|  | ||||
| typedef struct i2c_slave_struct_t { | ||||
|     i2c_dev_t * dev; | ||||
|     uint8_t num; | ||||
|     int8_t sda; | ||||
|     int8_t scl; | ||||
|     i2c_slave_request_cb_t request_callback; | ||||
|     i2c_slave_receive_cb_t receive_callback; | ||||
|     void * arg; | ||||
|     intr_handle_t intr_handle; | ||||
|     TaskHandle_t task_handle; | ||||
|     xQueueHandle event_queue; | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     xQueueHandle rx_queue; | ||||
| #else | ||||
|     RingbufHandle_t rx_ring_buf; | ||||
| #endif | ||||
|     xQueueHandle tx_queue; | ||||
|     uint32_t rx_data_count; | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     xSemaphoreHandle lock; | ||||
| #endif | ||||
| } i2c_slave_struct_t; | ||||
|  | ||||
| typedef union { | ||||
|     struct { | ||||
|         uint32_t event : 2; | ||||
|         uint32_t stop : 1; | ||||
|         uint32_t param : 29; | ||||
|     }; | ||||
|     uint32_t val; | ||||
| } i2c_slave_queue_event_t; | ||||
|  | ||||
| static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = { | ||||
|     { &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     , NULL | ||||
| #endif | ||||
|     }, | ||||
| #if SOC_I2C_NUM > 1 | ||||
|     { &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     , NULL | ||||
| #endif | ||||
|     } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #if CONFIG_DISABLE_HAL_LOCKS | ||||
| #define I2C_SLAVE_MUTEX_LOCK() | ||||
| #define I2C_SLAVE_MUTEX_UNLOCK() | ||||
| #else | ||||
| #define I2C_SLAVE_MUTEX_LOCK()    if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);} | ||||
| #define I2C_SLAVE_MUTEX_UNLOCK()  if(i2c->lock){xSemaphoreGive(i2c->lock);} | ||||
| #endif | ||||
|  | ||||
| //-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------ | ||||
| typedef enum { | ||||
|     I2C_STRETCH_CAUSE_MASTER_READ, | ||||
|     I2C_STRETCH_CAUSE_TX_FIFO_EMPTY, | ||||
|     I2C_STRETCH_CAUSE_RX_FIFO_FULL, | ||||
|     I2C_STRETCH_CAUSE_MAX | ||||
| } i2c_stretch_cause_t; | ||||
|  | ||||
| static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw) | ||||
| { | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
|     return hw->sr.stretch_cause; | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
|     return hw->status_reg.stretch_cause; | ||||
| #else | ||||
|     return I2C_STRETCH_CAUSE_MAX; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static inline void i2c_ll_set_stretch(i2c_dev_t *hw, uint16_t time) | ||||
| { | ||||
| #ifndef CONFIG_IDF_TARGET_ESP32 | ||||
|     typeof(hw->scl_stretch_conf) scl_stretch_conf; | ||||
|     scl_stretch_conf.val = 0; | ||||
|     scl_stretch_conf.slave_scl_stretch_en = (time > 0); | ||||
|     scl_stretch_conf.stretch_protect_num = time; | ||||
|     scl_stretch_conf.slave_scl_stretch_clr = 1; | ||||
|     hw->scl_stretch_conf.val = scl_stretch_conf.val; | ||||
|     if(time > 0){ | ||||
|         //enable interrupt | ||||
|         hw->int_ena.val |= I2C_SLAVE_STRETCH_INT_ENA; | ||||
|     } else { | ||||
|         //disable interrupt | ||||
|         hw->int_ena.val &= (~I2C_SLAVE_STRETCH_INT_ENA); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static inline void i2c_ll_stretch_clr(i2c_dev_t *hw) | ||||
| { | ||||
| #ifndef CONFIG_IDF_TARGET_ESP32 | ||||
|     hw->scl_stretch_conf.slave_scl_stretch_clr = 1; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw) | ||||
| { | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
|     return hw->sr.slave_addressed; | ||||
| #else | ||||
|     return hw->status_reg.slave_addressed; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll | ||||
| { | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
|     return hw->sr.slave_rw; | ||||
| #else | ||||
|     return hw->status_reg.slave_rw; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| //-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------ | ||||
| static void i2c_slave_free_resources(i2c_slave_struct_t * i2c); | ||||
| static void i2c_slave_delay_us(uint64_t us); | ||||
| static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode); | ||||
| static bool i2c_slave_check_line_state(int8_t sda, int8_t scl); | ||||
| static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl); | ||||
| static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c); | ||||
| static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed); | ||||
| static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event); | ||||
| static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c); | ||||
| static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len); | ||||
| static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len); | ||||
| static void i2c_slave_isr_handler(void* arg); | ||||
| static void i2c_slave_task(void *pv_args); | ||||
|  | ||||
|  | ||||
| //===================================================================================================================== | ||||
| //-------------------------------------- Public Functions ------------------------------------------------------------- | ||||
| //===================================================================================================================== | ||||
|  | ||||
| esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg){ | ||||
|     if(num >= SOC_I2C_NUM){ | ||||
|         log_e("Invalid port num: %u", num); | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|     i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; | ||||
|     I2C_SLAVE_MUTEX_LOCK(); | ||||
|     i2c->request_callback = request_callback; | ||||
|     i2c->receive_callback = receive_callback; | ||||
|     i2c->arg = arg; | ||||
|     I2C_SLAVE_MUTEX_UNLOCK(); | ||||
|     return ESP_OK; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) { | ||||
|     if(num >= SOC_I2C_NUM){ | ||||
|         log_e("Invalid port num: %u", num); | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|  | ||||
|     if (sda < 0 || scl < 0) { | ||||
|         log_e("invalid pins sda=%d, scl=%d", sda, scl); | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|  | ||||
|     if(!frequency){ | ||||
|         frequency = 100000; | ||||
|     } else if(frequency > 1000000){ | ||||
|         frequency = 1000000; | ||||
|     } | ||||
|  | ||||
|     log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID); | ||||
|  | ||||
|     i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; | ||||
|     esp_err_t ret = ESP_OK; | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(!i2c->lock){ | ||||
|         i2c->lock = xSemaphoreCreateMutex(); | ||||
|         if (i2c->lock == NULL) { | ||||
|             log_e("RX queue create failed"); | ||||
|             return ESP_ERR_NO_MEM; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     I2C_SLAVE_MUTEX_LOCK(); | ||||
|     i2c_slave_free_resources(i2c); | ||||
|  | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t)); | ||||
|     if (i2c->rx_queue == NULL) { | ||||
|         log_e("RX queue create failed"); | ||||
|         ret = ESP_ERR_NO_MEM; | ||||
|         goto fail; | ||||
|     } | ||||
| #else | ||||
|     i2c->rx_ring_buf = xRingbufferCreate(rx_len, RINGBUF_TYPE_BYTEBUF); | ||||
|     if (i2c->rx_ring_buf == NULL) { | ||||
|         log_e("RX RingBuf create failed"); | ||||
|         ret = ESP_ERR_NO_MEM; | ||||
|         goto fail; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     i2c->tx_queue = xQueueCreate(tx_len, sizeof(uint8_t)); | ||||
|     if (i2c->tx_queue == NULL) { | ||||
|         log_e("TX queue create failed"); | ||||
|         ret = ESP_ERR_NO_MEM; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     i2c->event_queue = xQueueCreate(16, sizeof(i2c_slave_queue_event_t)); | ||||
|     if (i2c->event_queue == NULL) { | ||||
|         log_e("Event queue create failed"); | ||||
|         ret = ESP_ERR_NO_MEM; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     xTaskCreate(i2c_slave_task, "i2c_slave_task", 4096, i2c, 20, &i2c->task_handle); | ||||
|     if(i2c->task_handle == NULL){ | ||||
|         log_e("Event thread create failed"); | ||||
|         ret = ESP_ERR_NO_MEM; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     if (frequency == 0) { | ||||
|         frequency = 100000L; | ||||
|     } | ||||
|     frequency = (frequency * 5) / 4; | ||||
|  | ||||
|     if (i2c->num == 0) { | ||||
|         periph_module_enable(PERIPH_I2C0_MODULE); | ||||
| #if SOC_I2C_NUM > 1 | ||||
|     } else { | ||||
|         periph_module_enable(PERIPH_I2C1_MODULE); | ||||
| #endif | ||||
|     } | ||||
|      | ||||
|     i2c_ll_slave_init(i2c->dev); | ||||
|     i2c_ll_set_fifo_mode(i2c->dev, true); | ||||
|     i2c_ll_set_slave_addr(i2c->dev, slaveID, false); | ||||
|     i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT); | ||||
|     i2c_slave_set_frequency(i2c, frequency); | ||||
|  | ||||
|     if (!i2c_slave_check_line_state(sda, scl)) { | ||||
|         log_e("bad pin state"); | ||||
|         ret = ESP_FAIL; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     i2c_slave_attach_gpio(i2c, sda, scl); | ||||
|  | ||||
|     if (i2c_ll_is_bus_busy(i2c->dev)) { | ||||
|         log_w("Bus busy, reinit"); | ||||
|         ret = ESP_FAIL; | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); | ||||
|     i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK); | ||||
|     i2c_ll_set_fifo_mode(i2c->dev, true); | ||||
|  | ||||
|     if (!i2c->intr_handle) { | ||||
|         uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; | ||||
|         if(i2c->num == 0) { | ||||
|             ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); | ||||
| #if SOC_I2C_NUM > 1 | ||||
|         } else { | ||||
|             ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); | ||||
| #endif | ||||
|         } | ||||
|  | ||||
|         if (ret != ESP_OK) { | ||||
|             log_e("install interrupt handler Failed=%d", ret); | ||||
|             goto fail; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     i2c_ll_txfifo_rst(i2c->dev); | ||||
|     i2c_ll_rxfifo_rst(i2c->dev); | ||||
|     i2c_ll_slave_enable_rx_it(i2c->dev); | ||||
|     i2c_ll_set_stretch(i2c->dev, 0x3FF); | ||||
|     i2c_ll_update(i2c->dev); | ||||
|     I2C_SLAVE_MUTEX_UNLOCK(); | ||||
|     return ret; | ||||
|  | ||||
| fail: | ||||
|     i2c_slave_free_resources(i2c); | ||||
|     I2C_SLAVE_MUTEX_UNLOCK(); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cSlaveDeinit(uint8_t num){ | ||||
|     if(num >= SOC_I2C_NUM){ | ||||
|         log_e("Invalid port num: %u", num); | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|  | ||||
|     i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(!i2c->lock){ | ||||
|         log_e("Lock is not initialized! Did you call i2c_slave_init()?"); | ||||
|         return ESP_ERR_NO_MEM; | ||||
|     } | ||||
| #endif | ||||
|     I2C_SLAVE_MUTEX_LOCK(); | ||||
|     i2c_slave_free_resources(i2c); | ||||
|     I2C_SLAVE_MUTEX_UNLOCK(); | ||||
|     return ESP_OK; | ||||
| } | ||||
|  | ||||
| size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { | ||||
|     if(num >= SOC_I2C_NUM){ | ||||
|         log_e("Invalid port num: %u", num); | ||||
|         return 0; | ||||
|     } | ||||
|     size_t to_queue = 0, to_fifo = 0; | ||||
|     i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(!i2c->lock){ | ||||
|         log_e("Lock is not initialized! Did you call i2c_slave_init()?"); | ||||
|         return ESP_ERR_NO_MEM; | ||||
|     } | ||||
| #endif | ||||
|     if(!i2c->tx_queue){ | ||||
|         return 0; | ||||
|     } | ||||
|     I2C_SLAVE_MUTEX_LOCK(); | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     i2c_ll_slave_disable_tx_it(i2c->dev); | ||||
|     if (i2c_ll_get_txfifo_len(i2c->dev) < SOC_I2C_FIFO_LEN) { | ||||
|         i2c_ll_txfifo_rst(i2c->dev); | ||||
|     } | ||||
| #endif | ||||
|     to_fifo = i2c_ll_get_txfifo_len(i2c->dev); | ||||
|     if(len < to_fifo){ | ||||
|         to_fifo = len; | ||||
|     } | ||||
|     i2c_ll_write_txfifo(i2c->dev, (uint8_t*)buf, to_fifo); | ||||
|     buf += to_fifo; | ||||
|     len -= to_fifo; | ||||
|     //reset tx_queue | ||||
|     xQueueReset(i2c->tx_queue); | ||||
|     //write the rest of the bytes to the queue | ||||
|     if(len){ | ||||
|         to_queue = uxQueueSpacesAvailable(i2c->tx_queue); | ||||
|         if(len < to_queue){ | ||||
|             to_queue = len; | ||||
|         } | ||||
|         for (size_t i = 0; i < to_queue; i++) { | ||||
|             if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_RATE_MS) != pdTRUE) { | ||||
|                 xQueueReset(i2c->tx_queue); | ||||
|                 to_queue = 0; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         //no need to enable TX_EMPTY if tx_queue is empty | ||||
|         if(to_queue){ | ||||
|             i2c_ll_slave_enable_tx_it(i2c->dev); | ||||
|         } | ||||
|     } | ||||
|     I2C_SLAVE_MUTEX_UNLOCK(); | ||||
|     return to_queue + to_fifo; | ||||
| } | ||||
|  | ||||
| //===================================================================================================================== | ||||
| //-------------------------------------- Private Functions ------------------------------------------------------------ | ||||
| //===================================================================================================================== | ||||
|  | ||||
| static void i2c_slave_free_resources(i2c_slave_struct_t * i2c){ | ||||
|     i2c_slave_detach_gpio(i2c); | ||||
|     i2c_ll_set_slave_addr(i2c->dev, 0, false); | ||||
|     i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); | ||||
|     i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK); | ||||
|  | ||||
|     if (i2c->intr_handle) { | ||||
|         esp_intr_free(i2c->intr_handle); | ||||
|         i2c->intr_handle = NULL; | ||||
|     } | ||||
|  | ||||
|     if(i2c->task_handle){ | ||||
|         vTaskDelete(i2c->task_handle); | ||||
|         i2c->task_handle = NULL; | ||||
|     } | ||||
|  | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     if (i2c->rx_queue) { | ||||
|         vQueueDelete(i2c->rx_queue); | ||||
|         i2c->rx_queue = NULL; | ||||
|     } | ||||
| #else | ||||
|     if (i2c->rx_ring_buf) { | ||||
|         vRingbufferDelete(i2c->rx_ring_buf); | ||||
|         i2c->rx_ring_buf = NULL; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     if (i2c->tx_queue) { | ||||
|         vQueueDelete(i2c->tx_queue); | ||||
|         i2c->tx_queue = NULL; | ||||
|     } | ||||
|  | ||||
|     if (i2c->event_queue) { | ||||
|         vQueueDelete(i2c->event_queue); | ||||
|         i2c->event_queue = NULL; | ||||
|     } | ||||
|  | ||||
|     i2c->rx_data_count = 0; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed) | ||||
| { | ||||
|     if (i2c == NULL) { | ||||
|         log_e("no control buffer"); | ||||
|         return false; | ||||
|     } | ||||
|     if(clk_speed > 1100000UL){ | ||||
|         clk_speed = 1100000UL; | ||||
|     } | ||||
|  | ||||
|     // Adjust Fifo thresholds based on frequency | ||||
|     uint32_t a = (clk_speed / 50000L) + 2; | ||||
|     log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); | ||||
|  | ||||
|     i2c_clk_cal_t clk_cal; | ||||
| #if SOC_I2C_SUPPORT_APB | ||||
|     i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); | ||||
|     i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_APB);            /*!< I2C source clock from APB, 80M*/ | ||||
| #elif SOC_I2C_SUPPORT_XTAL | ||||
|     i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); | ||||
|     i2c_ll_set_source_clk(i2c->dev, I2C_SCLK_XTAL);           /*!< I2C source clock from XTAL, 40M */ | ||||
| #endif | ||||
|     i2c_ll_set_txfifo_empty_thr(i2c->dev, a); | ||||
|     i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); | ||||
|     i2c_ll_set_bus_timing(i2c->dev, &clk_cal); | ||||
|     i2c_ll_set_filter(i2c->dev, 3); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static void i2c_slave_delay_us(uint64_t us) | ||||
| { | ||||
|     uint64_t m = esp_timer_get_time(); | ||||
|     if (us) { | ||||
|         uint64_t e = (m + us); | ||||
|         if (m > e) { //overflow | ||||
|             while ((uint64_t)esp_timer_get_time() > e); | ||||
|         } | ||||
|         while ((uint64_t)esp_timer_get_time() < e); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) | ||||
| { | ||||
|     gpio_config_t conf = { | ||||
|         .pin_bit_mask = 1LL << pin, | ||||
|         .mode = mode, | ||||
|         .pull_up_en = GPIO_PULLUP_ENABLE, | ||||
|         .pull_down_en = GPIO_PULLDOWN_DISABLE, | ||||
|         .intr_type = GPIO_INTR_DISABLE | ||||
|     }; | ||||
|     gpio_config(&conf); | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) | ||||
| { | ||||
|     if (sda < 0 || scl < 0) { | ||||
|         return false;//return false since there is nothing to do | ||||
|     } | ||||
|     // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles | ||||
|     gpio_set_level(sda, 1); | ||||
|     gpio_set_level(scl, 1); | ||||
|     i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); | ||||
|     i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); | ||||
|     gpio_set_level(scl, 1); | ||||
|  | ||||
|     if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state | ||||
|         log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); | ||||
|         for (uint8_t a=0; a<9; a++) { | ||||
|             i2c_slave_delay_us(5); | ||||
|             if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered | ||||
|                 log_w("Recovered after %d Cycles",a); | ||||
|                 gpio_set_level(sda,0); // start | ||||
|                 i2c_slave_delay_us(5); | ||||
|                 for (uint8_t a=0;a<9; a++) { | ||||
|                     gpio_set_level(scl,1); | ||||
|                     i2c_slave_delay_us(5); | ||||
|                     gpio_set_level(scl,0); | ||||
|                     i2c_slave_delay_us(5); | ||||
|                 } | ||||
|                 gpio_set_level(scl,1); | ||||
|                 i2c_slave_delay_us(5); | ||||
|                 gpio_set_level(sda,1); // stop | ||||
|                 break; | ||||
|             } | ||||
|             gpio_set_level(scl, 0); | ||||
|             i2c_slave_delay_us(5); | ||||
|             gpio_set_level(scl, 1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state | ||||
|         log_e("Bus Invalid State, Can't init sda=%d, scl=%d",gpio_get_level(sda),gpio_get_level(scl)); | ||||
|         return false; // bus is busy | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl) | ||||
| { | ||||
|     if (i2c == NULL) { | ||||
|         log_e("no control block"); | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     if ((sda < 0)||( scl < 0)) { | ||||
|         log_e("bad pins sda=%d, scl=%d",sda,scl); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     i2c->scl = scl; | ||||
|     gpio_set_level(scl, 1); | ||||
|     i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); | ||||
|     gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); | ||||
|     gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); | ||||
|  | ||||
|     i2c->sda = sda; | ||||
|     gpio_set_level(sda, 1); | ||||
|     i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); | ||||
|     gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); | ||||
|     gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c) | ||||
| { | ||||
|     if (i2c == NULL) { | ||||
|         log_e("no control Block"); | ||||
|         return false; | ||||
|     } | ||||
|     if (i2c->scl >= 0) { | ||||
|         gpio_matrix_out(i2c->scl, 0x100, false, false); | ||||
|         gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); | ||||
|         i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); | ||||
|         i2c->scl = -1; // un attached | ||||
|     } | ||||
|     if (i2c->sda >= 0) { | ||||
|         gpio_matrix_out(i2c->sda, 0x100, false, false); | ||||
|         gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); | ||||
|         i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); | ||||
|         i2c->sda = -1; // un attached | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event) | ||||
| { | ||||
|     bool pxHigherPriorityTaskWoken = false; | ||||
|     if(i2c->event_queue) { | ||||
|         if(xQueueSendFromISR(i2c->event_queue, event, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ | ||||
|             //log_e("event_queue_full"); | ||||
|         } | ||||
|     } | ||||
|     return pxHigherPriorityTaskWoken; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c) | ||||
| { | ||||
|     bool pxHigherPriorityTaskWoken = false; | ||||
|     uint32_t d = 0, moveCnt = i2c_ll_get_txfifo_len(i2c->dev); | ||||
|     while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty | ||||
|         if(xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE){ | ||||
|             i2c_ll_write_txfifo(i2c->dev, (uint8_t*)&d, 1); | ||||
|             moveCnt--; | ||||
|         } else { | ||||
|             i2c_ll_slave_disable_tx_it(i2c->dev); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return pxHigherPriorityTaskWoken; | ||||
| } | ||||
|  | ||||
| static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len) | ||||
| { | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     uint32_t d = 0; | ||||
| #else | ||||
|     uint8_t data[SOC_I2C_FIFO_LEN]; | ||||
| #endif | ||||
|     bool pxHigherPriorityTaskWoken = false; | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     while (len > 0) { | ||||
|         i2c_ll_read_rxfifo(i2c->dev, (uint8_t*)&d, 1); | ||||
|         if(xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ | ||||
|             log_e("rx_queue_full"); | ||||
|         } else { | ||||
|             i2c->rx_data_count++; | ||||
|         } | ||||
|         if (--len == 0) { | ||||
|             len = i2c_ll_get_rxfifo_cnt(i2c->dev); | ||||
|         } | ||||
| #else | ||||
|     if(len){ | ||||
|         i2c_ll_read_rxfifo(i2c->dev, data, len); | ||||
|         if(xRingbufferSendFromISR(i2c->rx_ring_buf, (void*) data, len, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ | ||||
|             log_e("rx_ring_buf_full"); | ||||
|         } else { | ||||
|             i2c->rx_data_count += len; | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
|     return pxHigherPriorityTaskWoken; | ||||
| } | ||||
|  | ||||
| static void i2c_slave_isr_handler(void* arg) | ||||
| { | ||||
|     bool pxHigherPriorityTaskWoken = false; | ||||
|     i2c_slave_struct_t * i2c = (i2c_slave_struct_t *) arg; // recover data | ||||
|  | ||||
|     uint32_t activeInt = i2c_ll_get_intsts_mask(i2c->dev); | ||||
|     i2c_ll_clr_intsts_mask(i2c->dev, activeInt); | ||||
|     uint8_t rx_fifo_len = i2c_ll_get_rxfifo_cnt(i2c->dev); | ||||
|     bool slave_rw = i2c_ll_slave_rw(i2c->dev); | ||||
|  | ||||
|     if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full | ||||
|         pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); | ||||
|         i2c_ll_slave_enable_rx_it(i2c->dev);//is this necessary? | ||||
|     } | ||||
|  | ||||
|     if(activeInt & I2C_TRANS_COMPLETE_INT_ENA){ // STOP | ||||
|         if(rx_fifo_len){ //READ RX FIFO | ||||
|             pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); | ||||
|         } | ||||
|         if(i2c->rx_data_count){ //WRITE or RepeatedStart | ||||
|             //SEND RX Event | ||||
|             i2c_slave_queue_event_t event; | ||||
|             event.event = I2C_SLAVE_EVT_RX; | ||||
|             event.stop = !slave_rw; | ||||
|             event.param = i2c->rx_data_count; | ||||
|             pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); | ||||
|             //Zero RX count | ||||
|             i2c->rx_data_count = 0; | ||||
|         } | ||||
|         if(slave_rw){ // READ | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|             if(i2c->dev->status_reg.scl_main_state_last == 6){ | ||||
|                 //SEND TX Event | ||||
|                 i2c_slave_queue_event_t event; | ||||
|                 event.event = I2C_SLAVE_EVT_TX; | ||||
|                 pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); | ||||
|             } | ||||
| #else | ||||
|             //reset TX data | ||||
|             i2c_ll_txfifo_rst(i2c->dev); | ||||
|             uint8_t d; | ||||
|             while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE) ;//flush partial write | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #ifndef CONFIG_IDF_TARGET_ESP32 | ||||
|     if(activeInt & I2C_SLAVE_STRETCH_INT_ENA){ // STRETCH | ||||
|         i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); | ||||
|         if(cause == I2C_STRETCH_CAUSE_MASTER_READ){ | ||||
|             //on C3 RX data dissapears with repeated start, so we need to get it here | ||||
|             if(rx_fifo_len){ | ||||
|                 pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); | ||||
|             } | ||||
|             //SEND TX Event | ||||
|             i2c_slave_queue_event_t event; | ||||
|             event.event = I2C_SLAVE_EVT_TX; | ||||
|             pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); | ||||
|             //will clear after execution | ||||
|         } else if(cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY){ | ||||
|             pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); | ||||
|             i2c_ll_stretch_clr(i2c->dev); | ||||
|         } else if(cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL){ | ||||
|             pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); | ||||
|             i2c_ll_stretch_clr(i2c->dev); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     if(activeInt & I2C_TXFIFO_WM_INT_ENA){ // TX FiFo Empty | ||||
|         pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); | ||||
|     } | ||||
|  | ||||
|     if(pxHigherPriorityTaskWoken){ | ||||
|         portYIELD_FROM_ISR(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len){ | ||||
|     if(!len){ | ||||
|         return 0; | ||||
|     } | ||||
| #if I2C_SLAVE_USE_RX_QUEUE | ||||
|     uint8_t d = 0; | ||||
|     BaseType_t res = pdTRUE; | ||||
|     for(size_t i=0; i<len; i++) { | ||||
|         if(data){ | ||||
|             res = xQueueReceive(i2c->rx_queue, &data[i], 0); | ||||
|         } else { | ||||
|             res = xQueueReceive(i2c->rx_queue, &d, 0); | ||||
|         } | ||||
|         if (res != pdTRUE) { | ||||
|             log_e("Read Queue(%u) Failed", i); | ||||
|             len = i; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return (data)?len:0; | ||||
| #else | ||||
|     size_t  dlen = 0,  | ||||
|             to_read = len,  | ||||
|             so_far = 0,  | ||||
|             available = 0; | ||||
|     uint8_t * rx_data = NULL; | ||||
|  | ||||
|     vRingbufferGetInfo(i2c->rx_ring_buf, NULL, NULL, NULL, NULL, &available); | ||||
|     if(available < to_read){ | ||||
|         log_e("Less available than requested. %u < %u", available, len); | ||||
|         to_read = available; | ||||
|     } | ||||
|  | ||||
|     while(to_read){ | ||||
|         dlen = 0; | ||||
|         rx_data = (uint8_t *)xRingbufferReceiveUpTo(i2c->rx_ring_buf, &dlen, 0, to_read); | ||||
|         if(!rx_data){ | ||||
|             log_e("Receive %u Failed", to_read); | ||||
|             return so_far; | ||||
|         } | ||||
|         if(data){ | ||||
|             memcpy(data+so_far, rx_data, dlen); | ||||
|         } | ||||
|         vRingbufferReturnItem(i2c->rx_ring_buf, rx_data); | ||||
|         so_far+=dlen; | ||||
|         to_read-=dlen; | ||||
|     } | ||||
|     return (data)?so_far:0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void i2c_slave_task(void *pv_args) | ||||
| { | ||||
|     i2c_slave_struct_t * i2c = (i2c_slave_struct_t *)pv_args; | ||||
|     i2c_slave_queue_event_t event; | ||||
|     size_t len = 0; | ||||
|     bool stop = false; | ||||
|     uint8_t * data = NULL; | ||||
|     for(;;){ | ||||
|         if(xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE){ | ||||
|             // Write | ||||
|             if(event.event == I2C_SLAVE_EVT_RX){ | ||||
|                 len = event.param; | ||||
|                 stop = event.stop; | ||||
|                 data = (len > 0)?(uint8_t*)malloc(len):NULL; | ||||
|  | ||||
|                 if(len && data == NULL){ | ||||
|                     log_e("Malloc (%u) Failed", len); | ||||
|                 } | ||||
|                 len = i2c_slave_read_rx(i2c, data, len); | ||||
|                 if(i2c->receive_callback){ | ||||
|                     i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); | ||||
|                 } | ||||
|                 free(data); | ||||
|  | ||||
|             // Read | ||||
|             } else if(event.event == I2C_SLAVE_EVT_TX){ | ||||
|                 if(i2c->request_callback){ | ||||
|                     i2c->request_callback(i2c->num, i2c->arg); | ||||
|                 } | ||||
|                 i2c_ll_stretch_clr(i2c->dev); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     vTaskDelete(NULL); | ||||
| } | ||||
							
								
								
									
										35
									
								
								cores/esp32/esp32-hal-i2c-slave.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								cores/esp32/esp32-hal-i2c-slave.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "stdint.h" | ||||
| #include "stddef.h" | ||||
| #include "esp_err.h" | ||||
|  | ||||
| typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg); | ||||
| typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg); | ||||
| esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg); | ||||
|  | ||||
| esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len); | ||||
| esp_err_t i2cSlaveDeinit(uint8_t num); | ||||
| size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										343
									
								
								cores/esp32/esp32-hal-i2c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								cores/esp32/esp32-hal-i2c.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | ||||
| // 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" | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "freertos/semphr.h" | ||||
| #endif | ||||
| #include "esp_attr.h" | ||||
| #include "esp_system.h" | ||||
| #include "soc/soc_caps.h" | ||||
| #include "soc/i2c_periph.h" | ||||
| #include "hal/i2c_hal.h" | ||||
| #include "hal/i2c_ll.h" | ||||
| #include "driver/i2c.h" | ||||
|  | ||||
| typedef volatile struct { | ||||
|     bool initialized; | ||||
|     uint32_t frequency; | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     SemaphoreHandle_t lock; | ||||
| #endif | ||||
| } i2c_bus_t; | ||||
|  | ||||
| static i2c_bus_t bus[SOC_I2C_NUM]; | ||||
|  | ||||
| bool i2cIsInit(uint8_t i2c_num){ | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return false; | ||||
|     } | ||||
|     return bus[i2c_num].initialized; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency){ | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(bus[i2c_num].lock == NULL){ | ||||
|         bus[i2c_num].lock = xSemaphoreCreateMutex(); | ||||
|         if(bus[i2c_num].lock == NULL){ | ||||
|             log_e("xSemaphoreCreateMutex failed"); | ||||
|             return ESP_ERR_NO_MEM; | ||||
|         } | ||||
|     } | ||||
|     //acquire lock | ||||
|     if(xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
| #endif | ||||
|     if(bus[i2c_num].initialized){ | ||||
|         log_e("bus is already initialized"); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|  | ||||
|     if(!frequency){ | ||||
|         frequency = 100000UL; | ||||
|     } else if(frequency > 1000000UL){ | ||||
|         frequency = 1000000UL; | ||||
|     } | ||||
|     log_i("Initialising I2C Master: sda=%d scl=%d freq=%d", sda, scl, frequency); | ||||
|  | ||||
|     i2c_config_t conf = { }; | ||||
|     conf.mode = I2C_MODE_MASTER; | ||||
|     conf.scl_io_num = (gpio_num_t)scl; | ||||
|     conf.sda_io_num = (gpio_num_t)sda; | ||||
|     conf.scl_pullup_en = GPIO_PULLUP_ENABLE; | ||||
|     conf.sda_pullup_en = GPIO_PULLUP_ENABLE; | ||||
|     conf.master.clk_speed = frequency; | ||||
|     conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL; //Any one clock source that is available for the specified frequency may be choosen | ||||
|  | ||||
|     esp_err_t ret = i2c_param_config((i2c_port_t)i2c_num, &conf); | ||||
|     if (ret != ESP_OK) { | ||||
|         log_e("i2c_param_config failed"); | ||||
|     } else { | ||||
|         ret = i2c_driver_install((i2c_port_t)i2c_num, conf.mode, 0, 0, 0); | ||||
|         if (ret != ESP_OK) { | ||||
|             log_e("i2c_driver_install failed"); | ||||
|         } else { | ||||
|             bus[i2c_num].initialized = true; | ||||
|             bus[i2c_num].frequency = frequency; | ||||
|             //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 | ||||
|             i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT); | ||||
|         } | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cDeinit(uint8_t i2c_num){ | ||||
|     esp_err_t err = ESP_FAIL; | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //acquire lock | ||||
|     if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return err; | ||||
|     } | ||||
| #endif | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|     } else { | ||||
|         err = i2c_driver_delete((i2c_port_t)i2c_num); | ||||
|         if(err == ESP_OK){ | ||||
|             bus[i2c_num].initialized = false; | ||||
|         } | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis){ | ||||
|     esp_err_t ret = ESP_FAIL; | ||||
|     i2c_cmd_handle_t cmd = NULL; | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //acquire lock | ||||
|     if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return ret; | ||||
|     } | ||||
| #endif | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|         goto end; | ||||
|     } | ||||
|      | ||||
|     //short implementation does not support zero size writes (example when scanning) PR in IDF? | ||||
|     //ret =  i2c_master_write_to_device((i2c_port_t)i2c_num, address, buff, size, timeOutMillis / portTICK_RATE_MS); | ||||
|  | ||||
|     ret = ESP_OK; | ||||
|     uint8_t cmd_buff[I2C_LINK_RECOMMENDED_SIZE(1)] = { 0 }; | ||||
|     cmd = i2c_cmd_link_create_static(cmd_buff, I2C_LINK_RECOMMENDED_SIZE(1)); | ||||
|     ret = i2c_master_start(cmd); | ||||
|     if (ret != ESP_OK) { | ||||
|         goto end; | ||||
|     } | ||||
|     ret = i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true); | ||||
|     if (ret != ESP_OK) { | ||||
|         goto end; | ||||
|     } | ||||
|     if(size){ | ||||
|         ret = i2c_master_write(cmd, buff, size, true); | ||||
|         if (ret != ESP_OK) { | ||||
|             goto end; | ||||
|         } | ||||
|     } | ||||
|     ret = i2c_master_stop(cmd); | ||||
|     if (ret != ESP_OK) { | ||||
|         goto end; | ||||
|     } | ||||
|     ret = i2c_master_cmd_begin((i2c_port_t)i2c_num, cmd, timeOutMillis / portTICK_RATE_MS); | ||||
|  | ||||
| end: | ||||
|     if(cmd != NULL){ | ||||
|         i2c_cmd_link_delete_static(cmd); | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount){ | ||||
|     esp_err_t ret = ESP_FAIL; | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //acquire lock | ||||
|     if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return ret; | ||||
|     } | ||||
| #endif | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|     } else { | ||||
|         ret = i2c_master_read_from_device((i2c_port_t)i2c_num, address, buff, size, timeOutMillis / portTICK_RATE_MS); | ||||
|         if(ret == ESP_OK){ | ||||
|             *readCount = size; | ||||
|         } else { | ||||
|             *readCount = 0; | ||||
|         } | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount){ | ||||
|     esp_err_t ret = ESP_FAIL; | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //acquire lock | ||||
|     if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return ret; | ||||
|     } | ||||
| #endif | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|     } else { | ||||
|         ret = i2c_master_write_read_device((i2c_port_t)i2c_num, address, wbuff, wsize, rbuff, rsize, timeOutMillis / portTICK_RATE_MS); | ||||
|         if(ret == ESP_OK){ | ||||
|             *readCount = rsize; | ||||
|         } else { | ||||
|             *readCount = 0; | ||||
|         } | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency){ | ||||
|     esp_err_t ret = ESP_FAIL; | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //acquire lock | ||||
|     if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ | ||||
|         log_e("could not acquire lock"); | ||||
|         return ret; | ||||
|     } | ||||
| #endif | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|         goto end; | ||||
|     } | ||||
|     if(bus[i2c_num].frequency == frequency){ | ||||
|         ret = ESP_OK; | ||||
|         goto end; | ||||
|     } | ||||
|     if(!frequency){ | ||||
|         frequency = 100000UL; | ||||
|     } else if(frequency > 1000000UL){ | ||||
|         frequency = 1000000UL; | ||||
|     } | ||||
|     // Freq limitation when using different clock sources | ||||
|     #define I2C_CLK_LIMIT_REF_TICK            (1 * 1000 * 1000 / 20)    /*!< Limited by REF_TICK, no more than REF_TICK/20*/ | ||||
|     #define I2C_CLK_LIMIT_APB                 (80 * 1000 * 1000 / 20)   /*!< Limited by APB, no more than APB/20*/ | ||||
|     #define I2C_CLK_LIMIT_RTC                 (20 * 1000 * 1000 / 20)   /*!< Limited by RTC, no more than RTC/20*/ | ||||
|     #define I2C_CLK_LIMIT_XTAL                (40 * 1000 * 1000 / 20)   /*!< Limited by RTC, no more than XTAL/20*/ | ||||
|  | ||||
|     typedef struct { | ||||
|         uint8_t character;          /*!< I2C source clock characteristic */ | ||||
|         uint32_t clk_freq;          /*!< I2C source clock frequency */ | ||||
|     } i2c_clk_alloc_t; | ||||
|  | ||||
|     // i2c clock characteristic, The order is the same as i2c_sclk_t. | ||||
|     static i2c_clk_alloc_t i2c_clk_alloc[I2C_SCLK_MAX] = { | ||||
|         {0, 0}, | ||||
|     #if SOC_I2C_SUPPORT_APB | ||||
|         {0, I2C_CLK_LIMIT_APB},                                                                /*!< I2C APB clock characteristic*/ | ||||
|     #endif | ||||
|     #if SOC_I2C_SUPPORT_XTAL | ||||
|         {0, I2C_CLK_LIMIT_XTAL},                                                               /*!< I2C XTAL characteristic*/ | ||||
|     #endif | ||||
|     #if SOC_I2C_SUPPORT_RTC | ||||
|         {I2C_SCLK_SRC_FLAG_LIGHT_SLEEP | I2C_SCLK_SRC_FLAG_AWARE_DFS, I2C_CLK_LIMIT_RTC},      /*!< I2C 20M RTC characteristic*/ | ||||
|     #endif | ||||
|     #if SOC_I2C_SUPPORT_REF_TICK | ||||
|         {I2C_SCLK_SRC_FLAG_AWARE_DFS, I2C_CLK_LIMIT_REF_TICK},                                 /*!< I2C REF_TICK characteristic*/ | ||||
|     #endif | ||||
|     }; | ||||
|  | ||||
|     i2c_sclk_t src_clk = I2C_SCLK_DEFAULT; | ||||
|     ret = ESP_OK; | ||||
|     for (i2c_sclk_t clk = I2C_SCLK_DEFAULT + 1; clk < I2C_SCLK_MAX; clk++) { | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 | ||||
|         if (clk == I2C_SCLK_RTC) { // RTC clock for s3 is unaccessable now. | ||||
|             continue; | ||||
|         } | ||||
| #endif | ||||
|         if (frequency <= i2c_clk_alloc[clk].clk_freq) { | ||||
|             src_clk = clk; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(src_clk == I2C_SCLK_MAX){ | ||||
|         log_e("clock source could not be selected"); | ||||
|         ret = ESP_FAIL; | ||||
|     } else { | ||||
|         i2c_hal_context_t hal; | ||||
|         hal.dev = I2C_LL_GET_HW(i2c_num); | ||||
|         i2c_hal_set_bus_timing(&(hal), frequency, src_clk); | ||||
|         bus[i2c_num].frequency = frequency; | ||||
|         //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 | ||||
|         i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT); | ||||
|     } | ||||
|  | ||||
| end: | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     //release lock | ||||
|     xSemaphoreGive(bus[i2c_num].lock); | ||||
| #endif | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency){ | ||||
|     if(i2c_num >= SOC_I2C_NUM){ | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|     if(!bus[i2c_num].initialized){ | ||||
|         log_e("bus is not initialized"); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     *frequency = bus[i2c_num].frequency; | ||||
|     return ESP_OK; | ||||
| } | ||||
							
								
								
									
										41
									
								
								cores/esp32/esp32-hal-i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								cores/esp32/esp32-hal-i2c.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // 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 | ||||
| // modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API | ||||
|  | ||||
| #ifndef _ESP32_HAL_I2C_H_ | ||||
| #define _ESP32_HAL_I2C_H_ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <esp_err.h> | ||||
|  | ||||
| esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed); | ||||
| esp_err_t i2cDeinit(uint8_t i2c_num); | ||||
| esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency); | ||||
| esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency); | ||||
| esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis); | ||||
| esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount); | ||||
| esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount); | ||||
| bool i2cIsInit(uint8_t i2c_num); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* _ESP32_HAL_I2C_H_ */ | ||||
							
								
								
									
										232
									
								
								cores/esp32/esp32-hal-ledc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								cores/esp32/esp32-hal-ledc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,232 @@ | ||||
| // 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 "soc/soc_caps.h" | ||||
| #include "driver/ledc.h" | ||||
|  | ||||
| #ifdef SOC_LEDC_SUPPORT_HS_MODE | ||||
| #define LEDC_CHANNELS           (SOC_LEDC_CHANNEL_NUM<<1) | ||||
| #else | ||||
| #define LEDC_CHANNELS           (SOC_LEDC_CHANNEL_NUM) | ||||
| #endif | ||||
|  | ||||
| //Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz | ||||
| //Need to be fixed in ESP-IDF | ||||
| #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK | ||||
| #define LEDC_DEFAULT_CLK        LEDC_USE_XTAL_CLK | ||||
| #else | ||||
| #define LEDC_DEFAULT_CLK        LEDC_AUTO_CLK | ||||
| #endif | ||||
|  | ||||
| #define LEDC_MAX_BIT_WIDTH      SOC_LEDC_TIMER_BIT_WIDE_NUM | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
| */ | ||||
|  | ||||
| uint8_t channels_resolution[LEDC_CHANNELS] = {0}; | ||||
|  | ||||
| uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){ | ||||
|         log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     uint8_t group=(chan/8), timer=((chan/2)%4); | ||||
|  | ||||
|     ledc_timer_config_t ledc_timer = { | ||||
|         .speed_mode       = group, | ||||
|         .timer_num        = timer, | ||||
|         .duty_resolution  = bit_num, | ||||
|         .freq_hz          = freq, | ||||
|         .clk_cfg          = LEDC_DEFAULT_CLK | ||||
|     }; | ||||
|     if(ledc_timer_config(&ledc_timer) != ESP_OK) | ||||
|     { | ||||
|         log_e("ledc setup failed!"); | ||||
|         return 0; | ||||
|     } | ||||
|     channels_resolution[chan] = bit_num; | ||||
|     return ledc_get_freq(group,timer); | ||||
| } | ||||
|  | ||||
| void ledcWrite(uint8_t chan, uint32_t duty) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS){ | ||||
|         return; | ||||
|     } | ||||
|     uint8_t group=(chan/8), channel=(chan%8); | ||||
|  | ||||
|     //Fixing if all bits in resolution is set = LEDC FULL ON | ||||
|     uint32_t max_duty = (1 << channels_resolution[chan]) - 1; | ||||
|  | ||||
|     if((duty == max_duty) && (max_duty != 1)){ | ||||
|         duty = max_duty + 1; | ||||
|     } | ||||
|  | ||||
|     ledc_set_duty(group, channel, duty); | ||||
|     ledc_update_duty(group, channel); | ||||
| } | ||||
|  | ||||
| uint32_t ledcRead(uint8_t chan) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS){ | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t group=(chan/8), channel=(chan%8); | ||||
|     return ledc_get_duty(group,channel); | ||||
| } | ||||
|  | ||||
| uint32_t ledcReadFreq(uint8_t chan) | ||||
| { | ||||
|     if(!ledcRead(chan)){ | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t group=(chan/8), timer=((chan/2)%4); | ||||
|     return ledc_get_freq(group,timer); | ||||
| } | ||||
|  | ||||
| uint32_t ledcWriteTone(uint8_t chan, uint32_t freq) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS){ | ||||
|         return 0; | ||||
|     } | ||||
|     if(!freq){ | ||||
|         ledcWrite(chan, 0); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     uint8_t group=(chan/8), timer=((chan/2)%4); | ||||
|  | ||||
|     ledc_timer_config_t ledc_timer = { | ||||
|         .speed_mode       = group, | ||||
|         .timer_num        = timer, | ||||
|         .duty_resolution  = 10, | ||||
|         .freq_hz          = freq,  | ||||
|         .clk_cfg          = LEDC_DEFAULT_CLK | ||||
|     }; | ||||
|  | ||||
|     if(ledc_timer_config(&ledc_timer) != ESP_OK) | ||||
|     { | ||||
|         log_e("ledcSetup failed!"); | ||||
|         return 0; | ||||
|     } | ||||
|     channels_resolution[chan] = 10; | ||||
|  | ||||
|     uint32_t res_freq = ledc_get_freq(group,timer); | ||||
|     ledcWrite(chan, 0x1FF); | ||||
|     return res_freq; | ||||
| } | ||||
|  | ||||
| uint32_t 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; | ||||
|     } | ||||
|     uint32_t noteFreq =  (uint32_t)noteFrequencyBase[note] / (uint32_t)(1 << (8-octave)); | ||||
|     return ledcWriteTone(chan, noteFreq); | ||||
| } | ||||
|  | ||||
| void ledcAttachPin(uint8_t pin, uint8_t chan) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS){ | ||||
|         return; | ||||
|     } | ||||
|     uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4); | ||||
|      | ||||
|     ledc_channel_config_t ledc_channel = { | ||||
|         .speed_mode     = group, | ||||
|         .channel        = channel, | ||||
|         .timer_sel      = timer, | ||||
|         .intr_type      = LEDC_INTR_DISABLE, | ||||
|         .gpio_num       = pin, | ||||
|         .duty           = 0, | ||||
|         .hpoint         = 0 | ||||
|     }; | ||||
|     ledc_channel_config(&ledc_channel); | ||||
| } | ||||
|  | ||||
| void ledcDetachPin(uint8_t pin) | ||||
| { | ||||
|     pinMatrixOutDetach(pin, false, false); | ||||
| } | ||||
|  | ||||
| uint32_t ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num) | ||||
| { | ||||
|     if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){ | ||||
|         log_e("LEDC channel not available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t group=(chan/8), timer=((chan/2)%4); | ||||
|  | ||||
|     ledc_timer_config_t ledc_timer = { | ||||
|         .speed_mode       = group, | ||||
|         .timer_num        = timer, | ||||
|         .duty_resolution  = bit_num, | ||||
|         .freq_hz          = freq,  | ||||
|         .clk_cfg          = LEDC_DEFAULT_CLK | ||||
|     }; | ||||
|  | ||||
|     if(ledc_timer_config(&ledc_timer) != ESP_OK) | ||||
|     { | ||||
|         log_e("ledcChangeFrequency failed!"); | ||||
|         return 0; | ||||
|     } | ||||
|     channels_resolution[chan] = bit_num; | ||||
|     return ledc_get_freq(group,timer); | ||||
| } | ||||
|  | ||||
| static int8_t pin_to_channel[SOC_GPIO_PIN_COUNT] = { 0 }; | ||||
| static int cnt_channel = LEDC_CHANNELS; | ||||
| void analogWrite(uint8_t pin, int value) { | ||||
|   // Use ledc hardware for internal pins | ||||
|   if (pin < SOC_GPIO_PIN_COUNT) { | ||||
|     if (pin_to_channel[pin] == 0) { | ||||
|       if (!cnt_channel) { | ||||
|           log_e("No more analogWrite channels available! You can have maximum %u", LEDC_CHANNELS); | ||||
|           return; | ||||
|       } | ||||
|       pin_to_channel[pin] = cnt_channel--; | ||||
|       ledcAttachPin(pin, cnt_channel); | ||||
|       ledcSetup(cnt_channel, 1000, 8); | ||||
|     } | ||||
|     ledcWrite(pin_to_channel[pin] - 1, value); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int8_t analogGetChannel(uint8_t pin) { | ||||
|     return pin_to_channel[pin] - 1; | ||||
| } | ||||
							
								
								
									
										45
									
								
								cores/esp32/esp32-hal-ledc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								cores/esp32/esp32-hal-ledc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| // 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 | ||||
| uint32_t    ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits); | ||||
| void        ledcWrite(uint8_t channel, uint32_t duty); | ||||
| uint32_t    ledcWriteTone(uint8_t channel, uint32_t freq); | ||||
| uint32_t    ledcWriteNote(uint8_t channel, note_t note, uint8_t octave); | ||||
| uint32_t    ledcRead(uint8_t channel); | ||||
| uint32_t    ledcReadFreq(uint8_t channel); | ||||
| void        ledcAttachPin(uint8_t pin, uint8_t channel); | ||||
| void        ledcDetachPin(uint8_t pin); | ||||
| uint32_t    ledcChangeFrequency(uint8_t channel, uint32_t freq, uint8_t resolution_bits); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* _ESP32_HAL_LEDC_H_ */ | ||||
							
								
								
									
										226
									
								
								cores/esp32/esp32-hal-log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								cores/esp32/esp32-hal-log.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| // 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" | ||||
| #include "esp_timer.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 | ||||
| #ifdef USE_ESP_IDF_LOG | ||||
| #ifndef LOG_LOCAL_LEVEL | ||||
| #define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL | ||||
| #endif | ||||
| #endif | ||||
| #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) | ||||
| #define ARDUHAL_LOG_COLOR_PRINT(letter) log_printf(ARDUHAL_LOG_COLOR_ ## letter) | ||||
| #define ARDUHAL_LOG_COLOR_PRINT_END log_printf(ARDUHAL_LOG_RESET_COLOR) | ||||
| #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 | ||||
| #define ARDUHAL_LOG_COLOR_PRINT(letter) | ||||
| #define ARDUHAL_LOG_COLOR_PRINT_END | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| const char * pathToFileName(const char * path); | ||||
| int log_printf(const char *fmt, ...); | ||||
| void log_print_buf(const uint8_t *b, size_t len); | ||||
|  | ||||
| #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 "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__ | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_v(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_VERBOSE);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_v(format, ...)  do {} while(0) | ||||
| #define isr_log_v(format, ...)  do {} while(0) | ||||
| #define log_buf_v(b,l)  do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_d(b,l) do{ARDUHAL_LOG_COLOR_PRINT(D);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_d(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_DEBUG);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_d(format, ...)  do {} while(0) | ||||
| #define isr_log_d(format, ...) do {} while(0) | ||||
| #define log_buf_d(b,l) do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_i(b,l) do{ARDUHAL_LOG_COLOR_PRINT(I);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_i(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_INFO);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_i(format, ...) do {} while(0) | ||||
| #define isr_log_i(format, ...) do {} while(0) | ||||
| #define log_buf_i(b,l) do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_w(b,l) do{ARDUHAL_LOG_COLOR_PRINT(W);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_w(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_WARN);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_w(format, ...) do {} while(0) | ||||
| #define isr_log_w(format, ...) do {} while(0) | ||||
| #define log_buf_w(b,l) do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_e(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_e(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_e(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_e(format, ...) do {} while(0) | ||||
| #define isr_log_e(format, ...) do {} while(0) | ||||
| #define log_buf_e(b,l) do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE | ||||
| #ifndef USE_ESP_IDF_LOG | ||||
| #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__) | ||||
| #define log_buf_n(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) | ||||
| #else | ||||
| #define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) | ||||
| #define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) | ||||
| #define log_buf_n(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0) | ||||
| #endif | ||||
| #else | ||||
| #define log_n(format, ...) do {} while(0) | ||||
| #define isr_log_n(format, ...) do {} while(0) | ||||
| #define log_buf_n(b,l) do {} while(0) | ||||
| #endif | ||||
|  | ||||
| #include "esp_log.h" | ||||
|  | ||||
| #ifdef USE_ESP_IDF_LOG | ||||
| //#ifndef TAG | ||||
| //#define TAG "ARDUINO" | ||||
| //#endif | ||||
| //#define log_n(format, ...) myLog(ESP_LOG_NONE, format, ##__VA_ARGS__) | ||||
| #else | ||||
| #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, format, ...)  log_e("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_LOGW(tag, format, ...)  log_w("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_LOGI(tag, format, ...)  log_i("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_LOGD(tag, format, ...)  log_d("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_LOGV(tag, format, ...)  log_v("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_EARLY_LOGE(tag, format, ...)  isr_log_e("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_EARLY_LOGW(tag, format, ...)  isr_log_w("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_EARLY_LOGI(tag, format, ...)  isr_log_i("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_EARLY_LOGD(tag, format, ...)  isr_log_d("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #define ESP_EARLY_LOGV(tag, format, ...)  isr_log_v("[%s] " format, tag, ##__VA_ARGS__) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* __ESP_LOGGING_H__ */ | ||||
							
								
								
									
										63
									
								
								cores/esp32/esp32-hal-matrix.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								cores/esp32/esp32-hal-matrix.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| // 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 "esp_system.h" | ||||
| #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #include "esp32/rom/gpio.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "esp32s2/rom/gpio.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "esp32s3/rom/gpio.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #include "esp32c3/rom/gpio.h" | ||||
| #else  | ||||
| #error Target CONFIG_IDF_TARGET is not supported | ||||
| #endif | ||||
| #else // ESP32 Before IDF 4.0 | ||||
| #include "rom/gpio.h" | ||||
| #endif | ||||
|  | ||||
| #define MATRIX_DETACH_OUT_SIG 0x100 | ||||
| #define MATRIX_DETACH_IN_LOW_PIN 0x30 | ||||
| #define MATRIX_DETACH_IN_LOW_HIGH 0x38 | ||||
|  | ||||
| void ARDUINO_ISR_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable) | ||||
| { | ||||
|     gpio_matrix_out(pin, function, invertOut, invertEnable); | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable) | ||||
| { | ||||
|     gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable); | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted) | ||||
| { | ||||
|     gpio_matrix_in(pin, signal, inverted); | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_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 ARDUINO_ISR_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){ | ||||
|   intr_matrix_set(PRO_CPU_NUM, source, inum); | ||||
| } | ||||
| */ | ||||
|  | ||||
							
								
								
									
										35
									
								
								cores/esp32/esp32-hal-matrix.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								cores/esp32/esp32-hal-matrix.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // 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_ */ | ||||
							
								
								
									
										285
									
								
								cores/esp32/esp32-hal-misc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								cores/esp32/esp32-hal-misc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,285 @@ | ||||
| // 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 "esp_task_wdt.h" | ||||
| #include "esp32-hal.h" | ||||
|  | ||||
| #include "esp_system.h" | ||||
| #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #include "esp32/rom/rtc.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "esp32s2/rom/rtc.h" | ||||
| #include "driver/temp_sensor.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "esp32s3/rom/rtc.h" | ||||
| #include "driver/temp_sensor.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32C3 | ||||
| #include "esp32c3/rom/rtc.h" | ||||
| #include "driver/temp_sensor.h" | ||||
| #else  | ||||
| #error Target CONFIG_IDF_TARGET is not supported | ||||
| #endif | ||||
| #else // ESP32 Before IDF 4.0 | ||||
| #include "rom/rtc.h" | ||||
| #endif | ||||
|  | ||||
| //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 | ||||
| #ifdef CONFIG_IDF_TARGET_ESP32 | ||||
| uint8_t temprature_sens_read(); | ||||
|  | ||||
| float temperatureRead() | ||||
| { | ||||
|     return (temprature_sens_read() - 32) / 1.8; | ||||
| } | ||||
| #else | ||||
| float temperatureRead() | ||||
| { | ||||
|     float result = NAN; | ||||
|     temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT(); | ||||
|     temp_sensor_set_config(tsens); | ||||
|     temp_sensor_start(); | ||||
|     temp_sensor_read_celsius(&result);  | ||||
|     temp_sensor_stop(); | ||||
|     return result; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void __yield() | ||||
| { | ||||
|     vPortYield(); | ||||
| } | ||||
|  | ||||
| void yield() __attribute__ ((weak, alias("__yield"))); | ||||
|  | ||||
| #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 ARDUINO_ISR_ATTR micros() | ||||
| { | ||||
|     return (unsigned long) (esp_timer_get_time()); | ||||
| } | ||||
|  | ||||
| unsigned long ARDUINO_ISR_ATTR millis() | ||||
| { | ||||
|     return (unsigned long) (esp_timer_get_time() / 1000ULL); | ||||
| } | ||||
|  | ||||
| void delay(uint32_t ms) | ||||
| { | ||||
|     vTaskDelay(ms / portTICK_PERIOD_MS); | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us) | ||||
| { | ||||
|     uint64_t m = (uint64_t)esp_timer_get_time(); | ||||
|     if(us){ | ||||
|         uint64_t e = (m + us); | ||||
|         if(m > e){ //overflow | ||||
|             while((uint64_t)esp_timer_get_time() > e){ | ||||
|                 NOP(); | ||||
|             } | ||||
|         } | ||||
|         while((uint64_t)esp_timer_get_time() < e){ | ||||
|             NOP(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void initVariant() __attribute__((weak)); | ||||
| void initVariant() {} | ||||
|  | ||||
| void init() __attribute__((weak)); | ||||
| void init() {} | ||||
|  | ||||
| #ifdef CONFIG_APP_ROLLBACK_ENABLE | ||||
| bool verifyOta() __attribute__((weak)); | ||||
| bool verifyOta() { return true; } | ||||
|  | ||||
| bool verifyRollbackLater() __attribute__((weak)); | ||||
| bool verifyRollbackLater() { return false; } | ||||
| #endif | ||||
|  | ||||
| #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 | ||||
|     if(!verifyRollbackLater()){ | ||||
|         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 || CONFIG_SPIRAM | ||||
|     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 || err == ESP_ERR_NVS_NEW_VERSION_FOUND){ | ||||
|         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!"); | ||||
|             } | ||||
|         } else { | ||||
|             log_e("Could not find 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 * ARDUINO_ISR_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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										148
									
								
								cores/esp32/esp32-hal-psram.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								cores/esp32/esp32-hal-psram.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| // 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" | ||||
|  | ||||
| #if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM | ||||
| #include "soc/efuse_reg.h" | ||||
| #include "esp_heap_caps.h" | ||||
|  | ||||
| #include "esp_system.h" | ||||
| #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #include "esp32/spiram.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "esp32s2/spiram.h" | ||||
| #include "esp32s2/rom/cache.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "esp32s3/spiram.h" | ||||
| #include "esp32s3/rom/cache.h" | ||||
| #else  | ||||
| #error Target CONFIG_IDF_TARGET is not supported | ||||
| #endif | ||||
| #else // ESP32 Before IDF 4.0 | ||||
| #include "esp_spiram.h" | ||||
| #endif | ||||
|  | ||||
| static volatile bool spiramDetected = false; | ||||
| static volatile bool spiramFailed = false; | ||||
|  | ||||
| //allows user to bypass SPI RAM test routine | ||||
| __attribute__((weak)) bool testSPIRAM(void)  | ||||
| {  | ||||
|      return esp_spiram_test();  | ||||
| } | ||||
|  | ||||
|  | ||||
| bool psramInit(){ | ||||
|     if (spiramDetected) { | ||||
|         return true; | ||||
|     } | ||||
| #ifndef CONFIG_SPIRAM_BOOT_INIT | ||||
|     if (spiramFailed) { | ||||
|         return false; | ||||
|     } | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|     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; | ||||
|     } | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
|     extern void esp_config_data_cache_mode(void); | ||||
|     esp_config_data_cache_mode(); | ||||
|     Cache_Enable_DCache(0); | ||||
| #endif | ||||
|     if (esp_spiram_init() != ESP_OK) { | ||||
|         spiramFailed = true; | ||||
|         log_w("PSRAM init failed!"); | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
|         if (pkg_ver != EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { | ||||
|             pinMatrixOutDetach(16, false, false); | ||||
|             pinMatrixOutDetach(17, false, false); | ||||
|         } | ||||
| #endif | ||||
|         return false; | ||||
|     } | ||||
|     esp_spiram_init_cache(); | ||||
|     //testSPIRAM() allows user to bypass SPI RAM test routine | ||||
|     if (!testSPIRAM()) { | ||||
|         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; | ||||
|     } | ||||
| #if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM | ||||
|     heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); | ||||
| #endif | ||||
| #endif /* CONFIG_SPIRAM_BOOT_INIT */ | ||||
|     log_i("PSRAM enabled"); | ||||
|     spiramDetected = true; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool ARDUINO_ISR_ATTR psramFound(){ | ||||
|     return spiramDetected; | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR *ps_malloc(size_t size){ | ||||
|     if(!spiramDetected){ | ||||
|         return NULL; | ||||
|     } | ||||
|     return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_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 ARDUINO_ISR_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 ARDUINO_ISR_ATTR psramFound(){ | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR *ps_malloc(size_t size){ | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){ | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){ | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										44
									
								
								cores/esp32/esp32-hal-psram.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								cores/esp32/esp32-hal-psram.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // 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 | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
|  | ||||
| #ifndef BOARD_HAS_PSRAM | ||||
| #ifdef CONFIG_SPIRAM_SUPPORT | ||||
| #undef CONFIG_SPIRAM_SUPPORT | ||||
| #endif | ||||
| #ifdef CONFIG_SPIRAM | ||||
| #undef CONFIG_SPIRAM | ||||
| #endif | ||||
| #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_ */ | ||||
							
								
								
									
										47
									
								
								cores/esp32/esp32-hal-rgb-led.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								cores/esp32/esp32-hal-rgb-led.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #include "esp32-hal-rgb-led.h" | ||||
|  | ||||
|  | ||||
| void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val){ | ||||
|   rmt_data_t led_data[24]; | ||||
|   static rmt_obj_t* rmt_send = NULL; | ||||
|   static bool initialized = false; | ||||
|  | ||||
|   uint8_t _pin = pin; | ||||
| #ifdef RGB_BUILTIN | ||||
|   if(pin == RGB_BUILTIN){ | ||||
|     _pin = RGB_BUILTIN-SOC_GPIO_PIN_COUNT; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   if(!initialized){ | ||||
|     if((rmt_send = rmtInit(_pin, RMT_TX_MODE, RMT_MEM_64)) == NULL){ | ||||
|         log_e("RGB LED driver initialization failed!"); | ||||
|         rmt_send = NULL; | ||||
|         return; | ||||
|     } | ||||
|     rmtSetTick(rmt_send, 100); | ||||
|     initialized = true; | ||||
|   } | ||||
|  | ||||
|   int color[] = {green_val, red_val, blue_val};  // Color coding is in order GREEN, RED, BLUE | ||||
|   int i = 0; | ||||
|   for(int col=0; col<3; col++ ){ | ||||
|     for(int bit=0; bit<8; bit++){ | ||||
|       if((color[col] & (1<<(7-bit)))){ | ||||
|         // HIGH bit | ||||
|         led_data[i].level0 = 1; // T1H | ||||
|         led_data[i].duration0 = 8; // 0.8us | ||||
|         led_data[i].level1 = 0; // T1L | ||||
|         led_data[i].duration1 = 4; // 0.4us | ||||
|       }else{ | ||||
|         // LOW bit | ||||
|         led_data[i].level0 = 1; // T0H | ||||
|         led_data[i].duration0 = 4; // 0.4us | ||||
|         led_data[i].level1 = 0; // T0L | ||||
|         led_data[i].duration1 = 8; // 0.8us | ||||
|       } | ||||
|       i++; | ||||
|     } | ||||
|   } | ||||
|   rmtWrite(rmt_send, led_data, 24); | ||||
| } | ||||
							
								
								
									
										20
									
								
								cores/esp32/esp32-hal-rgb-led.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								cores/esp32/esp32-hal-rgb-led.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #ifndef MAIN_ESP32_HAL_RGB_LED_H_ | ||||
| #define MAIN_ESP32_HAL_RGB_LED_H_ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "esp32-hal.h" | ||||
|  | ||||
| #ifndef RGB_BRIGHTNESS | ||||
|   #define RGB_BRIGHTNESS 64 | ||||
| #endif | ||||
|  | ||||
| void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* MAIN_ESP32_HAL_RGB_LED_H_ */ | ||||
							
								
								
									
										634
									
								
								cores/esp32/esp32-hal-rmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										634
									
								
								cores/esp32/esp32-hal-rmt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,634 @@ | ||||
| // 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 "esp32-hal.h" | ||||
| #include "driver/rmt.h" | ||||
|  | ||||
| /** | ||||
|  * Internal macros | ||||
|  */ | ||||
|  | ||||
| #define MAX_CHANNELS                        (SOC_RMT_GROUPS * SOC_RMT_CHANNELS_PER_GROUP) | ||||
|  | ||||
| #define RMT_TX_CH_START       (0) | ||||
| #define RMT_TX_CH_END         (SOC_RMT_TX_CANDIDATES_PER_GROUP - 1) | ||||
| #define RMT_RX_CH_START       (SOC_RMT_CHANNELS_PER_GROUP - SOC_RMT_TX_CANDIDATES_PER_GROUP) | ||||
| #define RMT_RX_CH_END         (SOC_RMT_CHANNELS_PER_GROUP - 1) | ||||
|  | ||||
| #define _LIMIT(a,b) (a>b?b:a) | ||||
|  | ||||
| #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 */ | ||||
|  | ||||
| #define RMT_DEFAULT_ARD_CONFIG_TX(gpio, channel_id, buffers)      \ | ||||
|     {                                                \ | ||||
|         .rmt_mode = RMT_MODE_TX,                     \ | ||||
|         .channel = channel_id,                       \ | ||||
|         .gpio_num = gpio,                            \ | ||||
|         .clk_div = 1,                                \ | ||||
|         .mem_block_num = buffers,                    \ | ||||
|         .flags = 0,                                  \ | ||||
|         .tx_config = {                               \ | ||||
|             .carrier_level = RMT_CARRIER_LEVEL_HIGH, \ | ||||
|             .idle_level = RMT_IDLE_LEVEL_LOW,        \ | ||||
|             .carrier_duty_percent = 50,              \ | ||||
|             .carrier_en = false,                     \ | ||||
|             .loop_en = false,                        \ | ||||
|             .idle_output_en = true,                  \ | ||||
|         }                                            \ | ||||
|     } | ||||
|  | ||||
| #define RMT_DEFAULT_ARD_CONFIG_RX(gpio, channel_id, buffers) \ | ||||
|     {                                           \ | ||||
|         .rmt_mode = RMT_MODE_RX,                \ | ||||
|         .channel = channel_id,                  \ | ||||
|         .gpio_num = gpio,                       \ | ||||
|         .clk_div = 1,                           \ | ||||
|         .mem_block_num = buffers,               \ | ||||
|         .flags = 0,                             \ | ||||
|         .rx_config = {                          \ | ||||
|             .idle_threshold = 0x80,             \ | ||||
|             .filter_ticks_thresh = 100,         \ | ||||
|             .filter_en = false,                 \ | ||||
|         }                                       \ | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Typedefs for internal stuctures, enums | ||||
|  */ | ||||
| struct rmt_obj_s | ||||
| { | ||||
|     bool allocated; | ||||
|     EventGroupHandle_t events; | ||||
|     int channel; | ||||
|     int buffers; | ||||
|     int data_size; | ||||
|     uint32_t* data_ptr; | ||||
|     rmt_rx_data_cb_t cb; | ||||
|     void * arg; | ||||
|     TaskHandle_t rxTaskHandle;   | ||||
|     bool rx_completed; | ||||
|     bool tx_not_rx; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Internal variables for channel descriptors | ||||
|  */ | ||||
| static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { | ||||
|     NULL, NULL, NULL, NULL,  | ||||
| #if MAX_CHANNELS > 4 | ||||
|     NULL, NULL, NULL, NULL | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
| #if MAX_CHANNELS > 4 | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
|     { false, NULL, 0, 0, 0, NULL, NULL, NULL, NULL, true, true}, | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Internal variables for driver data | ||||
|  */ | ||||
| static xSemaphoreHandle g_rmt_block_lock = NULL; | ||||
|  | ||||
| /** | ||||
|  * Internal method (private) declarations | ||||
|  */ | ||||
|  | ||||
| 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]); | ||||
| } | ||||
|  | ||||
| void _rmtDumpStatus(rmt_obj_t* rmt)  | ||||
| { | ||||
|    bool loop_en; | ||||
|    uint8_t div_cnt; | ||||
|    uint8_t memNum; | ||||
|    bool lowPowerMode; | ||||
|    rmt_mem_owner_t owner; | ||||
|    uint16_t idleThreshold; | ||||
|    uint32_t status; | ||||
|    rmt_source_clk_t srcClk; | ||||
|    rmt_channel_t channel = rmt->channel; | ||||
|  | ||||
| RMT_MUTEX_LOCK(channel); | ||||
|    rmt_get_tx_loop_mode(channel, &loop_en); | ||||
|    rmt_get_clk_div(channel, &div_cnt); | ||||
|    rmt_get_mem_block_num(channel, &memNum); | ||||
|    rmt_get_mem_pd(channel, &lowPowerMode); | ||||
|    rmt_get_memory_owner(channel, &owner); | ||||
|    rmt_get_rx_idle_thresh(channel, &idleThreshold); | ||||
|    rmt_get_status(channel, &status); | ||||
|    rmt_get_source_clk(channel, &srcClk); | ||||
|  | ||||
|    log_d("Status for RMT channel %d", channel); | ||||
|    log_d("- Loop enabled: %d", loop_en); | ||||
|    log_d("- Clock divisor: %d", div_cnt); | ||||
|    log_d("- Number of memory blocks: %d", memNum); | ||||
|    log_d("- Low power mode: %d", lowPowerMode); | ||||
|    log_d("- Memory owner: %s", owner==RMT_MEM_OWNER_TX?"TX":"RX"); | ||||
|    log_d("- Idle threshold: %d", idleThreshold); | ||||
|    log_d("- Status: %d", status); | ||||
|    log_d("- Source clock: %s", srcClk==RMT_BASECLK_APB?"APB (80MHz)":"1MHz"); | ||||
| RMT_MUTEX_UNLOCK(channel); | ||||
| } | ||||
|  | ||||
| static void _rmtRxTask(void *args) { | ||||
|     rmt_obj_t *rmt = (rmt_obj_t *) args; | ||||
|     RingbufHandle_t rb = NULL; | ||||
|     size_t rmt_len = 0; | ||||
|     rmt_item32_t *data = NULL; | ||||
|  | ||||
|     if (!rmt) { | ||||
|         log_e(" -- Inavalid Argument"); | ||||
|         goto err; | ||||
|     } | ||||
|  | ||||
|     int channel = rmt->channel; | ||||
|     rmt_get_ringbuf_handle(channel, &rb); | ||||
|     if (!rb) { | ||||
|         log_e(" -- Failed to get RMT ringbuffer handle"); | ||||
|         goto err;   | ||||
|     } | ||||
|      | ||||
|     for(;;) { | ||||
|         data = (rmt_item32_t *) xRingbufferReceive(rb, &rmt_len, portMAX_DELAY); | ||||
|         if (data) { | ||||
|             log_d(" -- Got %d bytes on RX Ringbuffer - CH %d", rmt_len, rmt->channel); | ||||
|             rmt->rx_completed = true;  // used in rmtReceiveCompleted() | ||||
|             // callback | ||||
|             if (rmt->cb) { | ||||
|                 (rmt->cb)((uint32_t *)data, rmt_len / sizeof(rmt_item32_t), rmt->arg); | ||||
|             } else { | ||||
|                 // stop RX -- will force a correct call with a callback pointer / new rmtReadData() / rmtReadAsync() | ||||
|                 rmt_rx_stop(channel); | ||||
|             } | ||||
|             // Async Read -- copy data to caller | ||||
|             if (rmt->data_ptr && rmt->data_size) { | ||||
|                 uint32_t data_size = rmt->data_size; | ||||
|                 uint32_t read_len = rmt_len / sizeof(rmt_item32_t); | ||||
|                 if (read_len < rmt->data_size) data_size = read_len; | ||||
|                 rmt_item32_t *p = (rmt_item32_t *)rmt->data_ptr; | ||||
|                 for (uint32_t i = 0; i < data_size; i++) { | ||||
|                     p[i] = data[i]; | ||||
|                 } | ||||
|             } | ||||
|             // set events | ||||
|             if (rmt->events) { | ||||
|                 xEventGroupSetBits(rmt->events, RMT_FLAG_RX_DONE); | ||||
|             } | ||||
|             vRingbufferReturnItem(rb, (void *) data); | ||||
|         } // xRingbufferReceive | ||||
|     } // for(;;) | ||||
|  | ||||
| err: | ||||
|   vTaskDelete(NULL);     | ||||
| } | ||||
|  | ||||
|  | ||||
| static bool _rmtCreateRxTask(rmt_obj_t* rmt)  | ||||
| { | ||||
|     if (!rmt) { | ||||
|         return false; | ||||
|     } | ||||
|     if (rmt->rxTaskHandle) {   // Task already created | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     xTaskCreate(_rmtRxTask, "rmt_rx_task", 4096, rmt, 20, &rmt->rxTaskHandle); | ||||
|  | ||||
|     if(rmt->rxTaskHandle == NULL){ | ||||
|         log_e("RMT RX Task create failed"); | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| // Helper function to test if an RMT channel is correctly assigned to TX or RX, issuing an error message if necessary | ||||
| // Also test RMT pointer for NULL and returns false in case it is NULL | ||||
| // return true when it is correctly assigned, false otherwise | ||||
| static bool _rmtCheckTXnotRX(rmt_obj_t* rmt, bool tx_not_rx) | ||||
| { | ||||
|     if (!rmt) {           // also returns false on NULL | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if (rmt->tx_not_rx == tx_not_rx) {  // matches expected RX/TX channel | ||||
|         return true; | ||||
|     } | ||||
|     | ||||
|     if (tx_not_rx) {    // expected TX channel | ||||
|         log_e("Can't write on a RX RMT Channel"); | ||||
|     } else{             // expected RX channel | ||||
|         log_e("Can't read on a TX RMT Channel"); | ||||
|     } | ||||
|     return false;       // missmatched | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Public method definitions | ||||
|  */ | ||||
|  | ||||
| bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_TX_MODE) || low > 0xFFFF || high > 0xFFFF) { | ||||
|         return false; | ||||
|     } | ||||
|     size_t channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_set_tx_carrier(channel, carrier_en, high, low, carrier_level); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE) || filter_level > 0xFF) { | ||||
|         return false; | ||||
|     } | ||||
|     size_t channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_set_rx_filter(channel, filter_en, filter_level); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE) || value > 0xFFFF) { | ||||
|         return false; | ||||
|     } | ||||
|     size_t channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_set_rx_idle_thresh(channel, 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; | ||||
|     } | ||||
|  | ||||
|     RMT_MUTEX_LOCK(rmt->channel); | ||||
|     // force stopping rmt processing | ||||
|     if (rmt->tx_not_rx) { | ||||
|         rmt_tx_stop(rmt->channel); | ||||
|     } else { | ||||
|         rmt_rx_stop(rmt->channel); | ||||
|         if(rmt->rxTaskHandle){ | ||||
|             vTaskDelete(rmt->rxTaskHandle); | ||||
|             rmt->rxTaskHandle = NULL; | ||||
|         }        | ||||
|     } | ||||
|  | ||||
|     rmt_driver_uninstall(rmt->channel); | ||||
|  | ||||
|     size_t from = rmt->channel; | ||||
|     size_t to = rmt->buffers + rmt->channel; | ||||
|     size_t i; | ||||
|  | ||||
|     for (i = from; i < to; i++) { | ||||
|         g_rmt_objects[i].allocated = false; | ||||
|     } | ||||
|  | ||||
|     g_rmt_objects[from].channel = 0; | ||||
|     g_rmt_objects[from].buffers = 0; | ||||
|     RMT_MUTEX_UNLOCK(rmt->channel); | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(g_rmt_objlocks[from] != NULL) { | ||||
|         vSemaphoreDelete(g_rmt_objlocks[from]); | ||||
|         g_rmt_objlocks[from] = NULL; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_TX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_tx_stop(channel); | ||||
|     rmt_set_tx_loop_mode(channel, true); | ||||
|     rmt_write_items(channel, (const rmt_item32_t *)data, size, false); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_TX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_tx_stop(channel); | ||||
|     rmt_set_tx_loop_mode(channel, false); | ||||
|     rmt_write_items(channel, (const rmt_item32_t *)data, size, false); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtWriteBlocking(rmt_obj_t* rmt, rmt_data_t* data, size_t size) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_TX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_tx_stop(channel); | ||||
|     rmt_set_tx_loop_mode(channel, false); | ||||
|     rmt_write_items(channel, (const rmt_item32_t *)data, size, true); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     rmtReadAsync(rmt, (rmt_data_t*) data, size, NULL, false, 0); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool rmtBeginReceive(rmt_obj_t* rmt) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX); | ||||
|     rmt_rx_start(channel, true); | ||||
|     rmt->rx_completed = false; | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtReceiveCompleted(rmt_obj_t* rmt) | ||||
| { | ||||
|     if (!rmt) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return rmt->rx_completed; | ||||
| } | ||||
|  | ||||
| bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg) | ||||
| { | ||||
|     if (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|  | ||||
|     rmt->arg = arg; | ||||
|     rmt->cb = cb; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     // cb as NULL is a way to cancel the callback process | ||||
|     if (cb == NULL) {         | ||||
|         rmt_rx_stop(channel); | ||||
|         return true; | ||||
|     } | ||||
|     // Start a read process but now with a call back function | ||||
|     rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX); | ||||
|     rmt_rx_start(channel, true); | ||||
|     rmt->rx_completed = false; | ||||
|     _rmtCreateRxTask(rmt); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| bool rmtEnd(rmt_obj_t* rmt)  | ||||
| { | ||||
|     if (!rmt) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     if (rmt->tx_not_rx) { | ||||
|         rmt_tx_stop(channel); | ||||
|     } else { | ||||
|         rmt_rx_stop(channel); | ||||
|         rmt->rx_completed = true; | ||||
|     } | ||||
|     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 (!_rmtCheckTXnotRX(rmt, RMT_RX_MODE)) { | ||||
|         return false; | ||||
|     } | ||||
|     int channel = rmt->channel; | ||||
|  | ||||
|     // No limit on size with IDF ;-) | ||||
|     //if (g_rmt_objects[channel].buffers < size/SOC_RMT_MEM_WORDS_PER_CHANNEL) { | ||||
|     //    return false; | ||||
|     //} | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     if (eventFlag) { | ||||
|         xEventGroupClearBits(eventFlag, RMT_FLAGS_ALL); | ||||
|     } | ||||
|     // if NULL, no problems - rmtReadAsync works as a plain rmtReadData() | ||||
|     rmt->events = eventFlag;   | ||||
|  | ||||
|     // if NULL, no problems - task will take care of it | ||||
|     rmt->data_ptr = (uint32_t*)data; | ||||
|     rmt->data_size = size; | ||||
|   | ||||
|     // Start a read process | ||||
|     rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX);  | ||||
|     rmt_rx_start(channel, true); | ||||
|     rmt->rx_completed = false; | ||||
|     _rmtCreateRxTask(rmt); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|  | ||||
|     // wait for data if requested so | ||||
|     if (waitForData && eventFlag) { | ||||
|         xEventGroupWaitBits(eventFlag, RMT_FLAGS_ALL, | ||||
|                             pdTRUE /* clear on exit */, pdFALSE /* wait for all bits */, timeout); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| float rmtSetTick(rmt_obj_t* rmt, float tick) | ||||
| { | ||||
|     if (!rmt) { | ||||
|         return false; | ||||
|     }     | ||||
|     size_t channel = rmt->channel; | ||||
|  | ||||
|     RMT_MUTEX_LOCK(channel); | ||||
|     // RMT_BASECLK_REF (1MHz) is not supported in IDF upon Programmming Guide | ||||
|     // Only APB works | ||||
|     rmt_set_source_clk(channel, RMT_BASECLK_APB);    | ||||
|     int apb_div = _LIMIT(tick/12.5f, 256); | ||||
|     float apb_tick = 12.5f * apb_div; | ||||
|      | ||||
|     rmt_set_clk_div(channel, apb_div & 0xFF); | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|     return apb_tick; | ||||
| } | ||||
|  | ||||
| rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) | ||||
| { | ||||
|     int buffers = memsize; | ||||
|     rmt_obj_t* rmt = NULL; | ||||
|     size_t i = 0; | ||||
|     size_t j = 0; | ||||
|  | ||||
|     // 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) {} | ||||
|  | ||||
|     // Some SoC may have fixed channel numbers for TX and RX - example: ESP32C3 | ||||
|     uint8_t ch_start, ch_end; | ||||
|     if (tx_not_rx) { | ||||
|         ch_start = RMT_TX_CH_START; | ||||
|         ch_end = RMT_TX_CH_END; | ||||
|     } else { | ||||
|         ch_start = RMT_RX_CH_START; | ||||
|         ch_end = RMT_RX_CH_END; | ||||
|     } | ||||
|     for (i=ch_start; i<=ch_end; i++) { | ||||
|         for (j=0; j<buffers && i+j <= ch_end; 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); | ||||
|         log_e("rmInit Failed - not enough channels"); | ||||
|         return NULL; | ||||
|     } | ||||
|      | ||||
|     // A suitable channel has been found, it has to block its resources in our internal data strucuture | ||||
|     size_t channel = i; | ||||
|     rmt = _rmtAllocate(pin, i, buffers); | ||||
|  | ||||
|     xSemaphoreGive(g_rmt_block_lock); | ||||
|  | ||||
|     rmt->buffers = buffers; | ||||
|     rmt->channel = channel; | ||||
|     rmt->arg = NULL; | ||||
|     rmt->cb = NULL; | ||||
|     rmt->data_ptr = NULL; | ||||
|     rmt->data_size = 0; | ||||
|     rmt->rx_completed = false; | ||||
|     rmt->events = NULL; | ||||
|     rmt->tx_not_rx = tx_not_rx; | ||||
|  | ||||
| #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); | ||||
|     esp_err_t esp_err_code = ESP_OK; | ||||
|  | ||||
|     if (tx_not_rx) { | ||||
|         rmt_config_t config = RMT_DEFAULT_ARD_CONFIG_TX(pin, channel, buffers); | ||||
|         esp_err_code = rmt_config(&config); | ||||
|         if (esp_err_code == ESP_OK)  | ||||
|             esp_err_code = rmt_driver_install(channel, 0, 0); | ||||
|         log_d(" -- %s RMT - CH %d - %d RAM Blocks - pin %d", tx_not_rx?"TX":"RX", channel, buffers, pin); | ||||
|     } else { | ||||
|         rmt_config_t config = RMT_DEFAULT_ARD_CONFIG_RX(pin, channel, buffers); | ||||
|         esp_err_code = rmt_config(&config); | ||||
|         if (esp_err_code == ESP_OK)  | ||||
|             esp_err_code = rmt_driver_install(channel, 1024, 0); | ||||
|         if (esp_err_code == ESP_OK)  | ||||
|             esp_err_code = rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX); | ||||
|         log_d(" -- %s RMT - CH %d - %d RAM Blocks - pin %d", tx_not_rx?"TX":"RX", channel, buffers, pin); | ||||
|     }  | ||||
|  | ||||
|     RMT_MUTEX_UNLOCK(channel); | ||||
|  | ||||
|     if (esp_err_code == ESP_OK) { | ||||
|         return rmt; | ||||
|     } else { | ||||
|         log_e("RMT failed to initilize."); | ||||
|         return NULL; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										169
									
								
								cores/esp32/esp32-hal-rmt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								cores/esp32/esp32-hal-rmt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| // 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) | ||||
|  | ||||
| #define RMT_TX_MODE      true | ||||
| #define RMT_RX_MODE      false | ||||
|  | ||||
| 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, void *arg); | ||||
|  | ||||
| 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; | ||||
|  | ||||
|  | ||||
| /** | ||||
| *    Prints object information | ||||
| * | ||||
| */ | ||||
| void _rmtDumpStatus(rmt_obj_t* rmt); | ||||
|  | ||||
| /** | ||||
| *    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) | ||||
| *    Non-Blocking mode - returns right after executing | ||||
| */ | ||||
| bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size); | ||||
|  | ||||
| /** | ||||
| *    Sending data in one-go mode or continual mode | ||||
| *     (more data being send while updating buffers in interrupts) | ||||
| *    Blocking mode - only returns when data has been sent | ||||
| */ | ||||
| bool rmtWriteBlocking(rmt_obj_t* rmt, rmt_data_t* data, size_t size); | ||||
|  | ||||
| /** | ||||
| *    Loop data up to the reserved memsize continuously | ||||
| * | ||||
| */ | ||||
| bool rmtLoop(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, void * arg); | ||||
|  | ||||
| /*** | ||||
|  * Ends async receive started with rmtRead(); but does not | ||||
|  * rmtDeInit(). | ||||
|  */ | ||||
| bool rmtEnd(rmt_obj_t* rmt); | ||||
|  | ||||
| /*  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_ */ | ||||
							
								
								
									
										89
									
								
								cores/esp32/esp32-hal-sigmadelta.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								cores/esp32/esp32-hal-sigmadelta.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| // 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 "soc/soc_caps.h" | ||||
| #include "driver/sigmadelta.h" | ||||
|  | ||||
| static uint8_t duty_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0}; | ||||
| static uint32_t prescaler_set[SOC_SIGMADELTA_CHANNEL_NUM] = {0}; | ||||
|  | ||||
| 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_AFTER_CHANGE){ | ||||
|         old_apb /= 1000000; | ||||
|         new_apb /= 1000000; | ||||
|         uint32_t old_prescale = prescaler_set[channel] + 1; | ||||
|         uint32_t new_prescale = ((new_apb * old_prescale) / old_apb) - 1; | ||||
|         sigmadelta_set_prescale(channel,new_prescale); | ||||
|         prescaler_set[channel] = new_prescale; | ||||
|     } | ||||
| } | ||||
|  | ||||
| uint32_t sigmaDeltaSetup(uint8_t pin, uint8_t channel, uint32_t freq) //chan 0-x according to SOC, freq 1220-312500 | ||||
| { | ||||
|     if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     uint32_t apb_freq = getApbFrequency(); | ||||
|     uint32_t prescale = (apb_freq/(freq*256)) - 1; | ||||
|     if(prescale > 0xFF) { | ||||
|         prescale = 0xFF; | ||||
|     } | ||||
|  | ||||
|     sigmadelta_config_t sigmadelta_cfg = { | ||||
|         .channel = channel, | ||||
|         .sigmadelta_prescale = prescale, | ||||
|         .sigmadelta_duty = 0, | ||||
|         .sigmadelta_gpio = pin, | ||||
|     }; | ||||
|     sigmadelta_config(&sigmadelta_cfg); | ||||
|  | ||||
|     prescaler_set[channel] = prescale; | ||||
|     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-x according to SOC duty 8 bit | ||||
| { | ||||
|     if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ | ||||
|         return; | ||||
|     } | ||||
|     duty -= 128;  | ||||
|  | ||||
|     sigmadelta_set_duty(channel,duty); | ||||
|     duty_set[channel] = duty; | ||||
| } | ||||
|  | ||||
| uint8_t sigmaDeltaRead(uint8_t channel) //chan 0-x according to SOC | ||||
| { | ||||
|     if(channel >= SOC_SIGMADELTA_CHANNEL_NUM){ | ||||
|         return 0; | ||||
|     } | ||||
|     return duty_set[channel]+128; | ||||
| } | ||||
|  | ||||
| void sigmaDeltaDetachPin(uint8_t pin) | ||||
| { | ||||
|     pinMatrixOutDetach(pin, false, false); | ||||
| } | ||||
							
								
								
									
										36
									
								
								cores/esp32/esp32-hal-sigmadelta.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								cores/esp32/esp32-hal-sigmadelta.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| // 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 pin, uint8_t channel, uint32_t freq); | ||||
| void        sigmaDeltaWrite(uint8_t channel, uint8_t duty); | ||||
| uint8_t     sigmaDeltaRead(uint8_t channel); | ||||
| void        sigmaDeltaDetachPin(uint8_t pin); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* _ESP32_HAL_SD_H_ */ | ||||
							
								
								
									
										1560
									
								
								cores/esp32/esp32-hal-spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1560
									
								
								cores/esp32/esp32-hal-spi.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										149
									
								
								cores/esp32/esp32-hal-spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								cores/esp32/esp32-hal-spi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| // 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 "sdkconfig.h" | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #define SPI_HAS_TRANSACTION | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 | ||||
| #define FSPI  0 | ||||
| #define HSPI  1 | ||||
| #else | ||||
| #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 | ||||
| #if CONFIG_IDF_TARGET_ESP32 | ||||
| #define VSPI  3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| // 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 clockDiv, 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, const 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, const 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_in, 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_in, 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_ */ | ||||
							
								
								
									
										97
									
								
								cores/esp32/esp32-hal-time.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								cores/esp32/esp32-hal-time.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // 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" | ||||
| //#include "tcpip_adapter.h" | ||||
| #include "esp_netif.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) | ||||
| { | ||||
|     //tcpip_adapter_init();  // Should not hurt anything if already inited | ||||
|     esp_netif_init(); | ||||
|     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) | ||||
| { | ||||
|     //tcpip_adapter_init();  // Should not hurt anything if already inited | ||||
|     esp_netif_init(); | ||||
|     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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										269
									
								
								cores/esp32/esp32-hal-timer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								cores/esp32/esp32-hal-timer.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,269 @@ | ||||
| // 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 "driver/timer.h" | ||||
| #include "soc/soc_caps.h" | ||||
|  | ||||
| typedef 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; | ||||
| } timer_cfg_t; | ||||
|  | ||||
| #define NUM_OF_TIMERS   SOC_TIMER_GROUP_TOTAL_TIMERS | ||||
|  | ||||
| typedef struct hw_timer_s | ||||
| { | ||||
|     uint8_t group; | ||||
|     uint8_t num; | ||||
| } hw_timer_t; | ||||
|  | ||||
| // Works for all chips | ||||
| static hw_timer_t timer_dev[4] = { | ||||
|     {0,0}, {1,0},  {0,1},  {1,1} | ||||
| }; | ||||
|  | ||||
| // NOTE: (in IDF 5.0 there wont be need to know groups/numbers  | ||||
| // timer_init() will list thru all timers and return free timer handle) | ||||
|  | ||||
|  | ||||
| uint64_t inline timerRead(hw_timer_t *timer){ | ||||
|  | ||||
|     uint64_t value; | ||||
|     timer_get_counter_value(timer->group, timer->num,&value); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| uint64_t timerAlarmRead(hw_timer_t *timer){ | ||||
|     uint64_t value; | ||||
|     timer_get_alarm_value(timer->group, timer->num, &value); | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| void timerWrite(hw_timer_t *timer, uint64_t val){ | ||||
|     timer_set_counter_value(timer->group, timer->num, val); | ||||
| } | ||||
|  | ||||
| void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ | ||||
|     timer_set_alarm_value(timer->group, timer->num, alarm_value); | ||||
|     timerSetAutoReload(timer,autoreload); | ||||
| } | ||||
|  | ||||
| void timerSetConfig(hw_timer_t *timer, uint32_t config){ | ||||
|     timer_cfg_t cfg; | ||||
|     cfg.val = config; | ||||
|     timer_set_alarm(timer->group, timer->num, cfg.alarm_en); | ||||
|     timerSetDivider(timer,cfg.divider); | ||||
|     timerSetAutoReload(timer,cfg.autoreload); | ||||
|     timerSetCountUp(timer, cfg.increase); | ||||
|  | ||||
|     if (cfg.enable) { | ||||
|         timerStart(timer); | ||||
|     } | ||||
|     else{ | ||||
|         timerStop(timer); | ||||
|     } | ||||
|     return; | ||||
| } | ||||
|  | ||||
| uint32_t timerGetConfig(hw_timer_t *timer){ | ||||
|     timer_config_t timer_cfg; | ||||
|     timer_get_config(timer->group, timer->num,&timer_cfg); | ||||
|  | ||||
|     //Translate to default uint32_t | ||||
|     timer_cfg_t cfg; | ||||
|     cfg.alarm_en = timer_cfg.alarm_en; | ||||
|     cfg.autoreload = timer_cfg.auto_reload; | ||||
|     cfg.divider = timer_cfg.divider; | ||||
|     cfg.edge_int_en = timer_cfg.intr_type; | ||||
|     cfg.level_int_en = !timer_cfg.intr_type; | ||||
|     cfg.enable = timer_cfg.counter_en; | ||||
|     cfg.increase = timer_cfg.counter_dir; | ||||
|  | ||||
|     return cfg.val; | ||||
| } | ||||
|  | ||||
| void timerSetCountUp(hw_timer_t *timer, bool countUp){ | ||||
|     timer_set_counter_mode(timer->group, timer->num,countUp); | ||||
| } | ||||
|  | ||||
| bool timerGetCountUp(hw_timer_t *timer){ | ||||
|     timer_cfg_t config; | ||||
|     config.val = timerGetConfig(timer); | ||||
|     return config.increase; | ||||
| } | ||||
|  | ||||
| void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ | ||||
|     timer_set_auto_reload(timer->group, timer->num,autoreload); | ||||
| } | ||||
|  | ||||
| bool timerGetAutoReload(hw_timer_t *timer){ | ||||
|     timer_cfg_t config; | ||||
|     config.val= timerGetConfig(timer); | ||||
|     return config.autoreload; | ||||
| } | ||||
|  | ||||
| // Set divider from 2 to 65535 | ||||
| void timerSetDivider(hw_timer_t *timer, uint16_t divider){ | ||||
|     if(divider < 2) | ||||
|     { | ||||
|         log_e("Timer divider must be set in range of 2 to 65535"); | ||||
|         return; | ||||
|     } | ||||
|     timer_set_divider(timer->group, timer->num,divider); | ||||
| } | ||||
|  | ||||
| uint16_t timerGetDivider(hw_timer_t *timer){ | ||||
|     timer_cfg_t config; | ||||
|     config.val = timerGetConfig(timer); | ||||
|     return config.divider; | ||||
| } | ||||
|  | ||||
| void timerStart(hw_timer_t *timer){ | ||||
|     timer_start(timer->group, timer->num); | ||||
| } | ||||
|  | ||||
| void timerStop(hw_timer_t *timer){ | ||||
|     timer_pause(timer->group, timer->num); | ||||
| } | ||||
|  | ||||
| void timerRestart(hw_timer_t *timer){ | ||||
|     timerWrite(timer,0); | ||||
| } | ||||
|  | ||||
| bool timerStarted(hw_timer_t *timer){ | ||||
|     timer_cfg_t config; | ||||
|     config.val = timerGetConfig(timer); | ||||
|     return config.enable; | ||||
| } | ||||
|  | ||||
| void timerAlarmEnable(hw_timer_t *timer){ | ||||
|     timer_set_alarm(timer->group, timer->num,true); | ||||
| } | ||||
|  | ||||
| void timerAlarmDisable(hw_timer_t *timer){ | ||||
|     timer_set_alarm(timer->group, timer->num,false); | ||||
| } | ||||
|  | ||||
| bool timerAlarmEnabled(hw_timer_t *timer){ | ||||
|     timer_cfg_t config; | ||||
|     config.val = timerGetConfig(timer); | ||||
|     return 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){ | ||||
|         timerStop(timer); | ||||
|     } else { | ||||
|         old_apb /= 1000000; | ||||
|         new_apb /= 1000000; | ||||
|         uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb; | ||||
|         timerSetDivider(timer,divider); | ||||
|         timerStart(timer); | ||||
|     } | ||||
| } | ||||
|  | ||||
| hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ | ||||
|     if(num >= NUM_OF_TIMERS) | ||||
|     { | ||||
|         log_e("Timer number %u exceeds available number of Timers.", num); | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     hw_timer_t * timer = &timer_dev[num];   //Get Timer group/num from 0-3 number | ||||
|      | ||||
|     timer_config_t config = { | ||||
|             .divider = divider, | ||||
|             .counter_dir = countUp, | ||||
|             .counter_en = TIMER_PAUSE, | ||||
|             .alarm_en = TIMER_ALARM_DIS, | ||||
|             .auto_reload = false, | ||||
|         }; | ||||
|  | ||||
|     timer_init(timer->group, timer->num, &config); | ||||
|     timer_set_counter_value(timer->group, timer->num, 0); | ||||
|     timerStart(timer); | ||||
|     addApbChangeCallback(timer, _on_apb_change); | ||||
|     return timer; | ||||
| } | ||||
|  | ||||
| void timerEnd(hw_timer_t *timer){ | ||||
|     removeApbChangeCallback(timer, _on_apb_change); | ||||
|     timer_deinit(timer->group, timer->num); | ||||
| } | ||||
|  | ||||
| bool IRAM_ATTR timerFnWrapper(void *arg){ | ||||
|     void (*fn)(void) = arg; | ||||
|     fn(); | ||||
|  | ||||
|     // some additional logic or handling may be required here to approriately yield or not | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ | ||||
|     if(edge){ | ||||
|         log_w("EDGE timer interrupt is not supported! Setting to LEVEL..."); | ||||
|     } | ||||
|     timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, 0); | ||||
| } | ||||
|  | ||||
| void timerDetachInterrupt(hw_timer_t *timer){ | ||||
|     timer_isr_callback_remove(timer->group, timer->num); | ||||
| } | ||||
|  | ||||
| uint64_t timerReadMicros(hw_timer_t *timer){ | ||||
|     uint64_t timer_val = timerRead(timer); | ||||
|     uint16_t div = timerGetDivider(timer); | ||||
|     return timer_val * div / (getApbFrequency() / 1000000); | ||||
| } | ||||
|  | ||||
| uint64_t timerReadMilis(hw_timer_t *timer){ | ||||
|     uint64_t timer_val = timerRead(timer); | ||||
|     uint16_t div = timerGetDivider(timer); | ||||
|     return timer_val * div / (getApbFrequency() / 1000); | ||||
| } | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
| uint64_t timerAlarmReadMilis(hw_timer_t *timer){ | ||||
|     uint64_t timer_val = timerAlarmRead(timer); | ||||
|     uint16_t div = timerGetDivider(timer); | ||||
|     return timer_val * div / (getApbFrequency() / 1000); | ||||
| } | ||||
|  | ||||
| double timerAlarmReadSeconds(hw_timer_t *timer){ | ||||
|     uint64_t timer_val = timerAlarmRead(timer); | ||||
|     uint16_t div = timerGetDivider(timer); | ||||
|     return (double)timer_val * div / getApbFrequency(); | ||||
| } | ||||
							
								
								
									
										73
									
								
								cores/esp32/esp32-hal-timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								cores/esp32/esp32-hal-timer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  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_ | ||||
|  | ||||
| #include "esp32-hal.h" | ||||
| #include "freertos/FreeRTOS.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| 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); | ||||
| uint64_t timerReadMilis(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 alarm_value, 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_ */ | ||||
							
								
								
									
										776
									
								
								cores/esp32/esp32-hal-tinyusb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										776
									
								
								cores/esp32/esp32-hal-tinyusb.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,776 @@ | ||||
|  | ||||
| #include "sdkconfig.h" | ||||
| #if CONFIG_TINYUSB_ENABLED | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #include "esp_log.h" | ||||
|  | ||||
| #include "soc/soc.h" | ||||
| #include "soc/efuse_reg.h" | ||||
| #include "soc/rtc_cntl_reg.h" | ||||
| #include "soc/usb_struct.h" | ||||
| #include "soc/usb_reg.h" | ||||
| #include "soc/usb_wrap_reg.h" | ||||
| #include "soc/usb_wrap_struct.h" | ||||
| #include "soc/usb_periph.h" | ||||
| #include "soc/periph_defs.h" | ||||
| #include "soc/timer_group_struct.h" | ||||
| #include "soc/system_reg.h" | ||||
|  | ||||
| #include "hal/usb_hal.h" | ||||
| #include "hal/gpio_ll.h" | ||||
|  | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
|  | ||||
| #include "driver/gpio.h" | ||||
| #include "driver/periph_ctrl.h" | ||||
|  | ||||
| #include "esp_efuse.h" | ||||
| #include "esp_efuse_table.h" | ||||
| #include "esp_rom_gpio.h" | ||||
|  | ||||
| #include "esp32-hal.h" | ||||
|  | ||||
| #include "esp32-hal-tinyusb.h" | ||||
| #if CONFIG_IDF_TARGET_ESP32S2 | ||||
| #include "esp32s2/rom/usb/usb_persist.h" | ||||
| #include "esp32s2/rom/usb/usb_dc.h" | ||||
| #include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #include "hal/usb_serial_jtag_ll.h" | ||||
| #include "esp32s3/rom/usb/usb_persist.h" | ||||
| #include "esp32s3/rom/usb/usb_dc.h" | ||||
| #include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" | ||||
| #endif | ||||
|  | ||||
| typedef enum{ | ||||
|     TINYUSB_USBDEV_0, | ||||
| } tinyusb_usbdev_t; | ||||
|  | ||||
| typedef char *tusb_desc_strarray_device_t[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; | ||||
|  | ||||
| typedef struct { | ||||
|     bool external_phy; | ||||
| } tinyusb_config_t; | ||||
|  | ||||
| static void configure_pins(usb_hal_context_t *usb) | ||||
| { | ||||
|     for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) { | ||||
|         if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) { | ||||
|             esp_rom_gpio_pad_select_gpio(iopin->pin); | ||||
|             if (iopin->is_output) { | ||||
|                 esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false); | ||||
|             } else { | ||||
|                 esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false); | ||||
|                 if ((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) { | ||||
|                     gpio_ll_input_enable(&GPIO, iopin->pin); | ||||
|                 } | ||||
|             } | ||||
|             esp_rom_gpio_pad_unhold(iopin->pin); | ||||
|         } | ||||
|     } | ||||
|     if (!usb->use_external_phy) { | ||||
|         gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); | ||||
|         gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); | ||||
|     } | ||||
| } | ||||
|  | ||||
| esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) | ||||
| { | ||||
|     usb_hal_context_t hal = { | ||||
|         .use_external_phy = config->external_phy | ||||
|     }; | ||||
|     usb_hal_init(&hal); | ||||
|     configure_pins(&hal); | ||||
|     if (!tusb_init()) { | ||||
|         log_e("Can't initialize the TinyUSB stack."); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     return ESP_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| typedef char tusb_str_t[127]; | ||||
|  | ||||
| static bool WEBUSB_ENABLED                = false; | ||||
|  | ||||
| static tusb_str_t WEBUSB_URL              = ""; | ||||
| static tusb_str_t USB_DEVICE_PRODUCT      = ""; | ||||
| static tusb_str_t USB_DEVICE_MANUFACTURER = ""; | ||||
| static tusb_str_t USB_DEVICE_SERIAL       = ""; | ||||
| static tusb_str_t USB_DEVICE_LANGUAGE     = "\x09\x04";//English (0x0409) | ||||
|  | ||||
| static uint8_t USB_DEVICE_ATTRIBUTES     = 0; | ||||
| static uint16_t USB_DEVICE_POWER         = 0; | ||||
|  | ||||
| /* | ||||
|  * Device Descriptor | ||||
|  * */ | ||||
| static tusb_desc_device_t tinyusb_device_descriptor = { | ||||
|         .bLength = sizeof(tusb_desc_device_t), | ||||
|         .bDescriptorType = TUSB_DESC_DEVICE, | ||||
|         .bcdUSB = 0, | ||||
|         .bDeviceClass = 0, | ||||
|         .bDeviceSubClass = 0, | ||||
|         .bDeviceProtocol = 0, | ||||
|         .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, | ||||
|  | ||||
|         .idVendor = 0, | ||||
|         .idProduct = 0, | ||||
|         .bcdDevice = 0, | ||||
|  | ||||
|         .iManufacturer = 0x01, | ||||
|         .iProduct = 0x02, | ||||
|         .iSerialNumber = 0x03, | ||||
|  | ||||
|         .bNumConfigurations = 0x01 | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * String Descriptors | ||||
|  * */ | ||||
| #define MAX_STRING_DESCRIPTORS 20 | ||||
| static uint32_t tinyusb_string_descriptor_len = 4; | ||||
| static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { | ||||
|         // array of pointer to string descriptors | ||||
|         USB_DEVICE_LANGUAGE,    // 0: is supported language | ||||
|         USB_DEVICE_MANUFACTURER,// 1: Manufacturer | ||||
|         USB_DEVICE_PRODUCT,     // 2: Product | ||||
|         USB_DEVICE_SERIAL,      // 3: Serials, should use chip ID | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* Microsoft OS 2.0 registry property descriptor | ||||
| Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx | ||||
| device should create DeviceInterfaceGUIDs. It can be done by driver and | ||||
| in case of real PnP solution device should expose MS "Microsoft OS 2.0 | ||||
| registry property descriptor". Such descriptor can insert any record | ||||
| into Windows registry per device/configuration/interface. In our case it | ||||
| will insert "DeviceInterfaceGUIDs" multistring property. | ||||
|  | ||||
| GUID is freshly generated and should be OK to use. | ||||
|  | ||||
| https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ | ||||
| (Section Microsoft OS compatibility descriptors) | ||||
|  */ | ||||
|  | ||||
| #define MS_OS_20_DESC_LEN  0xB2 | ||||
|  | ||||
| static uint8_t const tinyusb_ms_os_20_descriptor[] = | ||||
| { | ||||
|         // Set header: length, type, windows version, total length | ||||
|         U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN), | ||||
|  | ||||
|         // Configuration subset header: length, type, configuration index, reserved, configuration total length | ||||
|         U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), | ||||
|  | ||||
|         // Function Subset header: length, type, first interface, reserved, subset length | ||||
|         U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), | ||||
|  | ||||
|         // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID | ||||
|         U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, | ||||
|         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible | ||||
|  | ||||
|         // MS OS 2.0 Registry property descriptor: length, type | ||||
|         U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), | ||||
|         U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16 | ||||
|         'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, | ||||
|         'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, | ||||
|         U16_TO_U8S_LE(0x0050), // wPropertyDataLength | ||||
|         //bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”. | ||||
|         '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00, | ||||
|         '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, | ||||
|         '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00, | ||||
|         '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 | ||||
| }; | ||||
|  | ||||
| TU_VERIFY_STATIC(sizeof(tinyusb_ms_os_20_descriptor) == MS_OS_20_DESC_LEN, "Incorrect size"); | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * BOS Descriptor (required for webUSB) | ||||
|  * */ | ||||
| #define BOS_TOTAL_LEN      (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) | ||||
|  | ||||
| enum { | ||||
|     VENDOR_REQUEST_WEBUSB = 1, | ||||
|     VENDOR_REQUEST_MICROSOFT = 2 | ||||
| }; | ||||
|  | ||||
| static uint8_t const tinyusb_bos_descriptor[] = { | ||||
|         // total length, number of device caps | ||||
|         TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), | ||||
|  | ||||
|         // Vendor Code, iLandingPage | ||||
|         TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), | ||||
|  | ||||
|         // Microsoft OS 2.0 descriptor | ||||
|         TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * URL Descriptor (required for webUSB) | ||||
|  * */ | ||||
| typedef struct TU_ATTR_PACKED { | ||||
|   uint8_t bLength; | ||||
|   uint8_t bDescriptorType; | ||||
|   uint8_t bScheme; | ||||
|   char    url[127]; | ||||
| } tinyusb_desc_webusb_url_t; | ||||
|  | ||||
| static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = { | ||||
|         .bLength         = 3, | ||||
|         .bDescriptorType = 3, // WEBUSB URL type | ||||
|         .bScheme         = 255, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: "" | ||||
|         .url             = "" | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Configuration Descriptor | ||||
|  * */ | ||||
|  | ||||
| static tinyusb_descriptor_cb_t tinyusb_loaded_interfaces_callbacks[USB_INTERFACE_MAX]; | ||||
| static uint32_t tinyusb_loaded_interfaces_mask = 0; | ||||
| static uint8_t tinyusb_loaded_interfaces_num = 0; | ||||
| static uint16_t tinyusb_config_descriptor_len = 0; | ||||
| static uint8_t * tinyusb_config_descriptor = NULL; | ||||
|  | ||||
| /* | ||||
|  * Endpoint Usage Tracking | ||||
|  * */ | ||||
| typedef union { | ||||
|         struct { | ||||
|                 uint32_t in:16; | ||||
|                 uint32_t out:16; | ||||
|         }; | ||||
|         uint32_t val; | ||||
| } tinyusb_endpoints_usage_t; | ||||
|  | ||||
| static tinyusb_endpoints_usage_t tinyusb_endpoints; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * TinyUSB Callbacks | ||||
|  * */ | ||||
|  | ||||
| /** | ||||
|  * @brief Invoked when received GET CONFIGURATION DESCRIPTOR. | ||||
|  */ | ||||
| __attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index) | ||||
| { | ||||
|     //log_d("%u", index); | ||||
|     return tinyusb_config_descriptor; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Invoked when received GET DEVICE DESCRIPTOR. | ||||
|  */ | ||||
| __attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void) | ||||
| { | ||||
|     //log_d(""); | ||||
|     return (uint8_t const *)&tinyusb_device_descriptor; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Invoked when received GET STRING DESCRIPTOR request. | ||||
|  */ | ||||
| __attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) | ||||
| { | ||||
|     //log_d("%u (0x%x)", index, langid); | ||||
|     static uint16_t _desc_str[127]; | ||||
|     uint8_t chr_count; | ||||
|  | ||||
|     if (index == 0) { | ||||
|         memcpy(&_desc_str[1], tinyusb_string_descriptor[0], 2); | ||||
|         chr_count = 1; | ||||
|     } else { | ||||
|         // Convert ASCII string into UTF-16 | ||||
|         if (index >= tinyusb_string_descriptor_len) { | ||||
|             return NULL; | ||||
|         } | ||||
|         const char *str = tinyusb_string_descriptor[index]; | ||||
|         // Cap at max char | ||||
|         chr_count = strlen(str); | ||||
|         if (chr_count > 126) { | ||||
|             chr_count = 126; | ||||
|         } | ||||
|         for (uint8_t i = 0; i < chr_count; i++) { | ||||
|             _desc_str[1 + i] = str[i]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // first byte is len, second byte is string type | ||||
|     _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2); | ||||
|  | ||||
|     return _desc_str; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @brief Invoked when received GET BOS DESCRIPTOR request. | ||||
|  */ | ||||
| uint8_t const * tud_descriptor_bos_cb(void) | ||||
| { | ||||
|     //log_v(""); | ||||
|     return tinyusb_bos_descriptor; | ||||
| } | ||||
|  | ||||
| __attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ return false; } | ||||
|  | ||||
| /** | ||||
|  * @brief Handle WebUSB and Vendor requests. | ||||
|  */ | ||||
| bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) | ||||
| { | ||||
|     if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB | ||||
|             || (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){ | ||||
|         // we only care for SETUP stage | ||||
|         if (stage == CONTROL_STAGE_SETUP) { | ||||
|             if(request->bRequest == VENDOR_REQUEST_WEBUSB){ | ||||
|                 // match vendor request in BOS descriptor | ||||
|                 // Get landing page url | ||||
|                 tinyusb_url_descriptor.bLength = 3 + strlen(WEBUSB_URL); | ||||
|                 snprintf(tinyusb_url_descriptor.url, 127, "%s", WEBUSB_URL); | ||||
|                 return tud_control_xfer(rhport, request, (void*) &tinyusb_url_descriptor, tinyusb_url_descriptor.bLength); | ||||
|             } | ||||
|             // Get Microsoft OS 2.0 compatible descriptor | ||||
|             uint16_t total_len; | ||||
|             memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2); | ||||
|             return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|     log_v("rhport: %u, stage: %u, type: 0x%x, request: 0x%x", rhport, stage, request->bmRequestType_bit.type, request->bRequest); | ||||
|     return tinyusb_vendor_control_request_cb(rhport, stage, request); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Required Callbacks | ||||
|  * */ | ||||
| #if CFG_TUD_HID | ||||
| __attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(uint8_t itf){return NULL;} | ||||
| __attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;} | ||||
| __attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){} | ||||
| #endif | ||||
| #if CFG_TUD_MSC | ||||
| __attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;} | ||||
| __attribute__ ((weak)) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]){} | ||||
| __attribute__ ((weak)) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size){} | ||||
| __attribute__ ((weak)) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){return -1;} | ||||
| __attribute__ ((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){return -1;} | ||||
| __attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize){return -1;} | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Private API | ||||
|  * */ | ||||
| static bool usb_persist_enabled = false; | ||||
| static restart_type_t usb_persist_mode = RESTART_NO_PERSIST; | ||||
|  | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 | ||||
|  | ||||
| static void hw_cdc_reset_handler(void *arg) { | ||||
|     portBASE_TYPE xTaskWoken = 0; | ||||
|     uint32_t usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); | ||||
|     usb_serial_jtag_ll_clr_intsts_mask(usbjtag_intr_status); | ||||
|      | ||||
|     if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) { | ||||
|         xSemaphoreGiveFromISR((xSemaphoreHandle)arg, &xTaskWoken); | ||||
|     } | ||||
|  | ||||
|     if (xTaskWoken == pdTRUE) { | ||||
|         portYIELD_FROM_ISR(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void usb_switch_to_cdc_jtag(){ | ||||
|     // Disable USB-OTG | ||||
|     periph_module_reset(PERIPH_USB_MODULE); | ||||
|     //periph_module_enable(PERIPH_USB_MODULE); | ||||
|     periph_module_disable(PERIPH_USB_MODULE); | ||||
|  | ||||
|     // Switch to hardware CDC+JTAG | ||||
|     CLEAR_PERI_REG_MASK(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL|RTC_CNTL_USB_PAD_ENABLE)); | ||||
|  | ||||
|     // Do not use external PHY | ||||
|     CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL); | ||||
|  | ||||
|     // Release GPIO pins from  CDC+JTAG | ||||
|     CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); | ||||
|  | ||||
|     // Force the host to re-enumerate (BUS_RESET) | ||||
|     pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN); | ||||
|     pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN); | ||||
|     digitalWrite(USBPHY_DM_NUM, LOW); | ||||
|     digitalWrite(USBPHY_DP_NUM, LOW); | ||||
|  | ||||
|     // Initialize CDC+JTAG ISR to listen for BUS_RESET | ||||
|     usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|     usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|     usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_BUS_RESET); | ||||
|     intr_handle_t intr_handle = NULL; | ||||
|     xSemaphoreHandle reset_sem = xSemaphoreCreateBinary(); | ||||
|     if(reset_sem){ | ||||
|         if(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_reset_handler, reset_sem, &intr_handle) != ESP_OK){ | ||||
|             vSemaphoreDelete(reset_sem); | ||||
|             reset_sem = NULL; | ||||
|             log_e("HW USB CDC failed to init interrupts"); | ||||
|         } | ||||
|     } else { | ||||
|         log_e("reset_sem init failed"); | ||||
|     } | ||||
|  | ||||
|     // Connect GPIOs to integrated CDC+JTAG | ||||
|     SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); | ||||
|  | ||||
|     // Wait for BUS_RESET to give us back the semaphore | ||||
|     if(reset_sem){ | ||||
|         if(xSemaphoreTake(reset_sem, 1000 / portTICK_PERIOD_MS) != pdPASS){ | ||||
|             log_e("reset_sem timeout"); | ||||
|         } | ||||
|         usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); | ||||
|         esp_intr_free(intr_handle); | ||||
|         vSemaphoreDelete(reset_sem); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void IRAM_ATTR usb_persist_shutdown_handler(void) | ||||
| { | ||||
|     if(usb_persist_mode != RESTART_NO_PERSIST){ | ||||
|         if (usb_persist_enabled) { | ||||
|             usb_dc_prepare_persist(); | ||||
|         } | ||||
|         if (usb_persist_mode == RESTART_BOOTLOADER) { | ||||
|             //USB CDC Download | ||||
|             if (usb_persist_enabled) { | ||||
|                 chip_usb_set_persist_flags(USBDC_PERSIST_ENA); | ||||
| #if CONFIG_IDF_TARGET_ESP32S2 | ||||
|             } else { | ||||
|                 periph_module_reset(PERIPH_USB_MODULE); | ||||
|                 periph_module_enable(PERIPH_USB_MODULE); | ||||
| #endif | ||||
|             } | ||||
|             REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); | ||||
|         } else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) { | ||||
|             //DFU Download | ||||
| #if CONFIG_IDF_TARGET_ESP32S2 | ||||
|             // Reset USB Core | ||||
|             USB0.grstctl |= USB_CSFTRST; | ||||
|             while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){} | ||||
| #endif | ||||
|             chip_usb_set_persist_flags(USBDC_BOOT_DFU); | ||||
|             REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); | ||||
|         } else if (usb_persist_enabled) { | ||||
|             //USB Persist reboot | ||||
|             chip_usb_set_persist_flags(USBDC_PERSIST_ENA); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void usb_persist_restart(restart_type_t mode) | ||||
| { | ||||
|     if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) { | ||||
|         usb_persist_mode = mode; | ||||
| #if CONFIG_IDF_TARGET_ESP32S3 | ||||
|         if (mode == RESTART_BOOTLOADER) { | ||||
|             usb_switch_to_cdc_jtag(); | ||||
|         } | ||||
| #endif | ||||
|         esp_restart(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){ | ||||
|     if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){ | ||||
|         return false; | ||||
|     } | ||||
|     tinyusb_endpoints.in |= BIT(endpoint); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool tinyusb_reserve_out_endpoint(uint8_t endpoint){ | ||||
|     if(endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0){ | ||||
|         return false; | ||||
|     } | ||||
|     tinyusb_endpoints.out |= BIT(endpoint); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static bool tinyusb_has_available_fifos(void){ | ||||
|     uint8_t max_endpoints = 4, active_endpoints = 0; | ||||
|     if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) { | ||||
|         max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used | ||||
|     } | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.in & BIT(i)) != 0){ | ||||
|             active_endpoints++; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return active_endpoints < max_endpoints; | ||||
| } | ||||
|  | ||||
| static uint16_t tinyusb_load_descriptor(tinyusb_interface_t interface, uint8_t * dst, uint8_t * itf) | ||||
| { | ||||
|     if(tinyusb_loaded_interfaces_callbacks[interface]){ | ||||
|         return tinyusb_loaded_interfaces_callbacks[interface](dst, itf); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static bool tinyusb_load_enabled_interfaces(){ | ||||
|     tinyusb_config_descriptor_len += TUD_CONFIG_DESC_LEN; | ||||
|     tinyusb_config_descriptor = (uint8_t *)malloc(tinyusb_config_descriptor_len); | ||||
|     if (tinyusb_config_descriptor == NULL) { | ||||
|         log_e("Descriptor Malloc Failed"); | ||||
|         return false; | ||||
|     } | ||||
|     uint8_t * dst = tinyusb_config_descriptor + TUD_CONFIG_DESC_LEN; | ||||
|  | ||||
|     for(int i=0; i<USB_INTERFACE_MAX; i++){ | ||||
|         if (tinyusb_loaded_interfaces_mask & (1U << i)) { | ||||
|             uint16_t len = tinyusb_load_descriptor((tinyusb_interface_t)i, dst, &tinyusb_loaded_interfaces_num); | ||||
|             if (!len) { | ||||
|                 log_e("Descriptor Load Failed"); | ||||
|                 return false; | ||||
|             } else { | ||||
|                 dst += len; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Device"); | ||||
|     uint8_t descriptor[TUD_CONFIG_DESC_LEN] = { | ||||
|             //num configs, interface count, string index, total length, attribute, power in mA | ||||
|             TUD_CONFIG_DESCRIPTOR(1, tinyusb_loaded_interfaces_num, str_index, tinyusb_config_descriptor_len, USB_DEVICE_ATTRIBUTES, USB_DEVICE_POWER) | ||||
|     }; | ||||
|     memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN); | ||||
|     if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) { | ||||
|         //usb_persist_enabled = true; | ||||
|         //log_d("USB Persist enabled"); | ||||
|     } | ||||
|     log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask); | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static inline char nibble_to_hex_char(uint8_t b) | ||||
| { | ||||
|     if (b < 0xa) { | ||||
|         return '0' + b; | ||||
|     } else { | ||||
|         return 'a' + b - 0xa; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void set_usb_serial_num(void) | ||||
| { | ||||
|     /* Get the MAC address */ | ||||
|     const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0); | ||||
|     const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1); | ||||
|     uint8_t mac_bytes[6]; | ||||
|     memcpy(mac_bytes, &mac0, 4); | ||||
|     memcpy(mac_bytes + 4, &mac1, 2); | ||||
|  | ||||
|     /* Convert to UTF16 string */ | ||||
|     uint8_t* srl = (uint8_t*)USB_DEVICE_SERIAL; | ||||
|     for (int i = 0; i < 6; ++i) { | ||||
|         uint8_t b = mac_bytes[5 - i]; /* printing from the MSB */ | ||||
|         if (i) { | ||||
|             *srl++ = ':'; | ||||
|         } | ||||
|         *srl++ = nibble_to_hex_char(b >> 4); | ||||
|         *srl++ = nibble_to_hex_char(b & 0xf); | ||||
|     } | ||||
|     *srl++ = '\0'; | ||||
| } | ||||
|  | ||||
| static void tinyusb_apply_device_config(tinyusb_device_config_t *config){ | ||||
|     if(config->product_name){ | ||||
|         snprintf(USB_DEVICE_PRODUCT, 126, "%s", config->product_name); | ||||
|     } | ||||
|      | ||||
|     if(config->manufacturer_name){ | ||||
|         snprintf(USB_DEVICE_MANUFACTURER, 126, "%s", config->manufacturer_name); | ||||
|     } | ||||
|      | ||||
|     if(config->serial_number && config->serial_number[0]){ | ||||
|         snprintf(USB_DEVICE_SERIAL, 126, "%s", config->serial_number); | ||||
|     } else { | ||||
|         set_usb_serial_num(); | ||||
|     } | ||||
|      | ||||
|     if(config->webusb_url){ | ||||
|         snprintf(WEBUSB_URL, 126, "%s", config->webusb_url); | ||||
|     } | ||||
|  | ||||
|     // Windows 10 will not recognize the CDC device if WebUSB is enabled and USB Class is not 2 (CDC) | ||||
|     if( | ||||
|         (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC))  | ||||
|         && config->webusb_enabled  | ||||
|         && (config->usb_class != TUSB_CLASS_CDC) | ||||
|     ){ | ||||
|         config->usb_class = TUSB_CLASS_CDC; | ||||
|         config->usb_protocol = 0x00; | ||||
|     } | ||||
|  | ||||
|     WEBUSB_ENABLED            = config->webusb_enabled; | ||||
|     USB_DEVICE_ATTRIBUTES     = config->usb_attributes; | ||||
|     USB_DEVICE_POWER          = config->usb_power_ma; | ||||
|      | ||||
|     tinyusb_device_descriptor.bcdUSB = config->usb_version; | ||||
|     tinyusb_device_descriptor.idVendor = config->vid; | ||||
|     tinyusb_device_descriptor.idProduct = config->pid; | ||||
|     tinyusb_device_descriptor.bcdDevice = config->fw_version; | ||||
|     tinyusb_device_descriptor.bDeviceClass = config->usb_class; | ||||
|     tinyusb_device_descriptor.bDeviceSubClass = config->usb_subclass; | ||||
|     tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol; | ||||
| } | ||||
|  | ||||
| // USB Device Driver task | ||||
| // This top level thread processes all usb events and invokes callbacks | ||||
| static void usb_device_task(void *param) { | ||||
|     (void)param; | ||||
|     while(1) tud_task(); // RTOS forever loop | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * PUBLIC API | ||||
|  * */ | ||||
| #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR | ||||
|     const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"}; | ||||
| #endif | ||||
| static bool tinyusb_is_initialized = false; | ||||
|  | ||||
| esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb) | ||||
| { | ||||
|     if(tinyusb_is_initialized){ | ||||
|         log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){ | ||||
|         log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|     if(interface == USB_INTERFACE_CDC){ | ||||
|         if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){ | ||||
|             log_e("CDC Reserve Endpoints Failed"); | ||||
|             return ESP_FAIL; | ||||
|         } | ||||
|     } | ||||
|     tinyusb_loaded_interfaces_mask |= (1U << interface); | ||||
|     tinyusb_config_descriptor_len += descriptor_len; | ||||
|     tinyusb_loaded_interfaces_callbacks[interface] = cb; | ||||
|     log_d("Interface %s enabled", tinyusb_interface_names[interface]); | ||||
|     return ESP_OK; | ||||
| } | ||||
|  | ||||
| esp_err_t tinyusb_init(tinyusb_device_config_t *config) { | ||||
|     if(tinyusb_is_initialized){ | ||||
|         return ESP_OK; | ||||
|     } | ||||
|     tinyusb_is_initialized = true; | ||||
|      | ||||
|     //tinyusb_endpoints.val = 0; | ||||
|     tinyusb_apply_device_config(config); | ||||
|     if (!tinyusb_load_enabled_interfaces()) { | ||||
|         tinyusb_is_initialized = false; | ||||
|         return ESP_FAIL; | ||||
|     } | ||||
|  | ||||
|     bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA); | ||||
|  | ||||
|     //if(usb_did_persist && usb_persist_enabled){ | ||||
|         // Enable USB/IO_MUX peripheral reset, if coming from persistent reboot | ||||
|         REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE); | ||||
|         REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE); | ||||
|     //} else  | ||||
|     if(!usb_did_persist || !usb_persist_enabled){ | ||||
|         // Reset USB module | ||||
|         periph_module_reset(PERIPH_USB_MODULE); | ||||
|         periph_module_enable(PERIPH_USB_MODULE); | ||||
|     } | ||||
|  | ||||
|     tinyusb_config_t tusb_cfg = { | ||||
|             .external_phy = false // In the most cases you need to use a `false` value | ||||
|     }; | ||||
|     esp_err_t err = tinyusb_driver_install(&tusb_cfg); | ||||
|     if (err != ESP_OK) { | ||||
|         tinyusb_is_initialized = false; | ||||
|         return err; | ||||
|     } | ||||
|     xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| uint8_t tinyusb_add_string_descriptor(const char * str){ | ||||
|     if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){ | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t index = tinyusb_string_descriptor_len; | ||||
|     tinyusb_string_descriptor[tinyusb_string_descriptor_len++] = (char*)str; | ||||
|     return index; | ||||
| } | ||||
|  | ||||
| uint8_t tinyusb_get_free_duplex_endpoint(void){ | ||||
|     if(!tinyusb_has_available_fifos()){ | ||||
|         log_e("No available IN endpoints"); | ||||
|         return 0; | ||||
|     } | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0){ | ||||
|             tinyusb_endpoints.in |= BIT(i); | ||||
|             tinyusb_endpoints.out |= BIT(i); | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     log_e("No available duplex endpoints"); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| uint8_t tinyusb_get_free_in_endpoint(void){ | ||||
|     if(!tinyusb_has_available_fifos()){ | ||||
|         log_e("No available IN endpoints"); | ||||
|         return 0; | ||||
|     } | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0){ | ||||
|             tinyusb_endpoints.in |= BIT(i); | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.in & BIT(i)) == 0){ | ||||
|             tinyusb_endpoints.in |= BIT(i); | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| uint8_t tinyusb_get_free_out_endpoint(void){ | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0){ | ||||
|             tinyusb_endpoints.out |= BIT(i); | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     for(uint8_t i=1; i<7; i++){ | ||||
|         if((tinyusb_endpoints.out & BIT(i)) == 0){ | ||||
|             tinyusb_endpoints.out |= BIT(i); | ||||
|             return i; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_ENABLED */ | ||||
							
								
								
									
										106
									
								
								cores/esp32/esp32-hal-tinyusb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								cores/esp32/esp32-hal-tinyusb.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
|  | ||||
| #include "esp32-hal.h" | ||||
|  | ||||
| #if CONFIG_TINYUSB_ENABLED | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "tusb.h" | ||||
| #include "tusb_option.h" | ||||
| #include "tusb_config.h" | ||||
|  | ||||
| #define USB_ESPRESSIF_VID 0x303A | ||||
| #define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10 | ||||
|  | ||||
| typedef struct { | ||||
|         uint16_t vid; | ||||
|         uint16_t pid; | ||||
|         const char * product_name; | ||||
|         const char * manufacturer_name; | ||||
|         const char * serial_number; | ||||
|         uint16_t fw_version; | ||||
|          | ||||
|         uint16_t usb_version; | ||||
|         uint8_t usb_class; | ||||
|         uint8_t usb_subclass; | ||||
|         uint8_t usb_protocol; | ||||
|         uint8_t usb_attributes; | ||||
|         uint16_t usb_power_ma; | ||||
|          | ||||
|         bool webusb_enabled; | ||||
|         const char * webusb_url; | ||||
| } tinyusb_device_config_t; | ||||
|  | ||||
| #define TINYUSB_CONFIG_DEFAULT() {                                      \ | ||||
|         .vid = USB_ESPRESSIF_VID,                                       \ | ||||
|         .pid = 0x0002,                                                  \ | ||||
|         .product_name = CONFIG_TINYUSB_DESC_PRODUCT_STRING,                 \ | ||||
|         .manufacturer_name = CONFIG_TINYUSB_DESC_MANUFACTURER_STRING,       \ | ||||
|         .serial_number = CONFIG_TINYUSB_DESC_SERIAL_STRING,                 \ | ||||
|         .fw_version = CONFIG_TINYUSB_DESC_BCDDEVICE,                        \ | ||||
|         .usb_version = 0x0200,                                          \ | ||||
|         .usb_class = TUSB_CLASS_MISC,                                   \ | ||||
|         .usb_subclass = MISC_SUBCLASS_COMMON,                           \ | ||||
|         .usb_protocol = MISC_PROTOCOL_IAD,                              \ | ||||
|         .usb_attributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED,            \ | ||||
|         .usb_power_ma = 500,                                            \ | ||||
|         .webusb_enabled = false,                                        \ | ||||
|         .webusb_url = "espressif.github.io/arduino-esp32/webusb.html"   \ | ||||
| } | ||||
|  | ||||
| esp_err_t tinyusb_init(tinyusb_device_config_t *config); | ||||
|  | ||||
| /* | ||||
|  * USB Persistence API | ||||
|  * */ | ||||
| typedef enum { | ||||
|     RESTART_NO_PERSIST, | ||||
|     RESTART_PERSIST, | ||||
|     RESTART_BOOTLOADER, | ||||
|     RESTART_BOOTLOADER_DFU, | ||||
|     RESTART_TYPE_MAX | ||||
| } restart_type_t; | ||||
|  | ||||
| void usb_persist_restart(restart_type_t mode); | ||||
|  | ||||
| // The following definitions and functions are to be used only by the drivers | ||||
| typedef enum { | ||||
|     USB_INTERFACE_MSC, | ||||
|     USB_INTERFACE_DFU, | ||||
|     USB_INTERFACE_HID, | ||||
|     USB_INTERFACE_VENDOR, | ||||
|     USB_INTERFACE_CDC, | ||||
|     USB_INTERFACE_MIDI, | ||||
|     USB_INTERFACE_CUSTOM, | ||||
|     USB_INTERFACE_MAX | ||||
| } tinyusb_interface_t; | ||||
|  | ||||
| typedef uint16_t (*tinyusb_descriptor_cb_t)(uint8_t * dst, uint8_t * itf); | ||||
|  | ||||
| esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb); | ||||
| uint8_t tinyusb_add_string_descriptor(const char * str); | ||||
| uint8_t tinyusb_get_free_duplex_endpoint(void); | ||||
| uint8_t tinyusb_get_free_in_endpoint(void); | ||||
| uint8_t tinyusb_get_free_out_endpoint(void); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* CONFIG_TINYUSB_ENABLED */ | ||||
							
								
								
									
										273
									
								
								cores/esp32/esp32-hal-touch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								cores/esp32/esp32-hal-touch.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| // 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 "soc/soc_caps.h" | ||||
| #if SOC_TOUCH_SENSOR_NUM > 0 | ||||
|  | ||||
| #include "driver/touch_sensor.h" | ||||
| #include "esp32-hal-touch.h" | ||||
|  | ||||
| /* | ||||
|     Internal Private Touch Data Structure and Functions | ||||
| */ | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1         // ESP32  | ||||
| static uint16_t __touchSleepCycles = 0x1000; | ||||
| static uint16_t __touchMeasureCycles = 0x1000; | ||||
| #elif SOC_TOUCH_VERSION_2       // ESP32S2, ESP32S3 | ||||
| static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT; | ||||
| static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT; | ||||
| #endif | ||||
|  | ||||
| typedef void (*voidFuncPtr)(void); | ||||
| typedef void (*voidArgFuncPtr)(void *); | ||||
|  | ||||
| typedef struct { | ||||
|     voidFuncPtr fn; | ||||
|     bool callWithArgs; | ||||
|     void* arg; | ||||
| #if SOC_TOUCH_VERSION_2     // Only for ESP32S2 and ESP32S3 | ||||
|     bool lastStatusIsPressed; | ||||
| #endif | ||||
| } TouchInterruptHandle_t; | ||||
|  | ||||
| static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = {0,}; | ||||
|  | ||||
| static void ARDUINO_ISR_ATTR __touchISR(void * arg) | ||||
| { | ||||
| #if SOC_TOUCH_VERSION_1         // ESP32  | ||||
|     uint32_t pad_intr = touch_pad_get_status(); | ||||
|     //clear interrupt | ||||
|     touch_pad_clear_status(); | ||||
|     // call Pad ISR User callback | ||||
|     for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { | ||||
|         if ((pad_intr >> i) & 0x01) { | ||||
|             if(__touchInterruptHandlers[i].fn){ | ||||
|                 // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)" | ||||
|                 if (__touchInterruptHandlers[i].callWithArgs) { | ||||
|                     ((voidArgFuncPtr)__touchInterruptHandlers[i].fn)(__touchInterruptHandlers[i].arg); | ||||
|                 } else { | ||||
|                     __touchInterruptHandlers[i].fn(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| #elif SOC_TOUCH_VERSION_2     // ESP32S2, ESP32S3 | ||||
|     touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask(); | ||||
|     uint8_t pad_num = touch_pad_get_current_meas_channel(); | ||||
|     if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) { | ||||
|         // touch has been pressed / touched | ||||
|         __touchInterruptHandlers[pad_num].lastStatusIsPressed = true; | ||||
|     } | ||||
|     if (evt & TOUCH_PAD_INTR_MASK_INACTIVE) { | ||||
|         // touch has been released / untouched | ||||
|         __touchInterruptHandlers[pad_num].lastStatusIsPressed = false; | ||||
|     } | ||||
|     if(__touchInterruptHandlers[pad_num].fn){ | ||||
|         // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)" | ||||
|         if (__touchInterruptHandlers[pad_num].callWithArgs) { | ||||
|             ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg); | ||||
|         } else { | ||||
|             __touchInterruptHandlers[pad_num].fn(); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void __touchSetCycles(uint16_t measure, uint16_t sleep) | ||||
| { | ||||
|     __touchSleepCycles = sleep; | ||||
|     __touchMeasureCycles = measure; | ||||
|     touch_pad_set_meas_time(sleep, measure); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| static void __touchInit() | ||||
| { | ||||
|     static bool initialized = false; | ||||
|     if(initialized){ | ||||
|         return; | ||||
|     } | ||||
|   | ||||
|    esp_err_t err = ESP_OK; | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1                         // ESP32 | ||||
|     err = touch_pad_init(); | ||||
|     if (err != ESP_OK) { | ||||
|         goto err; | ||||
|     } | ||||
|     // the next two lines will drive the touch reading values -- both will return ESP_OK | ||||
|     touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);  | ||||
|     touch_pad_set_meas_time(__touchMeasureCycles, __touchSleepCycles); | ||||
|     // Touch Sensor Timer initiated | ||||
|     touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);   // returns ESP_OK | ||||
|     err = touch_pad_filter_start(10); | ||||
|     if (err != ESP_OK) { | ||||
|         goto err; | ||||
|     } | ||||
|     // keep ISR activated - it can run all together (ISR + touchRead()) | ||||
|     err = touch_pad_isr_register(__touchISR, NULL); | ||||
|     if (err != ESP_OK) { | ||||
|         goto err; | ||||
|     } | ||||
|     touch_pad_intr_enable();  // returns ESP_OK | ||||
| #elif SOC_TOUCH_VERSION_2                         // ESP32S2, ESP32S3 | ||||
|     err = touch_pad_init(); | ||||
|     if (err != ESP_OK) { | ||||
|         goto err; | ||||
|     } | ||||
|     // the next lines will drive the touch reading values -- all os them return ESP_OK | ||||
|     touch_pad_set_meas_time(__touchSleepCycles, __touchMeasureCycles); | ||||
|     touch_pad_set_voltage(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD, TOUCH_PAD_LOW_VOLTAGE_THRESHOLD, TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD); | ||||
|     touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT); | ||||
|     touch_pad_denoise_t denoise = { | ||||
|         .grade = TOUCH_PAD_DENOISE_BIT4, | ||||
|         .cap_level = TOUCH_PAD_DENOISE_CAP_L4, | ||||
|     }; | ||||
|     touch_pad_denoise_set_config(&denoise); | ||||
|     touch_pad_denoise_enable(); | ||||
|     // Touch Sensor Timer initiated | ||||
|     touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);  // returns ESP_OK | ||||
|     touch_pad_fsm_start();                         // returns ESP_OK | ||||
|     //ISR setup moved to __touchChannelInit | ||||
| #endif | ||||
|  | ||||
|     initialized = true; | ||||
|     return; | ||||
| err: | ||||
|     log_e(" Touch sensor initialization error."); | ||||
|     initialized = false; | ||||
|     return; | ||||
| } | ||||
|  | ||||
| static void __touchChannelInit(int pad) | ||||
| { | ||||
|    static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false }; | ||||
|        if(channels_initialized[pad]){ | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1                         // ESP32 | ||||
|     // Initial no Threshold and setup | ||||
|     __touchInterruptHandlers[pad].fn =  NULL; | ||||
|     touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX);  // returns ESP_OK | ||||
| #elif SOC_TOUCH_VERSION_2                       // ESP32S2, ESP32S3 | ||||
|     // Initial no Threshold and setup | ||||
|     __touchInterruptHandlers[pad].fn =  NULL; | ||||
|     touch_pad_config(pad);                       // returns ESP_OK | ||||
|     // keep ISR activated - it can run all together (ISR + touchRead()) | ||||
|     esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); | ||||
|     if (err != ESP_OK) { | ||||
|         log_e(" Touch sensor initialization error."); | ||||
|         return; | ||||
|     } | ||||
|     touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK | ||||
| #endif | ||||
|  | ||||
|     channels_initialized[pad] = true; | ||||
|     delay(20);  //delay needed before reading from touch channel after config | ||||
| } | ||||
|  | ||||
| static touch_value_t __touchRead(uint8_t pin) | ||||
| { | ||||
|     int8_t pad = digitalPinToTouchChannel(pin); | ||||
|     if(pad < 0){ | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     __touchInit(); | ||||
|     __touchChannelInit(pad); | ||||
|  | ||||
|     touch_value_t touch_value; | ||||
|     touch_pad_read_raw_data(pad, &touch_value); | ||||
|  | ||||
|     return touch_value; | ||||
| } | ||||
|  | ||||
| static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, touch_value_t threshold, bool callWithArgs) | ||||
| { | ||||
|     int8_t pad = digitalPinToTouchChannel(pin); | ||||
|     if(pad < 0){ | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (userFunc == NULL) { | ||||
|         // dettach ISR User Call | ||||
|         __touchInterruptHandlers[pad].fn = NULL; | ||||
|         threshold = SOC_TOUCH_PAD_THRESHOLD_MAX;   // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX | ||||
|     } else { | ||||
|         // attach ISR User Call | ||||
|         __touchInit(); | ||||
|         __touchChannelInit(pad); | ||||
|         __touchInterruptHandlers[pad].fn = userFunc; | ||||
|         __touchInterruptHandlers[pad].callWithArgs = callWithArgs; | ||||
|         __touchInterruptHandlers[pad].arg = Args; | ||||
|     } | ||||
|  | ||||
|     touch_pad_set_thresh(pad, threshold); | ||||
| } | ||||
|  | ||||
| // it keeps backwards compatibility | ||||
| static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold) | ||||
| { | ||||
|     __touchConfigInterrupt(pin, userFunc, NULL, threshold, false); | ||||
| } | ||||
|  | ||||
| // new additional version of the API with User Args | ||||
| static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold) | ||||
| { | ||||
|     __touchConfigInterrupt(pin, userFunc, args, threshold, true); | ||||
| } | ||||
|  | ||||
| // new additional API to dettach touch ISR | ||||
| static void __touchDettachInterrupt(uint8_t pin) | ||||
| { | ||||
|     __touchConfigInterrupt(pin, NULL, NULL, 0, false);  // userFunc as NULL acts as dettaching  | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|     External Public Touch API Functions | ||||
| */ | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1        // Only for ESP32 SoC | ||||
| void touchInterruptSetThresholdDirection(bool mustbeLower) { | ||||
|     if (mustbeLower) { | ||||
|         touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW); | ||||
|     } else { | ||||
|         touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE); | ||||
|     } | ||||
| } | ||||
| #elif SOC_TOUCH_VERSION_2     // Only for ESP32S2 and ESP32S3 | ||||
| // returns true if touch pad has been and continues pressed and false otherwise  | ||||
| bool touchInterruptGetLastStatus(uint8_t pin) { | ||||
|     int8_t pad = digitalPinToTouchChannel(pin); | ||||
|     if(pad < 0){ | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     return __touchInterruptHandlers[pad].lastStatusIsPressed; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| extern touch_value_t touchRead(uint8_t) __attribute__ ((weak, alias("__touchRead"))); | ||||
| extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__ ((weak, alias("__touchAttachInterrupt"))); | ||||
| extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__ ((weak, alias("__touchAttachArgsInterrupt"))); | ||||
| extern void touchDetachInterrupt(uint8_t) __attribute__ ((weak, alias("__touchDettachInterrupt"))); | ||||
| extern void touchSetCycles(uint16_t, uint16_t) __attribute__ ((weak, alias("__touchSetCycles"))); | ||||
|  | ||||
| #endif      // #if SOC_TOUCH_SENSOR_NUM > 0 | ||||
							
								
								
									
										96
									
								
								cores/esp32/esp32-hal-touch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								cores/esp32/esp32-hal-touch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  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 "soc/soc_caps.h" | ||||
| #include "esp32-hal.h" | ||||
|  | ||||
| #if SOC_TOUCH_SENSOR_NUM > 0 | ||||
|  | ||||
| #if !defined(SOC_TOUCH_VERSION_1) && !defined(SOC_TOUCH_VERSION_2) | ||||
| #error Touch IDF driver Not supported! | ||||
| #endif | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1 // ESP32 | ||||
| typedef uint16_t touch_value_t; | ||||
| #elif SOC_TOUCH_VERSION_2 // ESP32S2 ESP32S3 | ||||
| typedef uint32_t touch_value_t; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
|  * */ | ||||
| touch_value_t touchRead(uint8_t pin); | ||||
|  | ||||
| /* | ||||
|  * Set function to be called if touch pad value falls (ESP32) | ||||
|  * below the given threshold / rises (ESP32-S2/S3) by given increment (threshold).  | ||||
|  * Use touchRead to determine a proper threshold between touched and untouched state | ||||
|  * */ | ||||
| void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold); | ||||
| void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void*), void *arg, touch_value_t threshold); | ||||
| void touchDetachInterrupt(uint8_t pin); | ||||
|  | ||||
| /* | ||||
|  * Specific functions to ESP32  | ||||
|  * Tells the driver if it shall activate the ISR if the sensor is Lower or Higher than the Threshold | ||||
|  * Default if Lower. | ||||
|  **/ | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_1     // Only for ESP32 SoC | ||||
| void touchInterruptSetThresholdDirection(bool mustbeLower); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Specific functions to ESP32-S2 and ESP32-S3 | ||||
|  * Returns true when the latest ISR status for the Touchpad is that it is touched (Active) | ||||
|  * and false when the Touchpad is untoouched (Inactive) | ||||
|  * This function can be used in conjunction with ISR User callback in order to take action  | ||||
|  * as soon as the touchpad is touched and/or released | ||||
|  **/ | ||||
|  | ||||
| #if SOC_TOUCH_VERSION_2     // Only for ESP32S2 and ESP32S3 | ||||
| // returns true if touch pad has been and continues pressed and false otherwise  | ||||
| bool touchInterruptGetLastStatus(uint8_t pin); | ||||
| #endif | ||||
|  | ||||
| #endif // SOC_TOUCH_SENSOR_NUM > 0 | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| #endif /* MAIN_ESP32_HAL_TOUCH_H_ */ | ||||
							
								
								
									
										666
									
								
								cores/esp32/esp32-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										666
									
								
								cores/esp32/esp32-hal-uart.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,666 @@ | ||||
| // 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/semphr.h" | ||||
|  | ||||
| #include "driver/uart.h" | ||||
| #include "hal/uart_ll.h" | ||||
| #include "soc/soc_caps.h" | ||||
| #include "soc/uart_struct.h" | ||||
|  | ||||
| static int s_uart_debug_nr = 0; | ||||
|  | ||||
| struct uart_struct_t { | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     xSemaphoreHandle lock; | ||||
| #endif | ||||
|  | ||||
|     uint8_t num; | ||||
|     bool has_peek; | ||||
|     uint8_t peek_byte; | ||||
|     QueueHandle_t uart_event_queue;   // export it by some uartGetEventQueue() function | ||||
| }; | ||||
|  | ||||
| #if CONFIG_DISABLE_HAL_LOCKS | ||||
|  | ||||
| #define UART_MUTEX_LOCK() | ||||
| #define UART_MUTEX_UNLOCK() | ||||
|  | ||||
| static uart_t _uart_bus_array[] = { | ||||
|     {0, false, 0, NULL}, | ||||
| #if SOC_UART_NUM > 1 | ||||
|     {1, false, 0, NULL}, | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
|     {2, false, 0, NULL}, | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #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[] = { | ||||
|     {NULL, 0, false, 0, NULL}, | ||||
| #if SOC_UART_NUM > 1 | ||||
|     {NULL, 1, false, 0, NULL}, | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
|     {NULL, 2, false, 0, NULL}, | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| // solves issue https://github.com/espressif/arduino-esp32/issues/6032 | ||||
| // baudrate must be multiplied when CPU Frequency is lower than APB 80MHz | ||||
| uint32_t _get_effective_baudrate(uint32_t baudrate)  | ||||
| { | ||||
|     uint32_t Freq = getApbFrequency()/1000000; | ||||
|     if (Freq < 80) { | ||||
|         return 80 / Freq * baudrate; | ||||
|      } | ||||
|     else { | ||||
|         return baudrate; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Routines that take care of UART events will be in the HardwareSerial Class code | ||||
| void uartGetEventQueue(uart_t* uart, QueueHandle_t *q) | ||||
| { | ||||
|     // passing back NULL for the Queue pointer when UART is not initialized yet | ||||
|     *q = NULL; | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     *q = uart->uart_event_queue; | ||||
|     return; | ||||
| } | ||||
|  | ||||
| bool uartIsDriverInstalled(uart_t* uart)  | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     if (uart_is_driver_installed(uart->num)) { | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| // Valid pin UART_PIN_NO_CHANGE is defined to (-1) | ||||
| // Negative Pin Number will keep it unmodified, thus this function can set individual pins | ||||
| void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     UART_MUTEX_LOCK(); | ||||
|     // IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation. | ||||
|     uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin);  | ||||
|     UART_MUTEX_UNLOCK();   | ||||
| } | ||||
|  | ||||
| //  | ||||
| void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     // IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing | ||||
|     // IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) | ||||
|     uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold); | ||||
| } | ||||
|  | ||||
|  | ||||
| uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd) | ||||
| { | ||||
|     if(uart_nr >= SOC_UART_NUM) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     uart_t* uart = &_uart_bus_array[uart_nr]; | ||||
|  | ||||
|     if (uart_is_driver_installed(uart_nr)) { | ||||
|         uartEnd(uart); | ||||
|     } | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(uart->lock == NULL) { | ||||
|         uart->lock = xSemaphoreCreateMutex(); | ||||
|         if(uart->lock == NULL) { | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|  | ||||
|     uart_config_t uart_config; | ||||
|     uart_config.baud_rate = _get_effective_baudrate(baudrate); | ||||
|     uart_config.data_bits = (config & 0xc) >> 2; | ||||
|     uart_config.parity = (config & 0x3); | ||||
|     uart_config.stop_bits = (config & 0x30) >> 4; | ||||
|     uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; | ||||
|     uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd; | ||||
|     uart_config.source_clk = UART_SCLK_APB; | ||||
|  | ||||
|     ESP_ERROR_CHECK(uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0)); | ||||
|     ESP_ERROR_CHECK(uart_param_config(uart_nr, &uart_config)); | ||||
|     ESP_ERROR_CHECK(uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); | ||||
|  | ||||
|     // Is it right or the idea is to swap rx and tx pins?  | ||||
|     if (inverted) { | ||||
|         // invert signal for both Rx and Tx | ||||
|         ESP_ERROR_CHECK(uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV));     | ||||
|     } | ||||
|      | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|  | ||||
|     uartFlush(uart); | ||||
|     return uart; | ||||
| } | ||||
|  | ||||
| // This code is under testing - for now just keep it here | ||||
| void uartSetFastReading(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     // override default RX IDF Driver Interrupt - no BREAK, PARITY or OVERFLOW | ||||
|     uart_intr_config_t uart_intr = { | ||||
|         .intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT,   // only these IRQs - no BREAK, PARITY or OVERFLOW | ||||
|         .rx_timeout_thresh = 1, | ||||
|         .txfifo_empty_intr_thresh = 10, | ||||
|         .rxfifo_full_thresh = 2, | ||||
|     }; | ||||
|  | ||||
|     ESP_ERROR_CHECK(uart_intr_config(uart->num, &uart_intr)); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_set_rx_timeout(uart->num, numSymbTimeout); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_set_rx_full_threshold(uart->num, numBytesFIFOFull); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void uartEnd(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_driver_delete(uart->num); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void uartSetRxInvert(uart_t* uart, bool invert) | ||||
| { | ||||
|     if (uart == NULL) | ||||
|         return; | ||||
| #if 0 | ||||
|     // POTENTIAL ISSUE :: original code only set/reset rxd_inv bit  | ||||
|     // IDF or LL set/reset the whole inv_mask! | ||||
|     if (invert) | ||||
|         ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV)); | ||||
|     else | ||||
|         ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE)); | ||||
|      | ||||
| #else | ||||
|     // this implementation is better over IDF API because it only affects RXD | ||||
|     // this is supported in ESP32, ESP32-S2 and ESP32-C3 | ||||
|     uart_dev_t *hw = UART_LL_GET_HW(uart->num); | ||||
|     if (invert) | ||||
|         hw->conf0.rxd_inv = 1; | ||||
|     else | ||||
|         hw->conf0.rxd_inv = 0; | ||||
| #endif  | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t uartAvailable(uart_t* uart) | ||||
| { | ||||
|  | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     size_t available; | ||||
|     uart_get_buffered_data_len(uart->num, &available); | ||||
|     if (uart->has_peek) available++; | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|     return available; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint32_t uartAvailableForWrite(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uint32_t available =  uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));   | ||||
|     size_t txRingBufferAvailable = 0; | ||||
|     if (ESP_OK == uart_get_tx_buffer_free_size(uart->num, &txRingBufferAvailable)) { | ||||
|         available += txRingBufferAvailable;  | ||||
|     } | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|     return available; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint8_t uartRead(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|  | ||||
|     if (uart->has_peek) { | ||||
|       uart->has_peek = false; | ||||
|       c = uart->peek_byte; | ||||
|     } else { | ||||
|  | ||||
|         int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS); | ||||
|         if (len == 0) { | ||||
|             c  = 0; | ||||
|         } | ||||
|     } | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|     return c; | ||||
| } | ||||
|  | ||||
| uint8_t uartPeek(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     uint8_t c = 0; | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|  | ||||
|     if (uart->has_peek) { | ||||
|       c = uart->peek_byte; | ||||
|     } else { | ||||
|         int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS); | ||||
|         if (len == 0) { | ||||
|             c  = 0; | ||||
|         } else { | ||||
|             uart->has_peek = true; | ||||
|             uart->peek_byte = c; | ||||
|         } | ||||
|     } | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|     return c; | ||||
| } | ||||
|  | ||||
| void uartWrite(uart_t* uart, uint8_t c) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_write_bytes(uart->num, &c, 1); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len) | ||||
| { | ||||
|     if(uart == NULL || data == NULL || !len) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_write_bytes(uart->num, data, len); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void uartFlush(uart_t* uart) | ||||
| { | ||||
|     uartFlushTxOnly(uart, true); | ||||
| } | ||||
|  | ||||
| void uartFlushTxOnly(uart_t* uart, bool txOnly) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     UART_MUTEX_LOCK(); | ||||
|     while(!uart_ll_is_tx_idle(UART_LL_GET_HW(uart->num))); | ||||
|  | ||||
|     if ( !txOnly ) { | ||||
|         ESP_ERROR_CHECK(uart_flush_input(uart->num)); | ||||
|     } | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void uartSetBaudRate(uart_t* uart, uint32_t baud_rate) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), _get_effective_baudrate(baud_rate)); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
| } | ||||
|  | ||||
| uint32_t uartGetBaudRate(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num)); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|     return baud_rate; | ||||
| } | ||||
|  | ||||
| static void ARDUINO_ISR_ATTR uart0_write_char(char c) | ||||
| { | ||||
|     while (uart_ll_get_txfifo_len(&UART0) == 0); | ||||
|     uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1); | ||||
| } | ||||
|  | ||||
| #if SOC_UART_NUM > 1 | ||||
| static void ARDUINO_ISR_ATTR uart1_write_char(char c) | ||||
| { | ||||
|     while (uart_ll_get_txfifo_len(&UART1) == 0); | ||||
|     uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if SOC_UART_NUM > 2 | ||||
| static void ARDUINO_ISR_ATTR uart2_write_char(char c) | ||||
| { | ||||
|     while (uart_ll_get_txfifo_len(&UART2) == 0); | ||||
|     uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void uart_install_putc() | ||||
| { | ||||
|     switch(s_uart_debug_nr) { | ||||
|     case 0: | ||||
|         ets_install_putc1((void (*)(char)) &uart0_write_char); | ||||
|         break; | ||||
| #if SOC_UART_NUM > 1 | ||||
|     case 1: | ||||
|         ets_install_putc1((void (*)(char)) &uart1_write_char); | ||||
|         break; | ||||
| #endif | ||||
| #if SOC_UART_NUM > 2 | ||||
|     case 2: | ||||
|         ets_install_putc1((void (*)(char)) &uart2_write_char); | ||||
|         break; | ||||
| #endif | ||||
|     default: | ||||
|         ets_install_putc1(NULL); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void uartSetDebug(uart_t* uart) | ||||
| { | ||||
|     if(uart == NULL || uart->num >= SOC_UART_NUM) { | ||||
|         s_uart_debug_nr = -1; | ||||
|     } else { | ||||
|         s_uart_debug_nr = uart->num; | ||||
|     } | ||||
|     uart_install_putc(); | ||||
| } | ||||
|  | ||||
| int uartGetDebug() | ||||
| { | ||||
|     return s_uart_debug_nr; | ||||
| } | ||||
|  | ||||
| int log_printf(const char *format, ...) | ||||
| { | ||||
|     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, copy); | ||||
|     va_end(copy); | ||||
|     if(len >= sizeof(loc_buf)){ | ||||
|         temp = (char*)malloc(len+1); | ||||
|         if(temp == NULL) { | ||||
|             va_end(arg); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ | ||||
|         xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY); | ||||
|     } | ||||
| #endif | ||||
|      | ||||
|     vsnprintf(temp, len+1, format, arg); | ||||
|     ets_printf("%s", temp); | ||||
|  | ||||
| #if !CONFIG_DISABLE_HAL_LOCKS | ||||
|     if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ | ||||
|         xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock); | ||||
|     } | ||||
| #endif | ||||
|     va_end(arg); | ||||
|     if(len >= sizeof(loc_buf)){ | ||||
|         free(temp); | ||||
|     } | ||||
|     return len; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){ | ||||
|     for(size_t i = 0; i<len; i++){ | ||||
|         log_printf("%s0x%02x,",i?" ":"", b[i]); | ||||
|     } | ||||
|     if(total_len > 16){ | ||||
|         for(size_t i = len; i<16; i++){ | ||||
|             log_printf("      "); | ||||
|         } | ||||
|         log_printf("    // "); | ||||
|     } else { | ||||
|         log_printf(" // "); | ||||
|     } | ||||
|     for(size_t i = 0; i<len; i++){ | ||||
|         log_printf("%c",((b[i] >= 0x20) && (b[i] < 0x80))?b[i]:'.'); | ||||
|     } | ||||
|     log_printf("\n"); | ||||
| } | ||||
|  | ||||
| void log_print_buf(const uint8_t *b, size_t len){ | ||||
|     if(!len || !b){ | ||||
|         return; | ||||
|     } | ||||
|     for(size_t i = 0; i<len; i+=16){ | ||||
|         if(len > 16){ | ||||
|             log_printf("/* 0x%04X */ ", i); | ||||
|         } | ||||
|         log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, 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) | ||||
| { | ||||
| #ifndef CONFIG_IDF_TARGET_ESP32S3 | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     uart_dev_t *hw = UART_LL_GET_HW(uart->num); | ||||
|  | ||||
|     while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num) | ||||
|         if(flg) return 0; | ||||
|         ets_delay_us(1000); | ||||
|     } | ||||
|  | ||||
|     UART_MUTEX_LOCK(); | ||||
|     //log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt); | ||||
|     unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1); | ||||
|     UART_MUTEX_UNLOCK(); | ||||
|  | ||||
|     return ret; | ||||
| #else | ||||
|     return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * 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. | ||||
|  *  | ||||
|  * ESP32-C3 reports wrong baud rate detection as shown below: | ||||
|  *  | ||||
|  * This will help in a future recall for the C3. | ||||
|  * Baud Sent:          Baud Read: | ||||
|  *  300        -->       19536 | ||||
|  * 2400        -->       19536 | ||||
|  * 4800        -->       19536  | ||||
|  * 9600        -->       28818  | ||||
|  * 19200       -->       57678 | ||||
|  * 38400       -->       115440 | ||||
|  * 57600       -->       173535 | ||||
|  * 115200      -->       347826 | ||||
|  * 230400      -->       701754 | ||||
|  *  | ||||
|  *  | ||||
| */ | ||||
| void uartStartDetectBaudrate(uart_t *uart) { | ||||
|     if(uart == NULL) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| #ifdef CONFIG_IDF_TARGET_ESP32C3 | ||||
|      | ||||
|     // ESP32-C3 requires further testing | ||||
|     // Baud rate detection returns wrong values  | ||||
|     | ||||
|     log_e("ESP32-C3 baud rate detection is not supported."); | ||||
|     return; | ||||
|  | ||||
|     // Code bellow for C3 kept for future recall | ||||
|     //hw->rx_filt.glitch_filt = 0x08; | ||||
|     //hw->rx_filt.glitch_filt_en = 1; | ||||
|     //hw->conf0.autobaud_en = 0; | ||||
|     //hw->conf0.autobaud_en = 1; | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #else | ||||
|     uart_dev_t *hw = UART_LL_GET_HW(uart->num); | ||||
|     hw->auto_baud.glitch_filt = 0x08; | ||||
|     hw->auto_baud.en = 0; | ||||
|     hw->auto_baud.en = 1; | ||||
| #endif | ||||
| } | ||||
|   | ||||
| unsigned long | ||||
| uartDetectBaudrate(uart_t *uart) | ||||
| { | ||||
|     if(uart == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
| #ifndef CONFIG_IDF_TARGET_ESP32C3    // ESP32-C3 requires further testing - Baud rate detection returns wrong values  | ||||
|  | ||||
|     static bool uartStateDetectingBaudrate = false; | ||||
|  | ||||
|     if(!uartStateDetectingBaudrate) { | ||||
|         uartStartDetectBaudrate(uart); | ||||
|         uartStateDetectingBaudrate = true; | ||||
|     } | ||||
|  | ||||
|     unsigned long divisor = uartBaudrateDetect(uart, true); | ||||
|     if (!divisor) { | ||||
|         return 0; | ||||
|     } | ||||
|     //  log_i(...) below has been used to check C3 baud rate detection results | ||||
|     //log_i("Divisor = %d\n", divisor); | ||||
|     //log_i("BAUD RATE based on Positive Pulse %d\n", getApbFrequency()/((hw->pospulse.min_cnt + 1)/2)); | ||||
|     //log_i("BAUD RATE based on Negative Pulse %d\n", getApbFrequency()/((hw->negpulse.min_cnt + 1)/2)); | ||||
|  | ||||
|  | ||||
| #ifdef CONFIG_IDF_TARGET_ESP32C3 | ||||
|     //hw->conf0.autobaud_en = 0; | ||||
| #elif CONFIG_IDF_TARGET_ESP32S3 | ||||
| #else | ||||
|     uart_dev_t *hw = UART_LL_GET_HW(uart->num); | ||||
|     hw->auto_baud.en = 0; | ||||
| #endif | ||||
|     uartStateDetectingBaudrate = false; // Initialize for the next round | ||||
|  | ||||
|     unsigned long baudrate = getApbFrequency() / divisor; | ||||
|     //log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate); | ||||
|  | ||||
|     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]; | ||||
| #else | ||||
|     log_e("ESP32-C3 baud rate detection is not supported."); | ||||
|     return 0; | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										108
									
								
								cores/esp32/esp32-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								cores/esp32/esp32-hal-uart.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| // 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> | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/queue.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 | ||||
|  | ||||
| // These are Hardware Flow Contol possible usage | ||||
| // equivalent to UDF enum uart_hw_flowcontrol_t from  | ||||
| // https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/uart_types.h#L75-L81 | ||||
| #define HW_FLOWCTRL_DISABLE   0x0       // disable HW Flow Control | ||||
| #define HW_FLOWCTRL_RTS       0x1       // use only RTS PIN for HW Flow Control | ||||
| #define HW_FLOWCTRL_CTS       0x2       // use only CTS PIN for HW Flow Control | ||||
| #define HW_FLOWCTRL_CTS_RTS   0x3       // use both CTS and RTS PIN for HW Flow Control | ||||
|  | ||||
| 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 rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd); | ||||
| void uartEnd(uart_t* uart); | ||||
|  | ||||
| // This is used to retrieve the Event Queue pointer from a UART IDF Driver in order to allow user to deal with its events | ||||
| void uartGetEventQueue(uart_t* uart, QueueHandle_t *q);  | ||||
|  | ||||
| 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 uartFlushTxOnly(uart_t* uart, bool txOnly ); | ||||
|  | ||||
| void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); | ||||
| uint32_t uartGetBaudRate(uart_t* uart); | ||||
|  | ||||
| void uartSetRxInvert(uart_t* uart, bool invert); | ||||
| void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); | ||||
| void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); | ||||
| void uartSetFastReading(uart_t* uart); | ||||
|  | ||||
| void uartSetDebug(uart_t* uart); | ||||
| int uartGetDebug(); | ||||
|  | ||||
| bool uartIsDriverInstalled(uart_t* uart); | ||||
|  | ||||
| // Negative Pin Number will keep it unmodified, thus this function can set individual pins | ||||
| void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); | ||||
|  | ||||
| // Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins | ||||
| void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); | ||||
|  | ||||
| void uartStartDetectBaudrate(uart_t *uart); | ||||
| unsigned long uartDetectBaudrate(uart_t *uart); | ||||
|  | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* MAIN_ESP32_HAL_UART_H_ */ | ||||
							
								
								
									
										147
									
								
								cores/esp32/esp32-hal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								cores/esp32/esp32-hal.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| /* | ||||
|  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_ | ||||
|  | ||||
| #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" | ||||
| #include "esp_sleep.h" | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "freertos/queue.h" | ||||
| #include "freertos/semphr.h" | ||||
| #include "freertos/event_groups.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #ifndef F_CPU | ||||
| #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 | ||||
| #define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U) | ||||
| #elif CONFIG_IDF_TARGET_ESP32S2 | ||||
| #define F_CPU (CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ * 1000000U) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #if CONFIG_ARDUINO_ISR_IRAM | ||||
| #define ARDUINO_ISR_ATTR IRAM_ATTR | ||||
| #define ARDUINO_ISR_FLAG ESP_INTR_FLAG_IRAM | ||||
| #else | ||||
| #define ARDUINO_ISR_ATTR | ||||
| #define ARDUINO_ISR_FLAG (0) | ||||
| #endif | ||||
|  | ||||
| #ifndef ARDUINO_RUNNING_CORE | ||||
| #define ARDUINO_RUNNING_CORE CONFIG_ARDUINO_RUNNING_CORE | ||||
| #endif | ||||
|  | ||||
| #ifndef ARDUINO_EVENT_RUNNING_CORE | ||||
| #define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE | ||||
| #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-rgb-led.h" | ||||
| #include "esp32-hal-cpu.h" | ||||
|  | ||||
| void analogWrite(uint8_t pin, int value); | ||||
| int8_t analogGetChannel(uint8_t pin); | ||||
|  | ||||
| //returns chip temperature in Celsius | ||||
| float temperatureRead(); | ||||
|  | ||||
| //allows user to bypass SPI RAM test routine | ||||
| bool testSPIRAM(void); | ||||
|  | ||||
| #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_ */ | ||||
							
								
								
									
										24
									
								
								cores/esp32/esp8266-compat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								cores/esp32/esp8266-compat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| // 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 ARDUINO_ISR_ATTR | ||||
|  | ||||
|  | ||||
| #endif /* _ESP8266_COMPAT_H_ */ | ||||
							
								
								
									
										46
									
								
								cores/esp32/esp_arduino_version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								cores/esp32/esp_arduino_version.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| // Copyright 2019 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| /** Major version number (X.x.x) */ | ||||
| #define ESP_ARDUINO_VERSION_MAJOR   2 | ||||
| /** Minor version number (x.X.x) */ | ||||
| #define ESP_ARDUINO_VERSION_MINOR   0 | ||||
| /** Patch version number (x.x.X) */ | ||||
| #define ESP_ARDUINO_VERSION_PATCH   5 | ||||
|  | ||||
| /** | ||||
|  * Macro to convert ARDUINO version number into an integer | ||||
|  * | ||||
|  * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) | ||||
|  */ | ||||
| #define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) | ||||
|  | ||||
| /** | ||||
|  * Current ARDUINO version, as an integer | ||||
|  * | ||||
|  * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) | ||||
|  */ | ||||
| #define ESP_ARDUINO_VERSION  ESP_ARDUINO_VERSION_VAL(ESP_ARDUINO_VERSION_MAJOR, \ | ||||
|                                              ESP_ARDUINO_VERSION_MINOR, \ | ||||
|                                              ESP_ARDUINO_VERSION_PATCH) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										204
									
								
								cores/esp32/firmware_msc_fat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								cores/esp32/firmware_msc_fat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #include "firmware_msc_fat.h" | ||||
| //copy up to max_len chars from src to dst and do not terminate | ||||
| static size_t cplstr(void *dst, const void * src, size_t max_len){ | ||||
|     if(!src || !dst || !max_len){ | ||||
|         return 0; | ||||
|     } | ||||
|     size_t l = strlen((const char *)src); | ||||
|     if(l > max_len){ | ||||
|         l = max_len; | ||||
|     } | ||||
|     memcpy(dst, src, l); | ||||
|     return l; | ||||
| } | ||||
|  | ||||
| //copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate | ||||
| static void cplstrsp(void *dst, const void * src, size_t max_len){ | ||||
|     size_t l = cplstr(dst, src, max_len); | ||||
|     for(; l < max_len; l++){ | ||||
|       ((uint8_t*)dst)[l] = 0x20; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // FAT12 | ||||
| static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12"; | ||||
|  | ||||
| static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){ | ||||
|   uint32_t required_bytes = (((sector_num * 3)+1)/2); | ||||
|   return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0); | ||||
| } | ||||
|  | ||||
| static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){ | ||||
|   memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); | ||||
|   uint8_t * d = dst + DISK_SECTOR_SIZE; | ||||
|   d[0] = 0xF8; | ||||
|   d[1] = 0xFF; | ||||
|   d[2] = 0xFF; | ||||
|   return d; | ||||
| } | ||||
|  | ||||
| static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ | ||||
|   uint16_t offset = (index >> 1) * 3; | ||||
|   uint8_t * data = table + offset; | ||||
|   if(index & 1){ | ||||
|     data[2] = (value >> 4) & 0xFF; | ||||
|     data[1] = (data[1] & 0xF) | ((value & 0xF) << 4); | ||||
|   } else { | ||||
|     data[0] = value & 0xFF; | ||||
|     data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF); | ||||
|   } | ||||
| } | ||||
|  | ||||
| //FAT16 | ||||
| static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16"; | ||||
|  | ||||
| static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){ | ||||
|   uint32_t required_bytes = sector_num * 2; | ||||
|   return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0); | ||||
| } | ||||
|  | ||||
| static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){ | ||||
|   memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); | ||||
|   uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE); | ||||
|   d[0] = 0xFFF8; | ||||
|   d[1] = 0xFFFF; | ||||
|   return (uint8_t *)d; | ||||
| } | ||||
|  | ||||
| static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ | ||||
|   uint16_t offset = index * 2; | ||||
|   *(uint16_t *)(table + offset) = value; | ||||
| } | ||||
|  | ||||
| //Interface | ||||
| const char * fat_file_system_type(bool fat16) { | ||||
| 	return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE); | ||||
| } | ||||
|  | ||||
| uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){ | ||||
|   if(fat16){ | ||||
|     return fat16_sectors_per_alloc_table(sector_num); | ||||
|   } | ||||
|   return fat12_sectors_per_alloc_table(sector_num); | ||||
| } | ||||
|  | ||||
| uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){ | ||||
|   if(fat16){ | ||||
|     return fat16_add_table(dst, boot); | ||||
|   } | ||||
|   return fat12_add_table(dst, boot); | ||||
| } | ||||
|  | ||||
| void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){ | ||||
|   if(fat16){ | ||||
|     fat16_set_table_index(table, index, value); | ||||
|   } else { | ||||
|     fat12_set_table_index(table, index, value); | ||||
|   } | ||||
| } | ||||
|  | ||||
| fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){ | ||||
|   fat_boot_sector_t *boot = (fat_boot_sector_t*)dst; | ||||
|   boot->jump_instruction[0] = 0xEB; | ||||
|   boot->jump_instruction[1] = 0x3C; | ||||
|   boot->jump_instruction[2] = 0x90; | ||||
|   cplstr(boot->oem_name, "MSDOS5.0", 8); | ||||
|   boot->bytes_per_sector = DISK_SECTOR_SIZE; | ||||
|   boot->sectors_per_cluster = 1; | ||||
|   boot->reserved_sectors_count = 1; | ||||
|   boot->file_alloc_tables_num = 1; | ||||
|   boot->max_root_dir_entries = 16; | ||||
|   boot->fat12_sector_num = sector_num; | ||||
|   boot->media_descriptor = 0xF8; | ||||
|   boot->sectors_per_alloc_table = table_sectors; | ||||
|   boot->sectors_per_track = 1; | ||||
|   boot->num_heads = 1; | ||||
|   boot->hidden_sectors_count = 0; | ||||
|   boot->total_sectors_32 = 0; | ||||
|   boot->physical_drive_number = 0x80; | ||||
|   boot->reserved0 = 0x00; | ||||
|   boot->extended_boot_signature = 0x29; | ||||
|   boot->serial_number = serial_number; | ||||
|   cplstrsp(boot->volume_label, volume_label, 11); | ||||
|   memset(boot->reserved, 0, 448); | ||||
|   cplstrsp(boot->file_system_type, file_system_type, 8); | ||||
|   boot->signature = 0xAA55; | ||||
|   return boot; | ||||
| } | ||||
|  | ||||
| fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){ | ||||
|   fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; | ||||
|   fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE)); | ||||
|   memset(entry, 0, sizeof(fat_dir_entry_t)); | ||||
|   cplstrsp(entry->volume_label, volume_label, 11); | ||||
|   entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL; | ||||
|   return entry; | ||||
| } | ||||
|  | ||||
| fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){ | ||||
|   fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; | ||||
|   uint8_t * table = dst + DISK_SECTOR_SIZE; | ||||
|   fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); | ||||
|   memset(entry, 0, sizeof(fat_dir_entry_t)); | ||||
|   cplstrsp(entry->file_name, file_name, 8); | ||||
|   cplstrsp(entry->file_extension, file_extension, 3); | ||||
|   entry->file_attr = FAT_FILE_ATTR_ARCHIVE; | ||||
|   entry->file_size = file_size; | ||||
|   entry->data_start_sector = data_start_sector; | ||||
|   entry->extended_attr = 0; | ||||
|  | ||||
|   uint16_t file_sectors = file_size / DISK_SECTOR_SIZE; | ||||
|   if(file_size % DISK_SECTOR_SIZE){ | ||||
|     file_sectors++; | ||||
|   } | ||||
|  | ||||
|   uint16_t data_end_sector = data_start_sector + file_sectors; | ||||
|   for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){ | ||||
|     fat_set_table_index(table, i, i+1, is_fat16); | ||||
|   } | ||||
|   fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16); | ||||
|  | ||||
|   //Set Firmware Date based on the build time | ||||
|   static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; | ||||
|   char mstr[8] = {'\0',}; | ||||
|   const char *str = __DATE__ " " __TIME__; | ||||
|   int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0; | ||||
|   int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds); | ||||
|   if(r >= 0){ | ||||
|     for(int i=0; i<12; i++){ | ||||
|       if(!strcmp(mstr, month_names_short[i])){ | ||||
|         month = i; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     entry->creation_time_ms = FAT_MS2V(seconds, ms); | ||||
|     entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds); | ||||
|     entry->creation_time_ymd = FAT_YMD2V(year, month, date); | ||||
|     entry->last_access_ymd = entry->creation_time_ymd; | ||||
|     entry->last_modified_hms = entry->creation_time_hms; | ||||
|     entry->last_modified_ymd = entry->creation_time_ymd; | ||||
|   } | ||||
|   return entry; | ||||
| } | ||||
|  | ||||
| uint8_t fat_lfn_checksum(const uint8_t *short_filename){ | ||||
|    uint8_t sum = 0; | ||||
|    for (uint8_t i = 11; i; i--) { | ||||
|       sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++; | ||||
|    } | ||||
|    return sum; | ||||
| } | ||||
							
								
								
									
										141
									
								
								cores/esp32/firmware_msc_fat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								cores/esp32/firmware_msc_fat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
| #define FAT_U8(v) ((v) & 0xFF) | ||||
| #define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8) | ||||
| #define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24) | ||||
|  | ||||
| #define FAT12_TBL2B(l,h)    FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4) | ||||
|  | ||||
| #define FAT_MS2B(s,ms)    FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) | ||||
| #define FAT_HMS2B(h,m,s)  FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)),      FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) | ||||
| #define FAT_YMD2B(y,m,d)  FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)),    FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) | ||||
|  | ||||
| #define FAT_MS2V(s,ms)    FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) | ||||
| #define FAT_HMS2V(h,m,s)  (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8)) | ||||
| #define FAT_YMD2V(y,m,d)  (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8)) | ||||
|  | ||||
| #define FAT_B2HMS(hms)    ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1) | ||||
| #define FAT_B2YMD(ymd)    (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F) | ||||
|  | ||||
| #define FAT_FILE_ATTR_READ_ONLY     0x01 | ||||
| #define FAT_FILE_ATTR_HIDDEN        0x02 | ||||
| #define FAT_FILE_ATTR_SYSTEM        0x04 | ||||
| #define FAT_FILE_ATTR_VOLUME_LABEL  0x08 | ||||
| #define FAT_FILE_ATTR_SUBDIRECTORY  0x10 | ||||
| #define FAT_FILE_ATTR_ARCHIVE       0x20 | ||||
| #define FAT_FILE_ATTR_DEVICE        0x40 | ||||
|  | ||||
| static const uint16_t DISK_SECTOR_SIZE = 512; | ||||
|  | ||||
| #define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0) | ||||
|  | ||||
| typedef struct __attribute__ ((packed)) { | ||||
|   uint8_t jump_instruction[3]; | ||||
|   char oem_name[8];//padded with spaces (0x20) | ||||
|   uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512 | ||||
|   uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128 | ||||
|   uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32 | ||||
|   uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1 | ||||
|   uint16_t max_root_dir_entries;//FAT12 and FAT16 | ||||
|   uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16 | ||||
|   uint8_t media_descriptor; | ||||
|   uint16_t sectors_per_alloc_table;//FAT12 and FAT16 | ||||
|   uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access | ||||
|   uint16_t num_heads; | ||||
|   uint32_t hidden_sectors_count; | ||||
|   uint32_t total_sectors_32; | ||||
|   uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk | ||||
|   uint8_t reserved0; | ||||
|   uint8_t extended_boot_signature;//should be 0x29 | ||||
|   uint32_t serial_number;//0x1234 => 1234 | ||||
|   char volume_label[11];//padded with spaces (0x20) | ||||
|   char file_system_type[8];//padded with spaces (0x20) | ||||
|   uint8_t reserved[448]; | ||||
|   uint16_t signature;//should be 0xAA55 | ||||
| } fat_boot_sector_t; | ||||
|  | ||||
| typedef struct __attribute__ ((packed)) { | ||||
|   union { | ||||
|     struct { | ||||
|       char file_name[8];//padded with spaces (0x20) | ||||
|       char file_extension[3];//padded with spaces (0x20) | ||||
|     }; | ||||
|     struct { | ||||
|       uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..) | ||||
|       char file_magic_data[10]; | ||||
|     }; | ||||
|     char volume_label[11];//padded with spaces (0x20) | ||||
|   }; | ||||
|   uint8_t file_attr;//mask of FAT_FILE_ATTR_* | ||||
|   uint8_t reserved;//always 0 | ||||
|   uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms) | ||||
|   uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2) | ||||
|   uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d | ||||
|   uint16_t last_access_ymd; | ||||
|   uint16_t extended_attr; | ||||
|   uint16_t last_modified_hms; | ||||
|   uint16_t last_modified_ymd; | ||||
|   uint16_t data_start_sector; | ||||
|   uint32_t file_size; | ||||
| } fat_dir_entry_t; | ||||
|  | ||||
| typedef struct __attribute__ ((packed)) { | ||||
|   union { | ||||
|     struct { | ||||
|       uint8_t number:5; | ||||
|       uint8_t reserved0:1; | ||||
|       uint8_t llfp:1; | ||||
|       uint8_t reserved1:1; | ||||
|     } seq; | ||||
|     uint8_t seq_num; //0xE5: Deleted Entry | ||||
|   }; | ||||
|   uint16_t name0[5]; | ||||
|   uint8_t attr; //ALWAYS 0x0F | ||||
|   uint8_t type; //ALWAYS 0x00 | ||||
|   uint8_t dos_checksum; | ||||
|   uint16_t name1[6]; | ||||
|   uint16_t first_cluster; //ALWAYS 0x0000 | ||||
|   uint16_t name2[2]; | ||||
| } fat_lfn_entry_t; | ||||
|  | ||||
| typedef union { | ||||
|   fat_dir_entry_t dir; | ||||
|   fat_lfn_entry_t lfn; | ||||
| } fat_entry_t; | ||||
|  | ||||
| const char * fat_file_system_type(bool fat16); | ||||
| uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16); | ||||
| uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16); | ||||
| void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16); | ||||
| fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number); | ||||
| fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label); | ||||
| fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16); | ||||
| uint8_t fat_lfn_checksum(const uint8_t *short_filename); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
							
								
								
									
										7
									
								
								cores/esp32/libb64/AUTHORS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cores/esp32/libb64/AUTHORS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| libb64: Base64 Encoding/Decoding Routines | ||||
| ====================================== | ||||
|  | ||||
| Authors: | ||||
| ------- | ||||
|  | ||||
| Chris Venter	chris.venter@gmail.com	http://rocketpod.blogspot.com | ||||
							
								
								
									
										29
									
								
								cores/esp32/libb64/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								cores/esp32/libb64/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| 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. | ||||
							
								
								
									
										102
									
								
								cores/esp32/libb64/cdecode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								cores/esp32/libb64/cdecode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /* | ||||
| 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; | ||||
|         // fall through | ||||
|       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; | ||||
|         // fall through | ||||
|       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; | ||||
|         // fall through | ||||
|       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); | ||||
| } | ||||
							
								
								
									
										38
									
								
								cores/esp32/libb64/cdecode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								cores/esp32/libb64/cdecode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
| 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 */ | ||||
							
								
								
									
										104
									
								
								cores/esp32/libb64/cencode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								cores/esp32/libb64/cencode.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
| 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; | ||||
|             // fall through | ||||
|         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; | ||||
|             // fall through | ||||
|         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); | ||||
| } | ||||
							
								
								
									
										41
									
								
								cores/esp32/libb64/cencode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								cores/esp32/libb64/cencode.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
| 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 */ | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user