diff --git a/components/modules/ble.c b/components/modules/ble.c index 8b5abe03..fc182e3a 100644 --- a/components/modules/ble.c +++ b/components/modules/ble.c @@ -64,6 +64,8 @@ static QueueHandle_t response_queue; static int struct_pack_index; static int struct_unpack_index; +static enum { STOPPED, RUNNING, SHUTTING } inited; + static int seqno; // Note that the buffer should be freed @@ -490,7 +492,21 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) { if (lua_getfield(L, -1, "value") != LUA_TNIL) { chr->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE; - lua_pop(L, 1); // pop off value + + int flags = 0; + lua_getfield(L, -2, "read"); + if (lua_isboolean(L, 1) && lua_toboolean(L, -1)) { + flags = BLE_GATT_CHR_F_READ; + } + lua_getfield(L, -3, "write"); + if (lua_isboolean(L, 1) && lua_toboolean(L, -1)) { + flags |= BLE_GATT_CHR_F_WRITE; + } + if (flags) { + chr->flags = flags; + } + + lua_pop(L, 3); // pop off value, read, write } else { lua_getfield(L, -2, "read"); if (!lua_isnoneornil (L, -1)) { @@ -729,6 +745,10 @@ lble_start_advertising() { const char *name = gadget_name; int rc; + if (inited != RUNNING) { + return 0; + } + /* Figure out address to use while advertising (no privacy for now) */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { @@ -850,6 +870,9 @@ gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) static int lble_init(lua_State *L) { + if (inited != STOPPED) { + return luaL_error(L, "ble is already running"); + } if (!struct_pack_index) { lua_getglobal(L, "struct"); lua_getfield(L, -1, "pack"); @@ -924,10 +947,14 @@ static int lble_init(lua_State *L) { synced = true; } + inited = RUNNING; + return 0; } static int lble_shutdown(lua_State *L) { + inited = SHUTTING; + if (nimble_port_stop()) { return luaL_error(L, "Failed to stop the NIMBLE task"); } @@ -938,6 +965,8 @@ static int lble_shutdown(lua_State *L) { return luaL_error(L, "Failed to shutdown the BLE controller"); } + inited = STOPPED; + return 0; } diff --git a/components/modules/file.c b/components/modules/file.c index 933bfea8..8ced231d 100644 --- a/components/modules/file.c +++ b/components/modules/file.c @@ -383,60 +383,40 @@ static int file_stat( lua_State* L ) // g_read() static int file_g_read( lua_State* L, int n, int16_t end_char, int fd ) { - char *heap_mem = NULL; - - if(n <= 0) - n = FILE_READ_CHUNK; - - if(end_char < 0 || end_char >255) - end_char = EOF; + int i, j; + luaL_Buffer b; + char p[LUAL_BUFFERSIZE/2]; if(!fd) return luaL_error(L, "open a file first"); - char *p; - int i; - size_t bufsize = n; + luaL_buffinit(L, &b); - if (n > LUAL_BUFFERSIZE) { - // get buffer from heap - p = heap_mem = luaM_malloc(L, bufsize); - } else { - // small chunks go onto the stack - p = alloca(bufsize); - } + for (j = 0; j < n; j += sizeof(p)) { + int nwanted = (n - j >= sizeof(p)) ? sizeof(p) : n - j; + int nread = vfs_read(fd, p, nwanted); - n = vfs_read(fd, p, n); - // bypass search if no end character provided - if (n > 0 && end_char != EOF) { - for (i = 0; i < n; ++i) - if (p[i] == end_char) - { - ++i; + if (nread == VFS_RES_ERR || nread == 0) { + if (j > 0) { break; } - } else { - i = n; + lua_pushnil(L); + return 1; + } + + for (i = 0; i < nread; ++i) { + luaL_addchar(&b, p[i]); + if (p[i] == end_char) { + vfs_lseek(fd, -nread + i + 1, VFS_SEEK_CUR); //reposition after end char found + nread = 0; // force break on outer loop + break; + } + } + + if (nread < nwanted) + break; } - - int err = 0; - - if (i == 0 || n == VFS_RES_ERR) { - lua_pushnil(L); - } else { - vfs_lseek(fd, -(n - i), VFS_SEEK_CUR); - err = luaX_pushlstring(L, p, i); // On error it will return nonzero and leave a message on top of the stack. - } - - if (heap_mem) { - luaN_freearray(L, heap_mem, bufsize); - } - - if (err){ - lua_error(L); // luaX_pushlstring failed and the error message is on top of the stack. Throw it. - // never returns - } - + luaL_pushresult(&b); return 1; } @@ -476,6 +456,29 @@ static int file_readline( lua_State* L ) return file_g_read(L, FILE_READ_CHUNK, '\n', fd); } + +// Lua: getfile(filename) +static int file_getfile( lua_State* L ) +{ + // Warning this code C calls other file_* routines to avoid duplication code. These + // use Lua stack addressing of arguments, so this does Lua stack maniplation to + // align these + int ret_cnt = 0; + lua_settop(L ,1); + // Stack [1] = FD + file_open(L); + // Stack [1] = filename; [2] = FD or nil + if (!lua_isnil(L, -1)) { + lua_remove(L, 1); // dump filename, so [1] = FD + file_fd_ud *ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj"); + ret_cnt = file_g_read(L, LUAI_MAXINT32, EOF, ud->fd); + // Stack [1] = FD; [2] = contents if ret_cnt = 1; + file_close(L); // leaves Stack unchanged if [1] = FD + lua_remove(L, 1); // Dump FD leaving contents as [1] / ToS + } + return ret_cnt; +} + // Lua: write("string") static int file_write( lua_State* L ) { @@ -534,28 +537,6 @@ static int file_fsinfo( lua_State* L ) return 3; } -// Lua: getfile(filename) -static int file_getfile( lua_State* L ) -{ - // Warning this code C calls other file_* routines to avoid duplication code. These - // use Lua stack addressing of arguments, so this does Lua stack maniplation to - // align these - int ret_cnt = 0; - lua_settop(L ,1); - // Stack [1] = FD - file_open(L); - // Stack [1] = filename; [2] = FD or nil - if (!lua_isnil(L, -1)) { - lua_remove(L, 1); // dump filename, so [1] = FD - file_fd_ud *ud = (file_fd_ud *)luaL_checkudata(L, 1, "file.obj"); - ret_cnt = file_g_read(L, LUAI_MAXINT32, EOF, ud->fd); - // Stack [1] = FD; [2] = contents if ret_cnt = 1; - file_close(L); // leaves Stack unchanged if [1] = FD - lua_remove(L, 1); // Dump FD leaving contents as [1] / ToS - } - return ret_cnt; -} - // Lua: getfile(filename) static int file_putfile( lua_State* L ) { @@ -622,8 +603,6 @@ LROT_BEGIN(file, NULL, 0) LROT_FUNCENTRY( writeline, file_writeline ) LROT_FUNCENTRY( read, file_read ) LROT_FUNCENTRY( readline, file_readline ) - LROT_FUNCENTRY( getcontents, file_getfile ) - LROT_FUNCENTRY( putcontents, file_putfile ) #ifdef CONFIG_NODEMCU_BUILD_SPIFFS LROT_FUNCENTRY( format, file_format ) LROT_FUNCENTRY( fscfg, file_fscfg ) @@ -633,6 +612,8 @@ LROT_BEGIN(file, NULL, 0) LROT_FUNCENTRY( flush, file_flush ) LROT_FUNCENTRY( rename, file_rename ) LROT_FUNCENTRY( exists, file_exists ) + LROT_FUNCENTRY( getcontents, file_getfile ) + LROT_FUNCENTRY( putcontents, file_putfile ) LROT_FUNCENTRY( fsinfo, file_fsinfo ) LROT_FUNCENTRY( on, file_on ) LROT_FUNCENTRY( stat, file_stat ) diff --git a/docs/modules/ble.md b/docs/modules/ble.md index 088df082..149fe88d 100644 --- a/docs/modules/ble.md +++ b/docs/modules/ble.md @@ -74,10 +74,12 @@ The characteristic table contains the following keys: - `uuid` The UUID of the characteristics. This can be either a 16 byte string or a 2 byte string that identifies the particular characteristic. Typically, 2 byte strings are used for well-known characteristics. - `type` This is the optional type of the value. It has the same value as a unpack code in the `struct` module. - `value` This is the actual value of the characteristic. This will be a string of bytes unless a `type` value is set. -- `read` This is a function that will be invoked to read the value (and so does not need the `value` entry). It should return a string of bytes (unless `type` is set) +- `read` This is a function that will be invoked to read the value (and so does not need the `value` entry). It should return a string of bytes (unless `type` is set). - `write` This is a function that will be invoked to write the value (and so does not need the `value` entry). It is given a string of bytes (unless `type` is set) -The characteristics are treated as read/write unless only one of the `read` or `write` keys is present and the `value` key is not specificed. +If the `value` key is present, then the characteristic is read/write. However, if one or `read` or `write` is set to `true`, then it restricts access to that mode. + +The characteristics are treated as read/write unless only one of the `read` or `write` keys is present and the `value` key is not specified. The calling conventions for these functions are as follows: