From f2076253a7a40e11ec7c9cc810567382a67e4124 Mon Sep 17 00:00:00 2001 From: Dirk-Willem van Gulik Date: Fri, 11 Oct 2019 14:09:14 +0200 Subject: [PATCH 1/5] Add an aditional (void *) arg to the RMT callback - to allow more flexible handling of the callback (e.g. by passing a private struct or a class pointer). Same pattern as used by the Ticker() and many others. Example updated & new example with a trapoline added. --- cores/esp32/esp32-hal-rmt.c | 39 ++++++++--- cores/esp32/esp32-hal-rmt.h | 10 ++- .../examples/RMT/RMTCallback/RMTCallback.ino | 64 +++++++++++++++++++ 3 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 0a614226c29..6acfdf2fe68 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -94,6 +94,7 @@ struct rmt_obj_s transaction_state_t tx_state; rmt_rx_data_cb_t cb; bool data_alloc; + void * arg; }; /** @@ -104,14 +105,14 @@ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { }; static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL}, }; /** @@ -309,6 +310,7 @@ bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) return true; } + bool rmtBeginReceive(rmt_obj_t* rmt) { if (!rmt) { @@ -342,7 +344,7 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt) } } -bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) +bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg) { if (!rmt && !cb) { return false; @@ -350,6 +352,7 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) int channel = rmt->channel; RMT_MUTEX_LOCK(channel); + rmt->arg = arg; rmt->intr_mode = E_RX_INTR; rmt->tx_state = E_FIRST_HALF; rmt->cb = cb; @@ -376,6 +379,19 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) return true; } +bool rmtEnd(rmt_obj_t* rmt) { + if (!rmt) { + return false; + } + int channel = rmt->channel; + + RMT_MUTEX_LOCK(channel); + RMT.conf_ch[channel].conf1.rx_en = 1; + RMT_MUTEX_UNLOCK(channel); + + return true; +} + bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) { if (!rmt) { @@ -508,6 +524,8 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) rmt->tx_not_rx = tx_not_rx; rmt->buffers =buffers; rmt->channel = channel; + rmt->arg = NULL; + _initPin(pin, channel, tx_not_rx); // Initialize the registers in default mode: @@ -529,6 +547,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock + RMT.apb_conf.fifo_mask = 1; if (tx_not_rx) { @@ -643,7 +662,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) } if (g_rmt_objects[ch].cb) { // actually received data ptr - (g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch)); + (g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg); // restart the reception RMT.conf_ch[ch].conf1.mem_owner = 1; diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 19afcef89c7..338eb0b3d08 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -40,7 +40,7 @@ typedef enum { typedef struct rmt_obj_s rmt_obj_t; -typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len); +typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len, void *arg); typedef struct { union { @@ -84,7 +84,13 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag * and callback with data from ISR * */ -bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb); +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 */ diff --git a/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino b/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino new file mode 100644 index 00000000000..6a4c63bc7e5 --- /dev/null +++ b/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino @@ -0,0 +1,64 @@ +#include "Arduino.h" +#include "esp32-hal.h" + +extern "C" void receive_trampoline(uint32_t *data, size_t len, void * arg); + +class MyProcessor { + private: + rmt_obj_t* rmt_recv = NULL; + float realNanoTick; + uint32_t buff; // rolling buffer of most recent 32 bits. + int at = 0; + + public: + MyProcessor(uint8_t pin, float nanoTicks) { + assert((rmt_recv = rmtInit(21, false, RMT_MEM_192))); + + realNanoTick = rmtSetTick(rmt_recv, nanoTicks); + }; + void begin() { + rmtRead(rmt_recv, receive_trampoline, this); + }; + + void process(rmt_data_t *data, size_t len) { + for (int i = 0; len; len--) { + if (data[i].duration0 == 0) + break; + buff = (buff << 1) | (data[i].level0 ? 1 : 0); + i++; + + if (data[i].duration1 == 0) + break; + buff = (buff << 1) | (data[i].level1 ? 1 : 0); + i++; + }; + }; + uint32_t val() { + return buff; + } +}; + +void receive_trampoline(uint32_t *data, size_t len, void * arg) +{ + MyProcessor * p = (MyProcessor *)arg; + p->process((rmt_data_t*) data, len); +} + +// Attach 3 processors to GPIO 4, 5 and 10 with different tick/speeds. +MyProcessor mp1 = MyProcessor(4, 1000); +MyProcessor mp2 = MyProcessor(5, 1000); +MyProcessor mp3 = MyProcessor(10, 500); + +void setup() +{ + Serial.begin(115200); + mp1.begin(); + mp2.begin(); + mp3.begin(); +} + +void loop() +{ + Serial.printf("GPIO 4: %08x 5: %08x 6: %08x\n", mp1.val(), mp2.val(), mp3.val()); + delay(500); +} From 46833249397cc66c109594f6ff2f0674289ee443 Mon Sep 17 00:00:00 2001 From: Dirk-Willem van Gulik Date: Fri, 11 Oct 2019 14:16:14 +0200 Subject: [PATCH 2/5] Fix example for new API --- libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino index 29ab824d79d..ba3be7d66e7 100644 --- a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino +++ b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -172,7 +172,7 @@ void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){ } } -extern "C" void receive_data(uint32_t *data, size_t len) +extern "C" void receive_data(uint32_t *data, size_t len, void * arg) { parseRmt((rmt_data_t*) data, len, channels); } From 504709ca3ed6aa0c3caa39336854f83aa127a28e Mon Sep 17 00:00:00 2001 From: Dirk-Willem van Gulik Date: Fri, 11 Oct 2019 14:51:40 +0200 Subject: [PATCH 3/5] Fix lint warnings --- cores/esp32/esp32-hal-rmt.h | 1 - 1 file changed, 1 deletion(-) diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 338eb0b3d08..c338a2cb36d 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -92,7 +92,6 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg); */ bool rmtEnd(rmt_obj_t* rmt); - /* Additional interface */ /** From f55ae5e7d16bcb8b6f0fa4280cd1a1c70d80907b Mon Sep 17 00:00:00 2001 From: Dirk-Willem van Gulik Date: Fri, 11 Oct 2019 14:58:31 +0200 Subject: [PATCH 4/5] Add a second missed example. --- libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino index ba3be7d66e7..39978d26dab 100644 --- a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino +++ b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -192,7 +192,7 @@ void setup() Serial.printf("real tick set to: %fns\n", realTick); // Ask to start reading - rmtRead(rmt_recv, receive_data); + rmtRead(rmt_recv, receive_data, NULL); } void loop() From d13440c30cc3d0cea8091e87f0333a1eb1936cde Mon Sep 17 00:00:00 2001 From: Dirk-Willem van Gulik Date: Fri, 18 Oct 2019 21:33:08 +0200 Subject: [PATCH 5/5] Correct timeout & improve socket error handling. --- libraries/WiFiClientSecure/src/ssl_client.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/libraries/WiFiClientSecure/src/ssl_client.cpp b/libraries/WiFiClientSecure/src/ssl_client.cpp index ce8b31c727c..f015d17cdaf 100644 --- a/libraries/WiFiClientSecure/src/ssl_client.cpp +++ b/libraries/WiFiClientSecure/src/ssl_client.cpp @@ -77,12 +77,16 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { if(timeout <= 0){ - timeout = 30000; + timeout = 30000; // Milli seconds. } - lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); - lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); - lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); + timeval so_timeout = { .tv_sec = timeout / 1000, .tv_usec = (timeout % 1000) * 1000 }; + +#define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }} + ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &so_timeout, sizeof(so_timeout)),"SO_RCVTIMEO"); + ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &so_timeout, sizeof(so_timeout)),"SO_SNDTIMEO"); + + ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY"); + ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE"); } else { log_e("Connect to Server failed!"); return -1;