From 683dbf3b1b34267c0754a5206be461589a38ddce Mon Sep 17 00:00:00 2001 From: Pedro Minatel Date: Wed, 2 Mar 2022 13:17:18 +0000 Subject: [PATCH 1/5] Added ESP32-WROOM-DA module to boards.txt (#6361) Added dual antenna configuration based on the module selection Added warning to the example on how to use the DA --- boards.txt | 149 ++++++++++++++++++ .../WiFiScanDualAntenna.ino | 7 +- libraries/WiFi/src/WiFiGeneric.cpp | 8 + libraries/WiFi/src/WiFiGeneric.h | 2 +- variants/esp32da/pins_arduino.h | 60 +++++++ 5 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 variants/esp32da/pins_arduino.h diff --git a/boards.txt b/boards.txt index 06a48db0ff8..159c4d984de 100755 --- a/boards.txt +++ b/boards.txt @@ -487,6 +487,155 @@ esp32.menu.DebugLevel.verbose.build.code_debug=5 ############################################################## +esp32da.name=ESP32-WROOM-DA Module + +esp32da.upload.tool=esptool_py +esp32da.upload.maximum_size=1310720 +esp32da.upload.maximum_data_size=327680 +esp32da.upload.flags= +esp32da.upload.extra_flags= + +esp32da.serial.disableDTR=true +esp32da.serial.disableRTS=true + +esp32da.build.tarch=xtensa +esp32da.build.bootloader_addr=0x1000 +esp32da.build.target=esp32 +esp32da.build.mcu=esp32 +esp32da.build.core=esp32 +esp32da.build.variant=esp32da +esp32da.build.board=ESP32_WROOM_DA + +esp32da.build.f_cpu=240000000L +esp32da.build.flash_size=4MB +esp32da.build.flash_freq=40m +esp32da.build.flash_mode=dio +esp32da.build.boot=dio +esp32da.build.partitions=default +esp32da.build.defines= +esp32da.build.loop_core= +esp32da.build.event_core= + +esp32da.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS) +esp32da.menu.PartitionScheme.default.build.partitions=default +esp32da.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS) +esp32da.menu.PartitionScheme.defaultffat.build.partitions=default_ffat +esp32da.menu.PartitionScheme.default_8MB=8M Flash (3MB APP/1.5MB FAT) +esp32da.menu.PartitionScheme.default_8MB.build.partitions=default_8MB +esp32da.menu.PartitionScheme.default_8MB.upload.maximum_size=3342336 +esp32da.menu.PartitionScheme.minimal=Minimal (1.3MB APP/700KB SPIFFS) +esp32da.menu.PartitionScheme.minimal.build.partitions=minimal +esp32da.menu.PartitionScheme.no_ota=No OTA (2MB APP/2MB SPIFFS) +esp32da.menu.PartitionScheme.no_ota.build.partitions=no_ota +esp32da.menu.PartitionScheme.no_ota.upload.maximum_size=2097152 +esp32da.menu.PartitionScheme.noota_3g=No OTA (1MB APP/3MB SPIFFS) +esp32da.menu.PartitionScheme.noota_3g.build.partitions=noota_3g +esp32da.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576 +esp32da.menu.PartitionScheme.noota_ffat=No OTA (2MB APP/2MB FATFS) +esp32da.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat +esp32da.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152 +esp32da.menu.PartitionScheme.noota_3gffat=No OTA (1MB APP/3MB FATFS) +esp32da.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat +esp32da.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576 +esp32da.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS) +esp32da.menu.PartitionScheme.huge_app.build.partitions=huge_app +esp32da.menu.PartitionScheme.huge_app.upload.maximum_size=3145728 +esp32da.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS) +esp32da.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs +esp32da.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080 +esp32da.menu.PartitionScheme.fatflash=16M Flash (2MB APP/12.5MB FAT) +esp32da.menu.PartitionScheme.fatflash.build.partitions=ffat +esp32da.menu.PartitionScheme.fatflash.upload.maximum_size=2097152 +esp32da.menu.PartitionScheme.app3M_fat9M_16MB=16M Flash (3MB APP/9MB FATFS) +esp32da.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB +esp32da.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728 +esp32da.menu.PartitionScheme.rainmaker=RainMaker +esp32da.menu.PartitionScheme.rainmaker.build.partitions=rainmaker +esp32da.menu.PartitionScheme.rainmaker.upload.maximum_size=3145728 + +esp32da.menu.CPUFreq.240=240MHz (WiFi/BT) +esp32da.menu.CPUFreq.240.build.f_cpu=240000000L +esp32da.menu.CPUFreq.160=160MHz (WiFi/BT) +esp32da.menu.CPUFreq.160.build.f_cpu=160000000L +esp32da.menu.CPUFreq.80=80MHz (WiFi/BT) +esp32da.menu.CPUFreq.80.build.f_cpu=80000000L +esp32da.menu.CPUFreq.40=40MHz (40MHz XTAL) +esp32da.menu.CPUFreq.40.build.f_cpu=40000000L +esp32da.menu.CPUFreq.26=26MHz (26MHz XTAL) +esp32da.menu.CPUFreq.26.build.f_cpu=26000000L +esp32da.menu.CPUFreq.20=20MHz (40MHz XTAL) +esp32da.menu.CPUFreq.20.build.f_cpu=20000000L +esp32da.menu.CPUFreq.13=13MHz (26MHz XTAL) +esp32da.menu.CPUFreq.13.build.f_cpu=13000000L +esp32da.menu.CPUFreq.10=10MHz (40MHz XTAL) +esp32da.menu.CPUFreq.10.build.f_cpu=10000000L + +esp32da.menu.FlashMode.qio=QIO +esp32da.menu.FlashMode.qio.build.flash_mode=dio +esp32da.menu.FlashMode.qio.build.boot=qio +esp32da.menu.FlashMode.dio=DIO +esp32da.menu.FlashMode.dio.build.flash_mode=dio +esp32da.menu.FlashMode.dio.build.boot=dio +esp32da.menu.FlashMode.qout=QOUT +esp32da.menu.FlashMode.qout.build.flash_mode=dout +esp32da.menu.FlashMode.qout.build.boot=qout +esp32da.menu.FlashMode.dout=DOUT +esp32da.menu.FlashMode.dout.build.flash_mode=dout +esp32da.menu.FlashMode.dout.build.boot=dout + +esp32da.menu.FlashFreq.80=80MHz +esp32da.menu.FlashFreq.80.build.flash_freq=80m +esp32da.menu.FlashFreq.40=40MHz +esp32da.menu.FlashFreq.40.build.flash_freq=40m + +esp32da.menu.FlashSize.4M=4MB (32Mb) +esp32da.menu.FlashSize.4M.build.flash_size=4MB +esp32da.menu.FlashSize.8M=8MB (64Mb) +esp32da.menu.FlashSize.8M.build.flash_size=8MB +esp32da.menu.FlashSize.8M.build.partitions=default_8MB +esp32da.menu.FlashSize.16M=16MB (128Mb) +esp32da.menu.FlashSize.16M.build.flash_size=16MB + +esp32da.menu.UploadSpeed.921600=921600 +esp32da.menu.UploadSpeed.921600.upload.speed=921600 +esp32da.menu.UploadSpeed.115200=115200 +esp32da.menu.UploadSpeed.115200.upload.speed=115200 +esp32da.menu.UploadSpeed.256000.windows=256000 +esp32da.menu.UploadSpeed.256000.upload.speed=256000 +esp32da.menu.UploadSpeed.230400.windows.upload.speed=256000 +esp32da.menu.UploadSpeed.230400=230400 +esp32da.menu.UploadSpeed.230400.upload.speed=230400 +esp32da.menu.UploadSpeed.460800.linux=460800 +esp32da.menu.UploadSpeed.460800.macosx=460800 +esp32da.menu.UploadSpeed.460800.upload.speed=460800 +esp32da.menu.UploadSpeed.512000.windows=512000 +esp32da.menu.UploadSpeed.512000.upload.speed=512000 + +esp32da.menu.LoopCore.1=Core 1 +esp32da.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1 +esp32da.menu.LoopCore.0=Core 0 +esp32da.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0 + +esp32da.menu.EventsCore.1=Core 1 +esp32da.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1 +esp32da.menu.EventsCore.0=Core 0 +esp32da.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0 + +esp32da.menu.DebugLevel.none=None +esp32da.menu.DebugLevel.none.build.code_debug=0 +esp32da.menu.DebugLevel.error=Error +esp32da.menu.DebugLevel.error.build.code_debug=1 +esp32da.menu.DebugLevel.warn=Warn +esp32da.menu.DebugLevel.warn.build.code_debug=2 +esp32da.menu.DebugLevel.info=Info +esp32da.menu.DebugLevel.info.build.code_debug=3 +esp32da.menu.DebugLevel.debug=Debug +esp32da.menu.DebugLevel.debug.build.code_debug=4 +esp32da.menu.DebugLevel.verbose=Verbose +esp32da.menu.DebugLevel.verbose.build.code_debug=5 + +############################################################## + esp32wrover.name=ESP32 Wrover Module esp32wrover.upload.tool=esptool_py diff --git a/libraries/WiFi/examples/WiFiScanDualAntenna/WiFiScanDualAntenna.ino b/libraries/WiFi/examples/WiFiScanDualAntenna/WiFiScanDualAntenna.ino index d628068ccf5..f1c8f3e1e42 100644 --- a/libraries/WiFi/examples/WiFiScanDualAntenna/WiFiScanDualAntenna.ino +++ b/libraries/WiFi/examples/WiFiScanDualAntenna/WiFiScanDualAntenna.ino @@ -24,7 +24,12 @@ void setup() // Set WiFi to station mode and disconnect from an AP if it was previously connected WiFi.mode(WIFI_STA); - // Set WiFi dual antenna configuration by passing the GPIO and antenna mode for RX ant TX + /* Attention: This is the manual prodecure for the dual antenna configuration. + * If you choose the ESP32-WROOM-DA module from the Tools -> Board, this configuration + * is not necessary! + * + * Set WiFi dual antenna configuration by passing the GPIO and antenna mode for RX ant TX + */ err = WiFi.setDualAntennaConfig(GPIO_ANT1, GPIO_ANT1, WIFI_RX_ANT_AUTO, WIFI_TX_ANT_AUTO); /* For more details on how to use this feature, see our docs: diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 60654a66722..3c7d2330094 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -1061,6 +1061,14 @@ bool WiFiGenericClass::mode(wifi_mode_t m) if(!espWiFiStart()){ return false; } + + #ifdef BOARD_HAS_DUAL_ANTENNA + if(!setDualAntennaConfig(ANT1, ANT2, WIFI_RX_ANT_AUTO, WIFI_TX_ANT_AUTO)){ + log_e("Dual Antenna Config failed!"); + return false; + } + #endif + return true; } diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index f8a1bb77d37..62642b43dc7 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -186,7 +186,7 @@ class WiFiGenericClass bool initiateFTM(uint8_t frm_count=16, uint16_t burst_period=2, uint8_t channel=1, const uint8_t * mac=NULL); - bool setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode); + static bool setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode); static const char * getHostname(); static bool setHostname(const char * hostname); diff --git a/variants/esp32da/pins_arduino.h b/variants/esp32da/pins_arduino.h new file mode 100644 index 00000000000..14c1e548615 --- /dev/null +++ b/variants/esp32da/pins_arduino.h @@ -0,0 +1,60 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define EXTERNAL_NUM_INTERRUPTS 16 +#define NUM_DIGITAL_PINS 40 +#define NUM_ANALOG_INPUTS 16 + +#define analogInputToDigitalPin(p) (((p)<20)?(analogChannelToDigitalPin(p)):-1) +#define digitalPinToInterrupt(p) (((p)<40)?(p):-1) +#define digitalPinHasPWM(p) (p < 34) + +static const uint8_t TX = 1; +static const uint8_t RX = 3; + +static const uint8_t SDA = 21; +static const uint8_t SCL = 22; + +static const uint8_t SS = 5; +static const uint8_t MOSI = 23; +static const uint8_t MISO = 19; +static const uint8_t SCK = 18; + +static const uint8_t A0 = 36; +static const uint8_t A3 = 39; +static const uint8_t A4 = 32; +static const uint8_t A5 = 33; +static const uint8_t A6 = 34; +static const uint8_t A7 = 35; +static const uint8_t A10 = 4; +static const uint8_t A11 = 0; +static const uint8_t A12 = 2; +static const uint8_t A13 = 15; +static const uint8_t A14 = 13; +static const uint8_t A15 = 12; +static const uint8_t A16 = 14; +static const uint8_t A17 = 27; +static const uint8_t A18 = 25; +static const uint8_t A19 = 26; + +static const uint8_t T0 = 4; +static const uint8_t T1 = 0; +static const uint8_t T2 = 2; +static const uint8_t T3 = 15; +static const uint8_t T4 = 13; +static const uint8_t T5 = 12; +static const uint8_t T6 = 14; +static const uint8_t T7 = 27; +static const uint8_t T8 = 33; +static const uint8_t T9 = 32; + +static const uint8_t DAC1 = 25; +static const uint8_t DAC2 = 26; + +#define BOARD_HAS_DUAL_ANTENNA +static const uint8_t ANT1 = 2; +static const uint8_t ANT2 = 25; + +#endif /* Pins_Arduino_h */ From e8d6050a7ba43b89b14615baa197d4b1114ce5e3 Mon Sep 17 00:00:00 2001 From: P-R-O-C-H-Y <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Wed, 2 Mar 2022 14:18:20 +0100 Subject: [PATCH 2/5] Implemented new types of SmartConfig (#6367) --- libraries/WiFi/src/WiFiSTA.cpp | 19 ++++++++++++++++--- libraries/WiFi/src/WiFiSTA.h | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index dd468823607..c75405bb4f3 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -655,8 +655,15 @@ IPv6Address WiFiSTAClass::localIPv6() bool WiFiSTAClass::_smartConfigStarted = false; bool WiFiSTAClass::_smartConfigDone = false; - -bool WiFiSTAClass::beginSmartConfig() { +/** + * @brief + * + * @param type Select type of SmartConfig. Default type is SC_TYPE_ESPTOUCH + * @param crypt_key When using type SC_TYPE_ESPTOUTCH_V2 crypt key needed, else ignored. Lenght should be 16 chars. + * @return true if configuration is successful. + * @return false if configuration fails. + */ +bool WiFiSTAClass::beginSmartConfig(smartconfig_type_t type, char* crypt_key) { esp_err_t err; if (_smartConfigStarted) { return false; @@ -668,7 +675,13 @@ bool WiFiSTAClass::beginSmartConfig() { esp_wifi_disconnect(); smartconfig_start_config_t conf = SMARTCONFIG_START_CONFIG_DEFAULT(); - err = esp_smartconfig_set_type(SC_TYPE_ESPTOUCH); + + if (type == SC_TYPE_ESPTOUCH_V2){ + conf.esp_touch_v2_enable_crypt = true; + conf.esp_touch_v2_key = crypt_key; + } + + err = esp_smartconfig_set_type(type); if (err != ESP_OK) { log_e("SmartConfig Set Type Failed!"); return false; diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index afd641f7eb3..e49273f0176 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -92,7 +92,7 @@ class WiFiSTAClass static bool _autoReconnect; public: - bool beginSmartConfig(); + bool beginSmartConfig(smartconfig_type_t type = SC_TYPE_ESPTOUCH, char* crypt_key = NULL); bool stopSmartConfig(); bool smartConfigDone(); From 95b8e7e42baf3420f8392b0f79a0d421df8013ff Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 2 Mar 2022 10:19:05 -0300 Subject: [PATCH 3/5] Fixes DHCP Server Lease Range for any AP Server Static IP Address (#6296) * Fixes DHCP Server Lease Range for any AP Server Static IP Address * Fixes DHCP in APMode when Static IP is out of subnet range --- libraries/WiFi/src/WiFiAP.cpp | 18 +----------------- libraries/WiFi/src/WiFiGeneric.cpp | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/libraries/WiFi/src/WiFiAP.cpp b/libraries/WiFi/src/WiFiAP.cpp index 8201d4634d9..2ef68ff53b0 100644 --- a/libraries/WiFi/src/WiFiAP.cpp +++ b/libraries/WiFi/src/WiFiAP.cpp @@ -205,23 +205,7 @@ bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress } err = set_esp_interface_ip(ESP_IF_WIFI_AP, local_ip, gateway, subnet); - - // testing effectiveness of the operation beyond internal DHCP Client process - esp_netif_ip_info_t ip; - if(esp_netif_get_ip_info(get_esp_interface_netif(ESP_IF_WIFI_AP), &ip) != ESP_OK){ - log_e("Netif Get IP Failed!"); - return false; - } - bool ip_ok = IPAddress(ip.ip.addr) == local_ip; - bool gw_ok = IPAddress(ip.gw.addr) == gateway; - bool mk_ok = IPAddress(ip.netmask.addr) == subnet; - - if (ip_ok && gw_ok && mk_ok) { - return true; - } else { - log_e("Failed setting: %s %s %s", ip_ok ? "" : "Static IP", gw_ok ? "" : "- Gateway", mk_ok ? "" : "- Netmask"); - return false; - } + return err == ESP_OK; } diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 3c7d2330094..5d31341481a 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -138,9 +138,20 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA dhcps_lease_t lease; lease.enable = true; - lease.start_ip.addr = static_cast(local_ip) + (1 << 24); - lease.end_ip.addr = static_cast(local_ip) + (11 << 24); - + uint32_t dhcp_ipaddr = static_cast(local_ip); + // prevents DHCP lease range to overflow subnet/24 range + // there will be 11 addresses for DHCP to lease + uint8_t leaseStart = (uint8_t)(~subnet[3] - 12); + if ((local_ip[3]) < leaseStart) { + lease.start_ip.addr = dhcp_ipaddr + (1 << 24); + lease.end_ip.addr = dhcp_ipaddr + (11 << 24); + } else { + // make range stay in the begining of the netmask range + dhcp_ipaddr = (dhcp_ipaddr & 0x00FFFFFF); + lease.start_ip.addr = dhcp_ipaddr + (1 << 24); + lease.end_ip.addr = dhcp_ipaddr + (11 << 24); + } + log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString(), IPAddress(lease.end_ip.addr).toString()); err = tcpip_adapter_dhcps_option( (tcpip_adapter_dhcp_option_mode_t)TCPIP_ADAPTER_OP_SET, (tcpip_adapter_dhcp_option_id_t)REQUESTED_IP_ADDRESS, From 7d4992a811526f9cfe3aad5a72f66d97f9331dde Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 2 Mar 2022 10:20:43 -0300 Subject: [PATCH 4/5] Adds C++ std::function to Serial.onReceive() (#6364) * Adds C++ std::function to Serial.onReceive() * fixes LOCK macro when disabled --- cores/esp32/HardwareSerial.cpp | 159 +++++++++++++++++++++++++++++++-- cores/esp32/HardwareSerial.h | 37 ++++++-- cores/esp32/esp32-hal-uart.c | 90 ++++--------------- cores/esp32/esp32-hal-uart.h | 5 +- 4 files changed, 201 insertions(+), 90 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 313d0f784ef..61c41cebfb0 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -7,6 +7,7 @@ #include "HardwareSerial.h" #include "soc/soc_caps.h" #include "driver/uart.h" +#include "freertos/queue.h" #ifndef SOC_RX0 #if CONFIG_IDF_TARGET_ESP32 @@ -115,7 +116,131 @@ void serialEventRun(void) } #endif -HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256) {} +#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), +_onReceiveCB(NULL), +_onReceiveErrorCB(NULL), +_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 + xTaskCreate(_uartEventTask, "uart_event_task", 2048, this, configMAX_PRIORITIES - 1, &_eventTask); + 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) +{ + HSERIAL_MUTEX_LOCK(); + // function may be NULL to cancel onReceive() from its respective task + _onReceiveCB = 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::_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)) { + switch(event.type) { + case UART_DATA: + if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB(); + break; + case UART_FIFO_OVF: + log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR); + break; + case UART_BUFFER_FULL: + log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr); + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR); + break; + case UART_BREAK: + log_w("UART%d RX break.", uart->_uart_nr); + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BREAK_ERROR); + break; + case UART_PARITY_ERR: + log_w("UART%d parity error.", uart->_uart_nr); + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_PARITY_ERROR); + break; + case UART_FRAME_ERR: + log_w("UART%d frame error.", uart->_uart_nr); + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FRAME_ERROR); + break; + default: + log_w("UART%d unknown event type %d.", uart->_uart_nr, event.type); + break; + } + } + } + } + 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) { @@ -124,6 +249,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in 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) { @@ -176,11 +309,12 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in _uart = NULL; } } -} - -void HardwareSerial::onReceive(void(*function)(void)) -{ - uartOnReceive(_uart, function); + // 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); + } + HSERIAL_MUTEX_UNLOCK(); } void HardwareSerial::updateBaudRate(unsigned long baud) @@ -188,14 +322,21 @@ void HardwareSerial::updateBaudRate(unsigned long baud) uartSetBaudRate(_uart, baud); } -void HardwareSerial::end(bool turnOffDebug) +void HardwareSerial::end(bool fullyTerminate) { - if(turnOffDebug && uartGetDebug() == _uart_nr) { - uartSetDebug(0); + // 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) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index b1e21bc6b27..7a25b64e37f 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -46,23 +46,40 @@ #define HardwareSerial_h #include - +#include #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_BREAK_ERROR, + UART_BUFFER_FULL_ERROR, + UART_FIFO_OVF_ERROR, + UART_FRAME_ERROR, + UART_PARITY_ERROR +} hardwareSerial_error_t; + +typedef std::function OnReceiveCb; +typedef std::function OnReceiveErrorCb; + class HardwareSerial: public Stream { public: HardwareSerial(int uart_nr); + ~HardwareSerial(); // onReceive will setup a callback for whenever UART data is received - // it will work as UART Rx interrupt - void onReceive(void(*function)(void)); - + // it will work as UART Rx interrupt -- Using C++ 11 std::fuction + void onReceive(OnReceiveCb function); + void onReceiveError(OnReceiveErrorCb function); + 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 turnOffDebug = true); + void end(bool fullyTerminate = true); void updateBaudRate(unsigned long baud); int available(void); int availableForWrite(void); @@ -120,6 +137,16 @@ class HardwareSerial: public Stream int _uart_nr; uart_t* _uart; size_t _rxBufferSize; + OnReceiveCb _onReceiveCB; + OnReceiveErrorCb _onReceiveErrorCB; + TaskHandle_t _eventTask; + + void _createEventTask(void *args); + void _destroyEventTask(void); + static void _uartEventTask(void *args); +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t _lock; +#endif }; extern void serialEventRun(void) __attribute__((weak)); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 157c3640830..adc5d8c2991 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -34,9 +34,7 @@ struct uart_struct_t { uint8_t num; bool has_peek; uint8_t peek_byte; - QueueHandle_t uart_event_queue; - void (*onReceive)(void); - TaskHandle_t envent_task; + QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function }; #if CONFIG_DISABLE_HAL_LOCKS @@ -45,12 +43,12 @@ struct uart_struct_t { #define UART_MUTEX_UNLOCK() static uart_t _uart_bus_array[] = { - {0, false, 0, NULL, NULL, NULL}, + {0, false, 0, NULL}, #if SOC_UART_NUM > 1 - {1, false, 0, NULL, NULL, NULL}, + {1, false, 0, NULL}, #endif #if SOC_UART_NUM > 2 - {2, false, 0, NULL, NULL, NULL}, + {2, false, 0, NULL}, #endif }; @@ -60,12 +58,12 @@ static uart_t _uart_bus_array[] = { #define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock) static uart_t _uart_bus_array[] = { - {NULL, 0, false, 0, NULL, NULL, NULL}, + {NULL, 0, false, 0, NULL}, #if SOC_UART_NUM > 1 - {NULL, 1, false, 0, NULL, NULL, NULL}, + {NULL, 1, false, 0, NULL}, #endif #if SOC_UART_NUM > 2 - {NULL, 2, false, 0, NULL, NULL, NULL}, + {NULL, 2, false, 0, NULL}, #endif }; @@ -84,69 +82,22 @@ uint32_t _get_effective_baudrate(uint32_t baudrate) } } - -void uartOnReceive(uart_t* uart, void(*function)(void)) +// Routines that take care of UART events will be in the HardwareSerial Class code +void uartGetEventQueue(uart_t* uart, QueueHandle_t *q) { - if(uart == NULL || function == NULL) { + // passing back NULL for the Queue pointer when UART is not initialized yet + *q = NULL; + if(uart == NULL) { return; } - UART_MUTEX_LOCK(); - uart->onReceive = function; - UART_MUTEX_UNLOCK(); -} - - -static void uart_event_task(void *args) -{ - uart_t* uart = (uart_t *)args; - uart_event_t event; - for(;;) { - //Waiting for UART event. - if(xQueueReceive(uart->uart_event_queue, (void * )&event, (portTickType)portMAX_DELAY)) { - switch(event.type) { - //Event of UART receving data - case UART_DATA: - if(uart->onReceive) uart->onReceive(); - break; - //Event of HW FIFO overflow detected - case UART_FIFO_OVF: - log_w("UART%d FIFO Overflow. Flushing data. Consider adding Flow Control to your Application.", uart->num); - uart_flush_input(uart->num); - xQueueReset(uart->uart_event_queue); - break; - //Event of UART ring buffer full - case UART_BUFFER_FULL: - log_w("UART%d Buffer Full. Flushing data. Consider encreasing your buffer size of your Application.", uart->num); - uart_flush_input(uart->num); - xQueueReset(uart->uart_event_queue); - break; - //Event of UART RX break detected - case UART_BREAK: - log_w("UART%d RX break.", uart->num); - break; - //Event of UART parity check error - case UART_PARITY_ERR: - log_w("UART%d parity error.", uart->num); - break; - //Event of UART frame error - case UART_FRAME_ERR: - log_w("UART%d frame error.", uart->num); - break; - //Others - default: - log_w("UART%d unknown event type %d.", uart->num, event.type); - break; - } - } - } - vTaskDelete(NULL); + *q = uart->uart_event_queue; + return; } - bool uartIsDriverInstalled(uart_t* uart) { if(uart == NULL) { - return 0; + return false; } if (uart_is_driver_installed(uart->num)) { @@ -222,12 +173,6 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx ESP_ERROR_CHECK(uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV)); } - // Creating UART event Task - xTaskCreate(uart_event_task, "uart_event_task", 2048, uart, configMAX_PRIORITIES - 1, &(uart->envent_task)); - if (!uart->envent_task) { - log_e(" -- UART%d Event Task not Created!", uart_nr); - } - UART_MUTEX_UNLOCK(); uartFlush(uart); @@ -242,11 +187,6 @@ void uartEnd(uart_t* uart) UART_MUTEX_LOCK(); uart_driver_delete(uart->num); - if (uart->envent_task) { - vTaskDelete(uart->envent_task); - uart->envent_task = NULL; - uart->onReceive = NULL; - } UART_MUTEX_UNLOCK(); } diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 22a3a74c86a..25c17ea6ab6 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -22,6 +22,8 @@ extern "C" { #include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" #define SERIAL_5N1 0x8000010 #define SERIAL_6N1 0x8000014 @@ -62,7 +64,8 @@ typedef struct uart_struct_t uart_t; uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd); void uartEnd(uart_t* uart); -void uartOnReceive(uart_t* uart, void(*function)(void)); +// 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); From 4da1051266c2d664846f9eb7bc0d8936cb4b0848 Mon Sep 17 00:00:00 2001 From: Andreas Merkle Date: Wed, 2 Mar 2022 14:25:59 +0100 Subject: [PATCH 5/5] Bugfix of the following problems: Invalid variable argument list used to retrieve length. If length is greater or equal than the available buffer, a memory leak will happen because va_end() is missing. (#6360) --- cores/esp32/esp32-hal-uart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index adc5d8c2991..4581334bba8 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -421,11 +421,12 @@ int log_printf(const char *format, ...) va_list copy; va_start(arg, format); va_copy(copy, arg); - len = vsnprintf(NULL, 0, format, 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; } }