From 5c59c57a166da478907f0daac1f64b8385ce27a9 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Fri, 22 Oct 2021 12:38:07 +1100 Subject: [PATCH 1/7] Implement tmr.wdclr() --- components/modules/tmr.c | 10 ++++++++++ docs/modules/tmr.md | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/components/modules/tmr.c b/components/modules/tmr.c index 1bc53cdd..dda9e33c 100644 --- a/components/modules/tmr.c +++ b/components/modules/tmr.c @@ -233,6 +233,15 @@ static int tmr_create( lua_State *L ) { } +// Lua: tmr.wdclr() +static int tmr_wdclr( lua_State *L ) +{ + // Suspend ourselves momentarily to let the IDLE task do its thing + vTaskDelay(1); + return 0; +} + + // Module function map LROT_BEGIN(tmr_dyn, NULL, LROT_MASK_GC_INDEX) @@ -249,6 +258,7 @@ LROT_END(tmr_dyn, NULL, LROT_MASK_GC_INDEX) LROT_BEGIN(tmr, NULL, 0) LROT_FUNCENTRY( create, tmr_create ) + LROT_FUNCENTRY( wdclr, tmr_wdclr ) LROT_NUMENTRY ( ALARM_SINGLE, TIMER_MODE_SINGLE ) LROT_NUMENTRY ( ALARM_SEMI, TIMER_MODE_SEMI ) LROT_NUMENTRY ( ALARM_AUTO, TIMER_MODE_AUTO ) diff --git a/docs/modules/tmr.md b/docs/modules/tmr.md index 8f1d19d2..39223563 100644 --- a/docs/modules/tmr.md +++ b/docs/modules/tmr.md @@ -212,3 +212,37 @@ none #### See also [`tmr.obj:register()`](#tmrobjregister) + + +## tmr.wdclr() + +Resets the watchdog timer to prevent a reboot due to a perceived hung task. + +Use with caution, as this could prevent a reboot to recover from a +genuinely hung task. + +On the ESP32, the `tmr.wdclr()` function is implemented as a task yield +to let the system "IDLE" task do the necessary watchdog maintenance. +Overuse of this function is likely to result in degraded performance. + +#### Syntax +`tmr.wdclr()` + +#### Parameters +none + +#### Returns +`nil` + +#### Example +```lua +function long_running_function() + while 1 + do + if some_condition then break end + -- do some heavy calculation here, for example + tmr.wdclr() + end +end +``` + From 6db8c434808623ecb71ca9839af940fccbff32c0 Mon Sep 17 00:00:00 2001 From: Bernd Meyer Date: Thu, 4 Nov 2021 18:55:08 +1100 Subject: [PATCH 2/7] Prevent memory leak in UART driver when message handling is slow --- components/platform/platform.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/platform/platform.c b/components/platform/platform.c index d0178ea9..6198b2a7 100644 --- a/components/platform/platform.c +++ b/components/platform/platform.c @@ -116,12 +116,6 @@ static void task_uart( void *pvParameters ){ if(xQueueReceive(uart_status[id].queue, (void * )&event, (portTickType)portMAX_DELAY)) { switch(event.type) { case UART_DATA: { - post = (uart_event_post_t*)malloc(sizeof(uart_event_post_t)); - if(post == NULL) { - ESP_LOGE(UART_TAG, "Can not alloc memory in task_uart()"); - // reboot here? - continue; - } // Attempt to coalesce received bytes to reduce risk of overrunning // the task event queue. size_t len; @@ -129,6 +123,13 @@ static void task_uart( void *pvParameters ){ len = event.size; if (len == 0) continue; // we already gobbled all the bytes + + post = (uart_event_post_t*)malloc(sizeof(uart_event_post_t)); + if(post == NULL) { + ESP_LOGE(UART_TAG, "Can not alloc memory in task_uart()"); + // reboot here? + continue; + } post->data = malloc(len); if(post->data == NULL) { ESP_LOGE(UART_TAG, "Can not alloc memory in task_uart()"); From 9a2fb84512a5768af0b97dcd8783b59b47e4c97b Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Thu, 4 Nov 2021 20:51:59 +1100 Subject: [PATCH 3/7] Fix broken sjson module init. --- components/modules/sjson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/modules/sjson.c b/components/modules/sjson.c index 8ed7ce1a..cf49ef56 100644 --- a/components/modules/sjson.c +++ b/components/modules/sjson.c @@ -1037,7 +1037,7 @@ LROT_END(sjson, NULL, 0) LUALIB_API int luaopen_sjson (lua_State *L) { luaL_rometatable(L, "sjson.decoder", LROT_TABLEREF(sjson_decoder_map)); luaL_rometatable(L, "sjson.encoder", LROT_TABLEREF(sjson_encoder_map)); - return 1; + return 0; } NODEMCU_MODULE(SJSON, "sjson", sjson, luaopen_sjson); From a0c9085cca952f992ef937b93e224cbd6d4860f0 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Thu, 4 Nov 2021 22:17:55 +1100 Subject: [PATCH 4/7] Make node.output() RTOS thread safe. Also removed old, very unsafe node.osoutput(). We're now integrating cleanly with the IDF/newlib way of redirecting stdout. Added necessary depends in Kconfig to ensure VFS support is enabled, as otherwise you'd only get a mysterious crash when attempting to enable output redirection. --- components/lua/common/linput.c | 20 ---- components/lua/lua-5.1/luaconf.h | 2 +- components/lua/lua-5.3/lauxlib.h | 2 +- components/modules/Kconfig | 3 + components/modules/node.c | 170 ++++++++++++++++++------------- docs/modules/node.md | 89 +--------------- 6 files changed, 108 insertions(+), 178 deletions(-) diff --git a/components/lua/common/linput.c b/components/lua/common/linput.c index 2dba1cfd..bda08422 100644 --- a/components/lua/common/linput.c +++ b/components/lua/common/linput.c @@ -97,23 +97,3 @@ size_t feed_lua_input(const char *buf, size_t n) return n; // we consumed/buffered all the provided data } - - -void output_redirect(const char *str, size_t l) { - lua_State *L = lua_getstate(); - int n = lua_gettop(L); - lua_pushliteral(L, "stdout"); - lua_rawget(L, LUA_REGISTRYINDEX); /* fetch reg.stdout */ - if (lua_istable(L, -1)) { /* reg.stdout is pipe */ - lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdout[1] */ - lua_insert(L, -2); /* and move above the pipe ref */ - lua_pushlstring(L, str, l); - if (lua_pcall(L, 2, 0, 0) != LUA_OK) { /* Reg.stdout:write(str) */ - lua_writestringerror("error calling stdout:write(%s)\n", lua_tostring(L, -1)); - esp_restart(); - } - } else { /* reg.stdout == nil */ - printf(str, l); - } - lua_settop(L, n); /* Make sure all code paths leave stack unchanged */ -} diff --git a/components/lua/lua-5.1/luaconf.h b/components/lua/lua-5.1/luaconf.h index 613d23f8..2b43edbd 100644 --- a/components/lua/lua-5.1/luaconf.h +++ b/components/lua/lua-5.1/luaconf.h @@ -305,7 +305,7 @@ extern int readline4lua(const char *prompt, char *buffer, int length); ** They are only used in libraries and the stand-alone program. (The #if ** avoids including 'stdio.h' everywhere.) */ -#ifdef LUA_USE_ESP +#ifdef LUA_USE_ESP8266 void output_redirect(const char *str, size_t l); #define lua_writestring(s,l) output_redirect((s),(l)) #else diff --git a/components/lua/lua-5.3/lauxlib.h b/components/lua/lua-5.3/lauxlib.h index 2aff96ba..7a0ce1ee 100644 --- a/components/lua/lua-5.3/lauxlib.h +++ b/components/lua/lua-5.3/lauxlib.h @@ -230,7 +230,7 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, /* print a string */ #if !defined(lua_writestring) -#ifdef LUA_USE_ESP +#ifdef LUA_USE_ESP8266 void output_redirect(const char *str, size_t l); #define lua_writestring(s,l) output_redirect((s),(l)) #else diff --git a/components/modules/Kconfig b/components/modules/Kconfig index 749e0155..4d92ad8c 100644 --- a/components/modules/Kconfig +++ b/components/modules/Kconfig @@ -65,6 +65,8 @@ menu "NodeMCU modules" config NODEMCU_CMODULE_FILE bool "File module" default "y" + select VFS_SUPPORT_IO + select VFS_SUPPORT_DIR help Includes the file module (recommended). @@ -117,6 +119,7 @@ menu "NodeMCU modules" config NODEMCU_CMODULE_NET bool "Net module" default "y" + select VFS_SUPPORT_IO help Includes the net module (recommended). diff --git a/components/modules/node.c b/components/modules/node.c index 785f951c..ba4d76cc 100644 --- a/components/modules/node.c +++ b/components/modules/node.c @@ -399,26 +399,90 @@ static int node_input( lua_State* L ) // When there is any write to the replaced stdout, our function redir_write will be called. // we can then invoke the lua callback. -static FILE *oldstdout; // keep the old stdout, e.g., the uart0 -lua_ref_t output_redir = LUA_NOREF; // this will hold the Lua callback -int serial_debug = 0; // whether or not to write also to uart -const char *VFS_REDIR = "/redir"; // virtual filesystem mount point +// A buffer size that should be sufficient for most cases, yet not so large +// as to present an issue. +# define OUTPUT_CHUNK_SIZE 127 +typedef struct { + uint8_t used; + uint8_t bytes[OUTPUT_CHUNK_SIZE]; +} output_chunk_t; + +static task_handle_t output_task; // for getting output into the LVM thread +static lua_ref_t output_redir = LUA_NOREF; // this will hold the Lua callback +static FILE *serial_debug; // the console uart, if wanted +static const char *VFS_REDIR = "/redir"; // virtual filesystem mount point // redir_write will be called everytime any code writes to stdout when -// redirection is active +// redirection is active, from ANY RTOS thread ssize_t redir_write(int fd, const void *data, size_t size) { - if (serial_debug) // if serial_debug is nonzero, write to uart - fwrite(data, sizeof(char), size, oldstdout); - - if (output_redir != LUA_NOREF) { // prepare lua call - lua_State *L = lua_getstate(); - lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir); // push function reference - lua_pushlstring(L, (char *)data, size); // push data - luaL_pcallx(L, 1, 0); // invoke callback + UNUSED(fd); + if (size) + { + size_t n = (size > OUTPUT_CHUNK_SIZE) ? OUTPUT_CHUNK_SIZE : size; + output_chunk_t *chunk = malloc(sizeof(output_chunk_t)); + chunk->used = (uint8_t)n; + memcpy(chunk->bytes, data, n); + _Static_assert(sizeof(task_param_t) >= sizeof(chunk), "cast error below"); + if (!task_post_high(output_task, (task_param_t)chunk)) + { + static const char overflow[] = "E: output overflow\n"; + fwrite(overflow, sizeof(overflow) -1, sizeof(char), serial_debug); + free(chunk); + return -1; } - return size; + + if (serial_debug) + { + size_t written = 0; + while (written < n) + { + size_t w = fwrite( + data + written, sizeof(char), n - written, serial_debug); + if (w > 0) + written += w; + else break; + } + } + + return n; + } + else + return 0; } +void redir_output(task_param_t param, task_prio_t prio) +{ + UNUSED(prio); + output_chunk_t *chunk = (output_chunk_t *)param; + bool redir_active = (output_redir != LUA_NOREF); + if (redir_active) + { + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir); + lua_pushlstring(L, (char *)chunk->bytes, chunk->used); + luaL_pcallx(L, 1, 0); + } + free(chunk); +} + +#if !defined(CONFIG_ESP_CONSOLE_NONE) +static const char *default_console_name(void) +{ + return +#if defined(CONFIG_ESP_CONSOLE_UART) +# define STRINGIFY(x) STRINGIFY2(x) +# define STRINGIFY2(x) #x + "/dev/uart/" STRINGIFY(CONFIG_ESP_CONSOLE_UART_NUM); +#undef STRINGIFY2 +#undef STRINGIFY +#elif defined(CONFIG_ESP_CONSOLE_USB_CDC) + "/dev/cdcacm"; +#elif defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) + "/dev/usbserjtag"; +#endif +} +#endif + // redir_open is called when fopen() is called on /redir/xxx int redir_open(const char *path, int flags, int mode) { return 79; // since we only have one "file", just return some fd number to make the VFS system happy @@ -426,6 +490,11 @@ int redir_open(const char *path, int flags, int mode) { // Lua: node.output(func, serial_debug) static int node_output(lua_State *L) { + if (serial_debug) + { + fclose(serial_debug); + serial_debug = NULL; + } if (lua_isfunction(L, 1)) { if (output_redir == LUA_NOREF) { // create an instance of a virtual filesystem so we can use fopen @@ -439,69 +508,25 @@ static int node_output(lua_State *L) { }; // register this filesystem under the `/redir` namespace ESP_ERROR_CHECK(esp_vfs_register(VFS_REDIR, &redir_fs, NULL)); - oldstdout = stdout; // save the previous stdout - stdout = fopen(VFS_REDIR, "w"); // open the new one for writing + freopen(VFS_REDIR, "w", stdout); + + if (lua_isnoneornil(L, 2) || + (lua_isnumber(L, 2) && lua_tonumber(L, 2))) + serial_debug = fopen(default_console_name(), "w"); } else { luaX_unset_ref(L, &output_redir); // dereference previous callback } luaX_set_ref(L, 1, &output_redir); // set the callback } else { if (output_redir != LUA_NOREF) { - fclose(stdout); // close the redirected stdout - stdout = oldstdout; // restore original stdout - ESP_ERROR_CHECK(esp_vfs_unregister(VFS_REDIR)); // unregister redir filesystem - luaX_unset_ref(L, &output_redir); // forget callback - } - serial_debug = 1; - return 0; - } - - // second parameter indicates whether output will also be sent to old stdout - if (lua_isnumber(L, 2)) { - serial_debug = lua_tointeger(L, 2); - if (serial_debug != 0) - serial_debug = 1; - } else { - serial_debug = 1; // default to 1 - } - - return 0; -} - -// The implementation of node.osoutput redirect all OS logging to Lua space -lua_ref_t os_output_redir = LUA_NOREF; // this will hold the Lua callback -static vprintf_like_t oldvprintf; // keep the old vprintf - -// redir_vprintf will be called everytime the OS attempts to print a trace statement -int redir_vprintf(const char *fmt, va_list ap) -{ - static char data[128]; - int size = vsnprintf(data, 128, fmt, ap); - - if (os_output_redir != LUA_NOREF) { // prepare lua call - lua_State *L = lua_getstate(); - lua_rawgeti(L, LUA_REGISTRYINDEX, os_output_redir); // push function reference - lua_pushlstring(L, (char *)data, size); // push data - luaL_pcallx(L, 1, 0); // invoke callback - } - return size; -} - - -// Lua: node.output(func, serial_debug) -static int node_osoutput(lua_State *L) { - if (lua_isfunction(L, 1)) { - if (os_output_redir == LUA_NOREF) { - // register our log redirect first time this is invoked - oldvprintf = esp_log_set_vprintf(redir_vprintf); - } else { - luaX_unset_ref(L, &os_output_redir); // dereference previous callback - } - luaX_set_ref(L, 1, &os_output_redir); // set the callback - } else { - if (os_output_redir != LUA_NOREF) { - esp_log_set_vprintf(oldvprintf); - luaX_unset_ref(L, &os_output_redir); // forget callback +#if defined(CONFIG_ESP_CONSOLE_NONE) + fclose(stdout); +#else + // reopen the console device onto the stdout stream + freopen(default_console_name(), "w", stdout); +#endif + ESP_ERROR_CHECK(esp_vfs_unregister(VFS_REDIR)); + luaX_unset_ref(L, &output_redir); } } @@ -836,7 +861,6 @@ LROT_BEGIN(node, NULL, 0) LROT_FUNCENTRY( heap, node_heap ) LROT_FUNCENTRY( input, node_input ) LROT_FUNCENTRY( output, node_output ) - LROT_FUNCENTRY( osoutput, node_osoutput ) LROT_FUNCENTRY( osprint, node_osprint ) LROT_FUNCENTRY( restart, node_restart ) LROT_FUNCENTRY( setonerror, node_setonerror ) @@ -849,6 +873,8 @@ LROT_END(node, NULL, 0) int luaopen_node(lua_State *L) { + output_task = task_get_id(redir_output); + lua_settop(L, 0); return node_setonerror(L); /* set default onerror action */ } diff --git a/docs/modules/node.md b/docs/modules/node.md index 82d36d5d..eefd8720 100644 --- a/docs/modules/node.md +++ b/docs/modules/node.md @@ -301,68 +301,20 @@ Reload LFS with the flash image provided. Flash images can be generated on the h - The reload process internally makes multiple passes through the LFS image file. The first pass validates the file and header formats and detects many errors. If any is detected then an error string is returned. -## node.key() --deprecated - -Defines action to take on button press (on the old devkit 0.9), button connected to GPIO 16. - -This function is only available if the firmware was compiled with DEVKIT_VERSION_0_9 defined. - -#### Syntax -`node.key(type, function())` - -#### Parameters - - `type`: type is either string "long" or "short". long: press the key for 3 seconds, short: press shortly(less than 3 seconds) - - `function`: user defined function which is called when key is pressed. If nil, remove the user defined function. Default function: long: change LED blinking rate, short: reset chip - -#### Returns -`nil` - -#### Example -```lua -node.key("long", function() print('hello world') end) -``` -#### See also -[`node.led()`](#nodeled-deprecated) - -## node.led() --deprecated - -Sets the on/off time for the LED (on the old devkit 0.9), with the LED connected to GPIO16, multiplexed with [`node.key()`](#nodekey-deprecated). - -This function is only available if the firmware was compiled with DEVKIT_VERSION_0_9 defined. - -#### Syntax -`node.led(low, high)` - -#### Parameters - - `low` LED off time, LED keeps on when low=0. Unit: milliseconds, time resolution: 80~100ms - - `high` LED on time. Unit: milliseconds, time resolution: 80~100ms - -#### Returns -`nil` - -#### Example -```lua --- turn led on forever. -node.led(0) -``` - -#### See also -[`node.key()`](#nodekey-deprecated) - ## node.output() -Redirects the Lua interpreter output to a callback function. Optionally also prints it to the serial console. +Redirects all standard output (`stdout`) to a callback function. Optionally also prints it to the console device, as specified in Kconfig under the "ESP System Settings" section. !!! note "Note:" - Do **not** attempt to `print()` or otherwise induce the Lua interpreter to produce output from within the callback function. Doing so results in infinite recursion, and leads to a watchdog-triggered restart. + Do **not** attempt to `print()` or otherwise induce the Lua interpreter to produce output from within the callback function. Doing so results in infinite recursion, and leads to a crash or watchdog-triggered restart. #### Syntax -`node.output(function(str), serial_output)` +`node.output(function(str), console_output)` #### Parameters - `output_fn(str)` a function accept every output as str, and can send the output to a socket (or maybe a file). `nil` to unregister the previous function. - - `serial_output` 1 output also sent out the serial port. 0: no serial output. Defaults to 1 if not specified. + - `console_output` 1 output also sent out the console port. 0: no console output. Defaults to 1 if not specified. #### Returns `nil` @@ -372,7 +324,7 @@ Redirects the Lua interpreter output to a callback function. Optionally also pri function tonet(str) sk:send(str) end -node.output(tonet, 1) -- serial also get the lua output. +node.output(tonet, 1) -- console also get the lua output. ``` ```lua @@ -403,37 +355,6 @@ node.output(nil, 0) #### See also [`node.input()`](#nodeinput) -## node.osoutput() - -Redirects the debugging output from the Espressif SDK to a callback function allowing it to be captured or processed in Lua. - -####Syntax -`node.osoutput(function(str))` - -#### Parameters - -- `function(str)` a function accepts debugging output as str, and can send the output to a socket (or maybe a file). `nil` to unregister the previous function. - -#### Returns - -Nothing - -#### Example - -```lua -function luaprint(str) - print("lua space: "str) -end -node.osoutput(luaprint) -``` - -```lua --- disable all output completely -node.osoutput(nil) -``` - -## node.readvdd33() --deprecated -Moved to [`adc.readvdd33()`](adc/#adcreadvdd33). ## node.restart() From 4b4ce47ed1f76ccd3b341821155f4253c617a441 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Sat, 13 Nov 2021 12:26:49 +1100 Subject: [PATCH 5/7] Fix file listing on submounts. --- components/modules/file.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/modules/file.c b/components/modules/file.c index 6cf57ca8..e77ab54a 100644 --- a/components/modules/file.c +++ b/components/modules/file.c @@ -44,8 +44,13 @@ static int file_list( lua_State* L ) lua_newtable( L ); struct dirent *e; while ((e = readdir(dir))) { + char *fname; + asprintf(&fname, "%s/%s", dirname, e->d_name); + if (!fname) + return luaL_error(L, "no memory"); struct stat st = { 0, }; - stat(e->d_name, &st); + stat(fname, &st); + free(fname); lua_pushinteger(L, st.st_size); lua_setfield(L, -2, e->d_name); } From 6e632649637728d0b506b5ca81bd0d5d5af31b34 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Sun, 2 Jan 2022 13:31:58 +1100 Subject: [PATCH 6/7] Support interface-specific hostname on ethernet interface. (#3487) --- components/modules/eth.c | 13 +++++++++++++ docs/modules/eth.md | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/components/modules/eth.c b/components/modules/eth.c index 21d96c12..7ccefad5 100644 --- a/components/modules/eth.c +++ b/components/modules/eth.c @@ -230,6 +230,18 @@ static int leth_set_ip( lua_State *L ) return 0; } +static int leth_set_hostname(lua_State *L) +{ + const char *hostname = luaL_checkstring(L, 1); + + esp_err_t err = esp_netif_set_hostname(eth, hostname); + + if (err != ESP_OK) + return luaL_error (L, "failed to set hostname, code %d", err); + + return 0; +} + static int leth_on( lua_State *L ) { const char *event_name = luaL_checkstring( L, 1 ); @@ -338,6 +350,7 @@ LROT_BEGIN(eth, NULL, 0) LROT_FUNCENTRY( get_mac, leth_get_mac ) LROT_FUNCENTRY( set_mac, leth_set_mac ) LROT_FUNCENTRY( set_ip, leth_set_ip ) + LROT_FUNCENTRY( set_hostname, leth_set_hostname ) LROT_NUMENTRY( PHY_DP83848, ETH_PHY_DP83848 ) LROT_NUMENTRY( PHY_IP101, ETH_PHY_IP101 ) diff --git a/docs/modules/eth.md b/docs/modules/eth.md index 47cb22cf..3802586c 100644 --- a/docs/modules/eth.md +++ b/docs/modules/eth.md @@ -200,3 +200,21 @@ eth.set_ip({ dns = "8.8.8.8" }) ``` + +## eth.set_hostname() +Configures the interface specific hostname for the ethernet interface. The ethernet interface must be initialized before the hostname can be configured. + +By default the system hostname is used, as configured in the menu config. + +#### Syntax +```lua +eth.set_hostname(hostname) +``` + +#### Parameters +- `hostname` the hostname to use on the ethernet interface + +#### Returns +`nil` + +An error is thrown in case the hostname cannot be set. From 8b1ef35b66d47195aeebad27ba746dea03ae7167 Mon Sep 17 00:00:00 2001 From: Christoph Thelen Date: Fri, 7 Jan 2022 04:50:28 +0100 Subject: [PATCH 7/7] Consider RMT channel limitations at allocation time. (#3481) * Consider RMT channel limitations at allocation time. The ESP32-C3 is limited to TX on channel 0-1 and RX on channel 2-3. --- components/platform/dht.c | 2 +- components/platform/include/platform_rmt.h | 3 ++- components/platform/onewire.c | 4 ++-- components/platform/platform_rmt.c | 25 ++++++++++++++++++++-- components/platform/ws2812.c | 2 +- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/components/platform/dht.c b/components/platform/dht.c index aaf47f1b..70331005 100644 --- a/components/platform/dht.c +++ b/components/platform/dht.c @@ -76,7 +76,7 @@ static void dht_deinit( void ) static int dht_init( uint8_t gpio_num ) { // acquire an RMT module for RX - if ((dht_rmt.channel = platform_rmt_allocate( 1 )) >= 0) { + if ((dht_rmt.channel = platform_rmt_allocate( 1, RMT_MODE_RX )) >= 0) { #ifdef DHT_DEBUG ESP_LOGI("dht", "RMT RX channel: %d", dht_rmt.channel); diff --git a/components/platform/include/platform_rmt.h b/components/platform/include/platform_rmt.h index fbdbbc3d..7c368db1 100644 --- a/components/platform/include/platform_rmt.h +++ b/components/platform/include/platform_rmt.h @@ -14,13 +14,14 @@ * @brief Allocate an RMT channel. * * @param num_mem Number of memory blocks. + * @param mode Mode of the channel, RMT_MODE_TX allocates a TX channel, RMT_MODE_RX an RX channel. * * @return * - Channel number when successful * - -1 if no channel available * */ -int platform_rmt_allocate( uint8_t num_mem ); +int platform_rmt_allocate( uint8_t num_mem, rmt_mode_t mode ); /** * @brief Release a previously allocated RMT channel. diff --git a/components/platform/onewire.c b/components/platform/onewire.c index 383ee7cb..5472eeea 100644 --- a/components/platform/onewire.c +++ b/components/platform/onewire.c @@ -113,8 +113,8 @@ static int onewire_rmt_init( uint8_t gpio_num ) } // acquire an RMT module for TX and RX each - if ((ow_rmt.tx = platform_rmt_allocate( 1 )) >= 0) { - if ((ow_rmt.rx = platform_rmt_allocate( 1 )) >= 0) { + if ((ow_rmt.tx = platform_rmt_allocate( 1, RMT_MODE_TX )) >= 0) { + if ((ow_rmt.rx = platform_rmt_allocate( 1, RMT_MODE_RX )) >= 0) { #ifdef OW_DEBUG ESP_LOGI("ow", "RMT TX channel: %d", ow_rmt.tx); diff --git a/components/platform/platform_rmt.c b/components/platform/platform_rmt.c index 972fc0e5..e189c431 100644 --- a/components/platform/platform_rmt.c +++ b/components/platform/platform_rmt.c @@ -24,12 +24,33 @@ static bool rmt_channel_check( uint8_t channel, uint8_t num_mem ) return rmt_channel_check( channel-1, num_mem-1); } -int platform_rmt_allocate( uint8_t num_mem ) +#if defined(CONFIG_IDF_TARGET_ESP32C3) +int platform_rmt_allocate( uint8_t num_mem, rmt_mode_t mode ) +#else +int platform_rmt_allocate( uint8_t num_mem, rmt_mode_t mode __attribute__((unused))) +#endif { int channel; + int alloc_min; + int alloc_max; uint8_t tag = 1; - for (channel = RMT_CHANNEL_MAX-1; channel >= 0; channel--) { +#if defined(CONFIG_IDF_TARGET_ESP32C3) + /* The ESP32-C3 is limited to TX on channel 0-1 and RX on channel 2-3. */ + if( mode==RMT_MODE_TX ) { + alloc_min = 0; + alloc_max = SOC_RMT_TX_CANDIDATES_PER_GROUP - 1; + } else { + alloc_min = RMT_CHANNEL_MAX - SOC_RMT_RX_CANDIDATES_PER_GROUP; + alloc_max = RMT_CHANNEL_MAX - 1; + } +#else + /* The other ESP32 devices can do RX and TX on all channels. */ + alloc_min = 0; + alloc_max = RMT_CHANNEL_MAX - 1; +#endif + + for (channel = alloc_max; channel >= alloc_min; channel--) { if (rmt_channel_alloc[channel] == 0) { if (rmt_channel_check( channel, num_mem )) { rmt_channel_alloc[channel] = tag++; diff --git a/components/platform/ws2812.c b/components/platform/ws2812.c index 6b1b9ddc..67fa562d 100644 --- a/components/platform/ws2812.c +++ b/components/platform/ws2812.c @@ -138,7 +138,7 @@ int platform_ws2812_setup( uint8_t gpio_num, uint8_t num_mem, const uint8_t *dat { int channel; - if ((channel = platform_rmt_allocate( num_mem )) >= 0) { + if ((channel = platform_rmt_allocate( num_mem, RMT_MODE_TX )) >= 0) { ws2812_chain_t *chain = &(ws2812_chains[channel]); chain->valid = true;