Prvni ulozeni z chegewara githubu

This commit is contained in:
Pavel Brychta 2023-02-25 16:13:53 +01:00
commit 01eb80dfe2
3279 changed files with 638407 additions and 0 deletions

263
CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,58 @@
# Arduino core for the ESP32, ESP32-S2, ESP32-S3 and ESP32-C3
![Build Status](https://github.com/espressif/arduino-esp32/workflows/ESP32%20Arduino%20CI/badge.svg) [![Documentation Status](https://readthedocs.com/projects/espressif-arduino-esp32/badge/?version=latest)](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](https://badges.gitter.im/espressif/arduino-esp32.svg)](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 [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) [![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
Latest Development Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](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

File diff suppressed because it is too large Load Diff

216
cores/esp32/Arduino.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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 */

View 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;
}
}

View 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
View 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
View 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 */

View 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;
}

View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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() {
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -0,0 +1 @@
#include "lwip/apps/sntp.h"

64
cores/esp32/base64.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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);
}

View 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_ */

View 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

View 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_ */

View 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")));

View 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_ */

View 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);
}

View 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
View 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;
}

View 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_ */

View 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;
}

View 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
View 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__ */

View 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);
}
*/

View 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_ */

View 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;
}

View 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

View 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_ */

View 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);
}

View 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
View 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
View 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_ */

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

149
cores/esp32/esp32-hal-spi.h Normal file
View 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_ */

View 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;
}

View 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();
}

View 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_ */

View 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 */

View 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 */

View 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

View 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_ */

View 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
}

View 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
View 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_ */

View 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_ */

View 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

View 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;
}

View 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

View File

@ -0,0 +1,7 @@
libb64: Base64 Encoding/Decoding Routines
======================================
Authors:
-------
Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com

View 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.

View 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);
}

View 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 */

View 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);
}

View 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