Merge remote-tracking branch 'origin/dev-esp32-idf4' into ble

This commit is contained in:
Philip Gladstone 2022-01-07 21:12:10 +00:00
commit adc188b4b1
18 changed files with 226 additions and 193 deletions

View File

@ -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 */
}

View File

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

View File

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

View File

@ -73,6 +73,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).
@ -125,6 +127,7 @@ menu "NodeMCU modules"
config NODEMCU_CMODULE_NET
bool "Net module"
default "y"
select VFS_SUPPORT_IO
help
Includes the net module (recommended).

View File

@ -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 )

View File

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

View File

@ -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);
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;
}
if (output_redir != LUA_NOREF) { // prepare lua call
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); // push function reference
lua_pushlstring(L, (char *)data, size); // push data
luaL_pcallx(L, 1, 0); // invoke callback
lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir);
lua_pushlstring(L, (char *)chunk->bytes, chunk->used);
luaL_pcallx(L, 1, 0);
}
return size;
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 */
}

View File

@ -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);

View File

@ -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 )

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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()");

View File

@ -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++;

View File

@ -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;

View File

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

View File

@ -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()

View File

@ -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
```