Commit e52e0a8e authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Pulled in the 5.1+5.3 docs from the esp8266 branch.

With minor modifications to drop ESP8266 specific information not
applicable to the ESP32 series. Further corrections welcome.
parent 17df207a
This diff is collapsed.
This diff is collapsed.
......@@ -166,6 +166,18 @@ none
#### Returns
flash ID (number)
## node.flashindex() --deprecated
Deprecated synonym for [`node.LFS.get()`](#nodelfsget) to return an LFS function reference.
Note that this returns `nil` if the function does not exist in LFS.
## node.flashreload() --deprecated
Deprecated synonym for [`node.LFS.reload()`](#nodelfsreload) to reload [LFS (Lua Flash Store)](../lfs.md) with the named flash image provided.
## node.heap()
Returns the current available heap size in bytes. Note that due to fragmentation, actual allocations of this size may not be possible.
......@@ -230,6 +242,65 @@ sk:on("receive", function(conn, payload) node.input(payload) end)
#### See also
[`node.output()`](#nodeoutput)
## node.LFS
Sub-table containing the API for [Lua Flash Store](../lfs.md)(**LFS**) access. Programmers might prefer to map this to a global or local variable for convenience for example:
```lua
local LFS = node.LFS
```
This table contains the following methods and properties:
Property/Method | Description
-------|---------
`config` | A synonym for [`node.info('lfs')`](#nodeinfo). Returns the properties `lfs_base`, `lfs_mapped`, `lfs_size`, `lfs_used`.
`get()` | See [node.LFS.get()](#nodelfsget).
`list()` | See [node.LFS.list()](#nodelfslist).
`reload()` |See [node.LFS.reload()](#nodelfsreload).
`time` | Returns the Unix timestamp at time of image creation.
## node.LFS.get()
Returns the function reference for a function in LFS.
Note that unused `node.LFS` properties map onto the equialent `get()` call so for example: `node.LFS.mySub1` is a synonym for `node.LFS.get('mySub1')`.
#### Syntax
`node.LFS.get(modulename)`
#### Parameters
`modulename` The name of the module to be loaded.
#### Returns
- If the LFS is loaded and the `modulename` is a string that is the name of a valid module in the LFS, then the function is returned in the same way the `load()` and the other Lua load functions do
- Otherwise `nil` is returned.
## node.LFS.list()
List the modules in LFS.
#### Returns
- If no LFS image IS LOADED then `nil` is returned.
- Otherwise an sorted array of the name of modules in LFS is returned.
## node.LFS.reload()
Reload LFS with the flash image provided. Flash images can be generated on the host machine using the `luac.cross`command.
#### Syntax
`node.LFS.reload(imageName)`
#### Parameters
`imageName` The name of a image file in the filesystem to be loaded into the LFS.
#### Returns
- In the case when the `imagename` is a valid LFS image, this is expanded and loaded into flash, and the ESP is then immediately rebooted, _so control is not returned to the calling Lua application_ in the case of a successful reload.
- 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.
......
# pipe Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-07-18 | [Terry Ellison](https://github.com/TerryE) | [Terry Ellison](https://github.com/TerryE) | [pipe.c](../../app/modules/pipe.c)|
The pipe module provides a RAM-efficient means of passing character stream of records from one Lua
task to another.
## pipe.create()
Create a pipe.
#### Syntax
`pobj = pipe.create([CB_function],[task_priority])`
#### Parameters
- `CB_function` optional reader callback which is called through the `node.task.post()` when the pipe is written to. If the CB returns a boolean, then the reposting action is forced: it is reposted if true and not if false. If the return is nil or omitted then the deault is to repost if a pipe write has occured since the last call.
- `task_priority` See `ǹode.task.post()`
#### Returns
A pipe resource.
## pobj:read()
Read a record from a pipe object.
Note that the recommended method of reading from a pipe is to use a reader function as described below.
#### Syntax
`pobj:read([size/end_char])`
#### Parameters
- `size/end_char`
- If numeric then a string of `size` length will be returned from the pipe.
- If a string then this is a single character delimiter, followed by an optional "+" flag. The delimiter is used as an end-of-record to split the character stream into separate records. If the flag "+" is specified then the delimiter is also returned at the end of the record, otherwise it is discarded.
- If omitted, then this defaults to `"\n+"`
Note that if the last record in the pipe is missing a delimiter or is too short, then it is still returned, emptying the pipe.
#### Returns
A string or `nil` if the pipe is empty
#### Example
```lua
line = pobj:read('\n')
line = pobj:read(50)
```
## pobj:reader()
Returns a Lua **iterator** function for a pipe object. This is as described in the
[Lua Language: For Statement](http://www.lua.org/manual/5.1/manual.html#2.4.5). \(Note that the
`state` and `object` variables mentioned in 2.5.4 are optional and default to `nil`, so this
conforms to the`for` iterator syntax and works in a for because it maintains the state and `pobj`
internally as upvalues.
An emptied pipe takes up minimal RAM resources (an empty Lua array), and just like any other array
this is reclaimed if all variables referencing it go out of scope or are over-written. Note
that any reader iterators that you have created also refer to the pipe as an upval, so you will
need to discard these to descope the pipe array.
#### Syntax
`myFunc = pobj:reader([size/end_char])`
#### Parameters
- `size/end_char` as for `pobj:read()`
#### Returns
- `myFunc` iterator function
#### Examples
- used in `for` loop:
```lua
for rec in p:reader() do print(rec) end
-- or
fp = p:reader()
-- ...
for rec in fp do print(rec) end
```
- used in callback task:
```Lua
do
local pipe_reader = p:reader(1400)
local function flush(sk) -- Upvals flush, pipe_reader
local next = pipe_reader()
if next then
sk:send(next, flush)
else
sk:on('sent') -- dereference to allow GC
flush = nil
end
end
flush()
end
```
## pobj:unread()
Write a string to the head of a pipe object. This can be used to back-out a previous read.
#### Syntax
`pobj:unread(s)`
#### Parameters
`s` Any input string. Note that with all Lua strings, these may contain all character values including "\0".
#### Returns
Nothing
#### Example
```Lua
a=p:read()
p:unread(a) -- restores pipe to state before the read
```
## pobj:write()
Write a string to a pipe object.
#### Syntax
`pobj:write(s)`
#### Parameters
`s` Any input string. Note that with all Lua strings, these may contain all character values including "\0".
#### Returns
Nothing
## pobj:nrec()
Return the number of internal records in the pipe. Each record ranges from 1
to 256 bytes in length, with full chunks being the most common case. As
extracting from a pipe only to `unread` if too few bytes are available, it may
be useful to have a quickly estimated upper bound on the length of the string
that would be returned.
This diff is collapsed.
# Programming in NodeMCU
The standard Lua runtime offers support for both Lua modules that can define multiple Lua functions and properties in an encapsulating table as described in the [Lua 5.3 Reference Manual](https://www.lua.org/manual/5.3/) \("**LRM**") and specifically in [LRM Section 6.3](https://www.lua.org/manual/5.3/manual.html#6.3). Lua also provides a C API to allow developers to implement modules in compiled C.
NodeMCU developers are also able to develop and incorporate their own C modules into their own firmware build using this standard API, although we encourage developers to download the standard [Lua Reference Manual](https://www.lua.org/manual/) and also buy of copy of Roberto Ierusalimschy's Programming in Lua edition 4 \("**PiL**"). The NodeMCU implementation extends standard Lua as documented in the [NodeMCU Reference Manual](nodemcu-lrm.md) \("**NRM**").
Those developers who wish to develop or to modify existing C modules should have access to the LRM, PiL and NRM and familiarise themselves with these references. These are the primary references; and this document does not repeat this content, but rather provide some NodeMCU-specific information to supplement it.
From a perspective of developing C modules, there is very little difference from that of developing modules in standard Lua. All of the standard Lua library modules (`bit`, `coroutine`, `debug`, `math`, `string`, `table`, `utf8`) use the C API for Lua and the NodeMCU versions have been updated to use NRM extensions. so their source code is available for browsing and using as style template (see the corresponding `lXXXlib.c` file in GitHub [NodeMCU lua53](../app/lua53) folder).
The main functional change is that NodeMCU supports a read-only subclass of the `Table` type, known as a **`ROTable`**, which can be statically declared within the module source using static `const` declarations. There are also limitations on the valid types for ROTable keys and value in order to ensure that these are consistent with static declaration; and hence ROTables are stored in code space (and therefore in flash memory on the IoT device). Hence unlike standard Lua tables, ROTables do not take up RAM resources.
Also unlike standard Lua, two global ROTables are used for the registration of C modules. Again, static declaration macros plus linker "magic" (use of make filters plus linker _section_ directives) result in the marshalling of these ROTables during the make process, and because this is all ROTable based, the integration of modules into the firmware builds and their access from executing Lua applications depends on code space rather than RAM-based data structures.
Note that dynamic loading of C modules is not supported within the ESP SDK, so any library registration must be compiled into the source used in the firmware build. Our approach is simple, flexible and avoids the RAM overheads of the standard Lua approach. The special ROTable **`ROM`** is core to this approach. The global environment table has an `__index` metamethod referencing this ROM table. Hence, any non-raw lookups against the global table will also resolve against ROM. All base Lua functions (such as `print`) and any C libraries (written to NodeMCU standards) have an entry in the ROM table and hence have global visibility. This approach does not prevent developers use of standard Lua mechanisms, but rather it offers a simple low RAM use alternative.
The `NODEMCU_MODULE` macro is used in each module to register it in an entry in the **`ROM`** ROTable. It also adds a entry in the second (hidden) **`ROMentry`** ROTable.
- All `ROM` entries will resolve globally
- The Lua runtime scans the `ROMentry` ROTable during its start up, and it will execute any non-NULL `CFunction` values in this table. This enables C modules to hook in any one-time start-up functions if they are needed.
Note that the standard `make` will include any modules found in the `app/modules` folder within a firmware build _if_ the corresponding `LUA_USE_MODULES_modname` macro has been defined. These defines are conventionally set in a common include file `user_modules.h`, and this practice is mandated for any user-submitted modules that are added to to the NodeMCU distribution. However, this does not prevent developers adding their own local modules to the `app/modules` folder and simply defining the corresponding `LUA_USE_MODULES_modname` inline.
This macro + linker approach renders the need for `luaL_reg` declarations and use of `luaL_openlib()` unnecessary, and these are not permitted in project-adopted `app/modules` files.
Hence a NodeMCU C library module typically has a standard layout that parallels that of the standard Lua library modules and uses the same C API to access the Lua runtime:
- A `#ìnclude` block to resolve access to external resources. All modules will include entries for `"module.h"`, and `"lauxlib.h"`. They should _not_ reference any other `lXXX.h` includes from the Lua source directory as these are private to the Lua runtime. These may be followed by C standard runtime includes, external application libraries and any SDK resource headers needed.
- The only external interface to a C module should be via the Lua runtime and its `NODEMCU_MODULE` hooks. Therefore all functions and resources should be declared `static` and be private to the module. These can be ordered as the developer wishes, subject of course to the need for appropriate forward declarations to comply with C scoping rules.
- Module methods will typically employ a Lua standard `static int somefunc (lua_State *L) { ... }` template.
- ROTables are typically declared at the end of the module to minimise the need for forward references and use the `LROT` macros described in the NRM. Note that ROTables only support static declaration of string keys and the value types: C function, Lightweight userdata, Numeric, ROTable. ROTables can also have ROTable metatables.
- Whilst the ROTable search algorithm is a simply linear scan of the ROTable entries, the runtime also maintains a LRU cache of ROTable accesses, so typically over 95% of ROTable accesses bypass the linear scan and do a direct access to the appropriate entry.
- ROTables are also reasonable lightweight and well integrated into the Lua runtime, so the normal metamethod processing works well. This means that developers can use the `__index` method to implement other key and value typed entries through an index function.
- NodeMCU modules are intended to be compilable against both our Lua 5.1 and Lua 5.3 runtimes. The NRM discusses the implications and constraints here. However note that:
- We have back-ported many new Lua 5.3 features into the NodeMCU Lua 5.1 API, so in general you can use the 5.3 API to code your modules. Again the NRM notes the exceptions where you will either need variant code or to decide to limit yourself to the the 5.3 runtime. In this last case the simplest approach is to `#if LUA_VERSION_NUM != 503` to disable the 5.3 content so that 5.1 build can compile and link. Note that all modules currently in the `app/modules` folder will compile against and execute within both the Lua 5.1 and the 5.3 environments.
- Lua 5.3 uses a 32-bit representation for all numerics with separate subtypes for integer (stored as a 32 bit signed integer) and float (stored as 32bit single precision float). This achieves the same RAM storage density as Lua 5.1 integer builds without the loss of use of floating point when convenient. We have therefore decided that there is no benefit in having a separate Integer 5.3 build variant.
- We recommend that developers make use of the full set of `luaL_` API calls to minimise code verbosity. We have also added a couple of registry access optimisations that both simply and improve runtime performance when using the Lua registry for callback support.
- `luaL_reref()` replaces an existing registry reference in place (or creates a new one if needed). Less code and faster execution than a `luaL_unref()` plus `luaL_ref()` construct.
- `luaL_unref2()` does the unref and set the static int hook to `LUA_NOREF`.
Rather than include simple examples of module templates, we suggest that you review the modules in our GitHub repository, such as the [`utf8`](../app/lua53/lutf8lib.c) library. Note that whilst all of the existing modules in `app/modules` folder compile and work, we plan to do a clean up of the core modules to ensure that they conform to best practice.
......@@ -27,10 +27,15 @@ pages:
- Uploading code: 'upload.md'
- JTAG debugging: 'debug.md'
- Support: 'support.md'
- Reference:
- NodeMCU Language Reference Manual: 'nodemcu-lrm.md'
- Programming in NodeMCU: 'nodemcu-pil.md'
- FAQs:
- Lua Developer FAQ: 'lua-developer-faq.md'
- Extension Developer FAQ: 'extn-developer-faq.md'
- Whitepapers:
- Lua 5.3 Support: 'lua53.md'
- Lua Flash Store (LFS): 'lfs.md'
- Filesystem on SD card: 'sdcard.md'
- Writing external C modules: 'modules/extmods.md'
- C Modules:
......@@ -54,6 +59,7 @@ pages:
- 'node': 'modules/node.md'
- 'ota': 'modules/otaupgrade.md'
- 'ow (1-Wire)': 'modules/ow.md'
- 'pipe': 'modules/pipe.md'
- 'pulsecnt': 'modules/pulsecnt.md'
- 'qrcodegen': 'modules/qrcodegen.md'
- 'sdmmc': 'modules/sdmmc.md'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment