Unverified Commit 310faf7f authored by Terry Ellison's avatar Terry Ellison Committed by GitHub
Browse files

Merge pull request #2886 from nodemcu/dev

Next master drop
parents 68c425c0 a08e74d9
...@@ -236,6 +236,10 @@ Provides DNS resolution for a hostname. ...@@ -236,6 +236,10 @@ Provides DNS resolution for a hostname.
- `domain` domain name - `domain` domain name
- `function(net.socket, ip)` callback function. The first parameter is the socket, the second parameter is the IP address as a string. - `function(net.socket, ip)` callback function. The first parameter is the socket, the second parameter is the IP address as a string.
If a callback `c` is provided, it is equivalent to having called `:on("dns",
c)` on this socket; this callback will, hereafter, receive any pending
resolution results recieved for this socket!
#### Returns #### Returns
`nil` `nil`
...@@ -580,6 +584,11 @@ Resolve a hostname to an IP address. Doesn't require a socket like [`net.socket. ...@@ -580,6 +584,11 @@ Resolve a hostname to an IP address. Doesn't require a socket like [`net.socket.
- `host` hostname to resolve - `host` hostname to resolve
- `function(sk, ip)` callback called when the name was resolved. `sk` is always `nil` - `function(sk, ip)` callback called when the name was resolved. `sk` is always `nil`
There is at most one callback for all `net.dns.resolve()` requests at any time;
all resolution results are sent to the most recent callback specified at time
of receipt! If multiple DNS callbacks are needed, associate them with separate
sockets using [`net.socket:dns()`](#netsocketdns).
#### Returns #### Returns
`nil` `nil`
......
...@@ -183,7 +183,7 @@ Returns the function reference for a function in the [LFS (Lua Flash Store)](../ ...@@ -183,7 +183,7 @@ Returns the function reference for a function in the [LFS (Lua Flash Store)](../
`modulename` The name of the module to be loaded. If this is `nil` or invalid then an info list is returned `modulename` The name of the module to be loaded. If this is `nil` or invalid then an info list is returned
#### Returns #### Returns
- In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash and mapped base addresss of the LFS - In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash mapped base addresss of the LFS, its flash offset, and the size of the LFS.
- If the LFS is loaded and the function is called with 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. - If the LFS is loaded and the function is called with 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 an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS. - Otherwise an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS.
...@@ -239,6 +239,28 @@ do ...@@ -239,6 +239,28 @@ do
end end
``` ```
## node.getpartitiontable()
Get the current LFS and SPIFFS partition information.
#### Syntax
`node.getpartitiontable()`
#### Parameters
none
#### Returns
An array containing entries for `lfs_addr`, `lfs_size`, `spiffs_addr` and `spiffs_size`. The address values are offsets relative to the start of the Flash memory.
#### Example
```lua
print("The LFS size is " .. node.getpartitiontable().lfs_size)
```
#### See also
[`node.setpartitiontable()`](#nodesetpartitiontable)
## node.heap() ## node.heap()
Returns the current available heap size in bytes. Note that due to fragmentation, actual allocations of this size may not be possible. Returns the current available heap size in bytes. Note that due to fragmentation, actual allocations of this size may not be possible.
...@@ -254,23 +276,51 @@ system heap size left in bytes (number) ...@@ -254,23 +276,51 @@ system heap size left in bytes (number)
## node.info() ## node.info()
Returns NodeMCU version, chipid, flashid, flash size, flash mode, flash speed, and Lua File Store (LFS) usage statics. Returns information about hardware, software version and build configuration.
#### Syntax #### Syntax
`node.info()` `node.info([group])`
#### Parameters #### Parameters
none `group` A designator for a group of properties. May be one of `"hw"`, `"sw_version"`, `"build_config"`. It is currently optional; if omitted the legacy structure is returned. However, not providing any value is deprecated.
#### Returns #### Returns
- `majorVer` (number) If a `group` is given the return value will be a table containing the following elements:
- `minorVer` (number)
- `devVer` (number) - for `group` = `"hw"`
- `chipid` (number) - `chip_id` (number)
- `flashid` (number) - `flash_id` (number)
- `flashsize` (number) - `flash_size` (number)
- `flashmode` (number) - `flash_mode` (number) 0 = QIO, 1 = QOUT, 2 = DIO, 15 = DOUT.
- `flashspeed` (number) - `flash_speed` (number)
- for `group` = `"sw_version"`
- `git_branch` (string)
- `git_commit_id` (string)
- `git_release` (string) release name +additional commits e.g. "2.0.0-master_20170202 +403"
- `git_commit_dts` (string) commit timestamp in an ordering format. e.g. "201908111200"
- `node_verion_major` (number)
- `node_verion_minor` (number)
- `node_verion_revision` (number)
- for `group` = `"build_config"`
- `ssl` (boolean)
- `lfs_size` (number) as defined at build time
- `modules` (string) comma separated list
- `number_type` (string) `integer` or `float`
!!! attention
Not providing a `group` is deprecated and support for that will be removed in one of the next releases.
- for `group` = `nil`
- `majorVer` (number)
- `minorVer` (number)
- `devVer` (number)
- `chipid` (number)
- `flashid` (number)
- `flashsize` (number)
- `flashmode` (number)
- `flashspeed` (number)
#### Example #### Example
```lua ```lua
...@@ -278,6 +328,17 @@ majorVer, minorVer, devVer, chipid, flashid, flashsize, flashmode, flashspeed = ...@@ -278,6 +328,17 @@ majorVer, minorVer, devVer, chipid, flashid, flashsize, flashmode, flashspeed =
print("NodeMCU "..majorVer.."."..minorVer.."."..devVer) print("NodeMCU "..majorVer.."."..minorVer.."."..devVer)
``` ```
```lua
for k,v in pairs(node.info("build_config")) do
print (k,v)
end
```
```lua
print(node.info("sw_version").git_release)
```
## node.input() ## node.input()
Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation. Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation.
...@@ -407,6 +468,35 @@ target CPU frequency (number) ...@@ -407,6 +468,35 @@ target CPU frequency (number)
node.setcpufreq(node.CPU80MHZ) node.setcpufreq(node.CPU80MHZ)
``` ```
## node.setpartitiontable()
Sets the current LFS and / or SPIFFS partition information.
#### Syntax
`node.setpartitiontable(partition_info)`
!!! note
This function is typically only used once during initial provisioning after first flashing the firmware. It does some consistency checks to validate the specified parameters, and it then reboots the ESP module to load the new partition table. If the LFS or SPIFFS regions have changed then you will need to reload LFS, reformat the SPIFSS and reload its contents.
#### Parameters
An array containing one or more of the following enties. The address values are byte offsets relative to the start of the Flash memory. The size values are in bytes. Note that these parameters must be a multiple of 8Kb to align to Flash page boundaries.
- `lfs_addr`. The base address of the LFS region.
- `lfs_size`. The size of the LFS region.
- `spiffs_addr`. The base address of the SPIFFS region.
- `spiffs_size`. The size of the SPIFFS region.
#### Returns
Not applicable. The ESP module will be rebooted for a valid new set, or a Lua error will be thown if inconsistencies are detected.
#### Example
```lua
node.setpartitiontable{lfs_size = 0x20000, spiffs_addr = 0x120000, spiffs_size = 0x20000}
```
#### See also
[`node.getpartitiontable()`](#nodegetpartitiontable)
## node.sleep() ## node.sleep()
......
# 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 RAM-efficient a means of passing character stream of records from one Lua
task to another.
## pipe.create()
Create a pipe.
#### Syntax
`pobj = pipe.create()`
#### Parameters
None
#### 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 user 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 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 descard these to desope 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 a head of pipe object. This can be used to back-out a previous read.
#### 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
#### Example
```Lua
a=p:read()
p:unread() -- 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
# PWM2 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-02-12 | [fikin](https://github.com/fikin) | [fikin](https://github.com/fikin) | [pwm2.c](../../../app/modules/pwm2.c)|
Module to generate PWM impulses to any of the GPIO pins.
PWM is being generated by software using soft-interrupt TIMER1 FRC1. This module is using the timer in exclusive mode. See [understanding timer use](#understanding-timer-use) for more.
Supported frequencies are roughly from 120kHZ (with 50% duty) up to pulse/53sec (or 250kHz and 26 sec for CPU160). See [understanding frequencies](#understand-frequencies) for more.
Supported are also frequency fractions even for integer-only firmware builds.
Supported are all of the GPIO pins except pin 0.
One can generate different PWM signals to any of them at the same time. See [working with multiple frequencies](#working-with-multiple-frequencies) for more.
This module supports CPU80MHz as well as CPU160MHz. Frequency boundaries are same but by using CPU160MHz one can hope of doing more work meantime.
Typical usage is as following:
```lua
pwm2.setup_pin_hz(3,250000,2,1) -- pin 3, PWM freq of 250kHz, pulse period of 2 steps, initial duty 1 period step
pwm2.setup_pin_hz(4,1,2,1) -- pin 4, PWM freq of 1Hz, pulse period of 2 steps, initial duty 1 period step
pwm2.start() -- starts pwm, internal led will blink with 0.5sec interval
...
pwm2.set_duty(4, 2) -- led full off (pin is high)
...
pwm2.set_duty(4, 0) -- led full on (pin is low)
...
pwm2.stop() -- PWM stopped, gpio pin released, timer1 released
```
## Understand frequencies
All frequencines and periods internally are expressed as CPU ticks using following formula: `cpuTicksPerSecond / (frequencyHz * period)`. For example, 1kHz with 1000 period for CPU80MHz results in 80 CPU ticks per period i.e. period is 1uS long.
In order to allow for better tunning, I've added an optional frequencyDivisor argument when setting pins up. With it one can express the frequency as division between two values : `frequency / divisor`. For example to model 100,1Hz frequency one has to specify frequency of 1001 and divisor 10.
An easy way to express sub-Hz frequencies, i.e. the ones taking seconds to complete one impulse, is to use setup in seconds methods. For them formula to compute CPU ticks is `cpuTicksPerSecond * frequencySec / period`. Max pulse duration is limited by roll-over of the ESP's internal CPU 32bits ticks counter. For CPU80 that would be every 53 seconds, for CPU160 that would be half.
## Frequency precision and limits
ESP's TIMER1 FRC1 is operating at fixed, own frequency of 5MHz. Therefore the precision of individual interrupt is 200ns. But that limit cannot be attained.
OS timer interrupt handler code itself has internal overhead. For auto-loaded interrupts it is about 50CPUTicks. For short periods of time one can interrupt at approximately 1MHz but then watchdog will intervene.
PWM2 own interrupt handler has an overhead of 162CPUTicks + 12CPUTicks per each used pin.
With the fastest setup i.e. 1 pin, 50% duty cycle (pulse period of 2) and CPU80 one could expect to achive PWM frequency of 125kHz.
For 12 pins that would drop to about 100kHz. With CPU160 one could reach 220kHz with 1 pin.
Frequencies internally are expressed as CPU ticks first then to TIMER1 ticks. Because TIMER1 frequency is 1/16 of CPU frequency, some frequency precision is lost when converting from CPU to TIMER ticks. One can inspect exact values used via [pwm2.get_timer_data()](#pwm2get_timer_data). Value of `interruptTimerCPUTicks` represents desired interrupt period in CPUTicks. And `interruptTimerTicks` represents actually used interrupt period as TIMER1 ticks (1/16 of CPU).
## Working with multiple frequencies
When working with multiple pins, this module auto-discovers what would be the right underlying interrupt frequency. It does so by computing the greatest common frequency divisor and use it as common frequency for all pins.
When using same frequency for many pins, tunning frequency of single pin is enough to ensure precision.
When using different frequencies, one has to pay close attention at their greates common divisor when expressed as CPU ticks. For example, mixing 100kHz with period 2 and 0.5Hz with period 2 results in underlying interrupt period of 800CPU ticks. But changing to 100kHz+1 will easily result to divisor of 1. This is clearly non-working combination.
Another example is frequency of 120kHz with period 2, which results in period of 333CPU ticks. If combined with even-resulting frequency like 1Hz with period of 2, this will lead to common divisor of 1, which is clearly a non-working setup either.
For the moment best would be to use [pwm2.get_timer_data()](#pwm2get_timer_data) and observe how `interruptTimerCPUTicks` and `interruptTimerTicks` change with given input.
## Understanding timer use
This module is using soft-interrupt TIMER1 FRC1 to generate PWM signal. Since its interrupts can be masked, as some part of OS are doing it, it is possible to have some impact on the quality of generated PWM signal. As a general principle, one should not expect high precision signal with this module.
Also note that interrupt masking is dependent on other activities happening within the ESP besides pwm2 module.
Additionally this timer is used by other modules like pwm, pcm, ws2812 and etc. Since an exclusive lock is maintained on the timer, simultaneous use of such modules would not be possible.
## Troubleshooting watchdog timeouts
Watchdog interrupt typically will occur if choosen frequency (and period) is too big i.e. too small timer ticks value. For CPU80MHz I guess threshold is around 125kHz with period of 2 and single pin (CPU80), given not much other load on the system. For CPU160 threshold is 225kHz.
Another reason for watchdog interrupt to occur is due to mixing otherwise not very compatible frequencies when multiple pins are used. See [working with multiple frequencies](#working-with-multiple-frequencies) for more.
Both cases are best anlyzed using [pwm2.get_timer_data()](#pwm2get_timer_data) watching values of `interruptTimerCPUTicks` and `interruptTimerTicks`. For `interruptTimerCPUTicks` with CPU80 anything below (330/630) for (1/12) pins would be cause for special attention.
## Differences with PWM module
PWM and PWM2 are modules doing similar job and have much in common.
Here are few PWM2 highlights compared to PWM module:
- PWM2 is using TIMER1 exclusively, which allows for possibly a better quality PWM signal
- PWM2 can generate PWM frequencies in the range of 1pulse/53 seconds up to 125kHz (26sec/225kHz for CPU160)
- PWM2 can generate PWM frequencies with fractions i.e. 1001kHz
- PWM2 supports CPU160
- PWM2 supports virtually all GPIO ports at the same time
Unlike PWM2, PWM can:
- generate PWM pulse with a little bit bigger duty cycle i.e. 1kHz at 1000 pulse period
- can be used at the same time with some other modules like gpio.pulse
## pwm2.setup_pin_hz()
Assigns PWM frequency expressed as Hz to given pin.
This method is suitable for setting up frequencies in the range of >= 1Hz.
### Syntax
`pwm2.setup_pin_hz(pin,frequencyAsHz,pulsePeriod,initialDuty [,frequencyDivisor])`
### Parameters
- `pin` 1-12
- `frequencyAsHz` desired frequency in Hz, for example 1000 for 1KHz
- `pulsePeriod` discreet steps in single PWM pulse, for example 100
- `initialDuty` initial duty in pulse period steps i.e. 50 for 50% pulse of 100 resolution
- `frequencyDivisor` an integer to divide product of frequency and pulsePeriod. Used to form frequency fractions. By default not required.
### Returns
`nil`
### See also
- [pwm2.setup_pin_sec()](#pwm2setup_pin_sec)
- [pwm2.start()](#pwm2start)
- [pwm2.release_pin()](#pwm2release_pin)
- [understanding frequencies](#understand-frequencies)
- [working with multiple frequencies](#working-with-multiple-frequencies)
- [pwm2.get_timer_data()](#pwm2get_timer_data)
## pwm2.setup_pin_sec()
Assigns PWM frequency expressed as one impulse per second(s) to given pin.
This method is suitable for setting up frequencies in the range of 0 < 1Hz but expressed as seconds instead.
For example 0.5Hz are expressed as 2 seconds impulse.
### Syntax
`pwm2.setup_pin_sec(pin,frequencyAsSec,pulsePeriod,initialDuty [,frequencyDivisor])`
### Parameters
- `pin` 1-12
- `frequencyAsSec` desired frequency as one impulse for given seconds, for example 2 means PWM with impulse long 2 seconds.
- `pulsePeriod` discreet steps in single PWM pulse, for example 100
- `initialDuty` initial duty in pulse period steps i.e. 50 for 50% pulse of 100 resolution
- `frequencyDivisor` an integer to divide product of frequency and pulsePeriod. Used to form frequency fractions. By default not required.
### Returns
`nil`
### See also
- [pwm2.setup_pin_hz()](#pwm2setup_pin_hz)
- [pwm2.start()](#pwm2start)
- [pwm2.release_pin()](#pwm2release_pin)
- [understanding frequencies](#understand-frequencies)
- [working with multiple frequencies](#working-with-multiple-frequencies)
- [pwm2.get_timer_data()](#pwm2get_timer_data)
## pwm2.start()
Starts PWM for all setup pins.
At this moment GPIO pins are marked as output and TIMER1 is being reserved for this module.
If the TIMER1 is already reserved by another module this method reports a Lua error and returns false.
### Syntax
`pwm2.start()`
### Parameters
`nil`
### Returns
- `bool` true if PWM started ok, false of TIMER1 is reserved by another module.
### See also
- [pwm2.setup_pin_hz()](#pwm2setup_pin_hz)
- [pwm2.setup_pin_sec()](#pwm2setup_pin_sec)
- [pwm2.set_duty()](#pwm2set_duty)
- [pwm2.stop()](#pwm2stop)
## pwm2.stop()
Stops PWM for all pins. All GPIO pins and TIMER1 are being released.
One can resume PWM with previous pin settings by calling [pwm2.start()](#pwm2start) right after stop.
### Syntax
`pwm2.stop()`
### Parameters
`nil`
### Returns
`nil`
### See also
- [pwm2.start()](#pwm2start)
- [pwm2.release_pin()](#pwm2release_pin)
## pwm2.set_duty()
Sets duty cycle for one or more a pins. This method takes immediate effect to ongoing PWM generation.
### Syntax
`pwm2.set_duty(pin, duty [,pin,duty]*)`
### Parameters
- `pin` 1~12, IO index
- `duty` 0~period, pwm duty cycle
### Returns
`nil`
### See also
- [pwm2.stop()](#pwm2stop)
## pwm2.release_pin()
Releases given pin from previously done setup. This method is applicable when PWM is stopped and given pin is not needed anymore.
Releasing pins is not strictly needed. This method is useful for start-stop-start situations when pins do change.
### Syntax
`pwm2.release_pin(pin)`
### Parameters
- `pin` 1~12, IO index
### Returns
`nil`
### See also
- [pwm2.setup_pin_hz()](#pwm2setup_pin_hz)
- [pwm2.setup_pin_sec()](#pwm2setup_pin_sec)
- [pwm2.stop()](#pwm2stop)
## pwm2.get_timer_data()
Prints internal data structures related to the timer. This method is usefull for people troubleshooting frequency side effects.
### Syntax
`pwm2.get_timer_data()`
### Parameters
`nil`
### Returns
- `isStarted` bool, if true PWM2 has been started
- `interruptTimerCPUTicks` int, desired timer interrupt period in CPU ticks
- `interruptTimerTicks` int, actual timer interrupt period in timer ticks
### Example
```
isStarted, interruptTimerCPUTicks, interruptTimerTicks = pwm2.get_timer_data()
```
### See also
- [pwm2.setup_pin_hz()](#pwm2setup_pin_hz)
- [pwm2.setup_pin_sec()](#pwm2setup_pin_sec)
- [pwm2.get_pin_data()](#pwm2get_pin_data)
## pwm2.get_pin_data()
Prints internal data structures related to given GPIO pin. This method is usefull for people troubleshooting frequency side effects.
### Syntax
`pwm2.get_pin_data(pin)`
### Parameters
- `pin` 1~12, IO index
### Returns
- `isPinSetup` bool, if 1 pin is setup
- `duty` int, assigned duty
- `pulseResolutions` int, assigned pulse periods
- `divisableFrequency` int, assigned frequency
- `frequencyDivisor` int, assigned frequency divisor
- `resolutionCPUTicks` int, calculated one pulse period in CPU ticks
- `resolutionInterruptCounterMultiplier` int, how many timer interrupts constitute one pulse period
### Example
```
isPinSetup, duty, pulseResolutions, divisableFrequency, frequencyDivisor, resolutionCPUTicks, resolutionInterruptCounterMultiplier = pwm2..get_pin_data(4)
```
### See also
- [pwm2.setup_pin_hz()](#pwm2setup_pin_hz)
- [pwm2.setup_pin_sec()](#pwm2setup_pin_sec)
- [pwm2.get_timer_data()](#pwm2get_timer_data)
...@@ -20,20 +20,29 @@ most common features supported. Specifically, it provides: ...@@ -20,20 +20,29 @@ most common features supported. Specifically, it provides:
- key exchange algorithms: DHE and ECDHE - key exchange algorithms: DHE and ECDHE
- elliptic curves: secp{256,384}r1, secp256k1, bp{256,384}. - elliptic curves: secp{256,384}r1, secp256k1, bp{256,384}.
!!! tip !!! warning
If possible, you will likely be much better served by using the ECDSA
signature and key exchange algorithms than by using RSA. An
increasingly large fraction of the Internet understands ECDSA, and most
server software can speak it as well. The much smaller key size (at
equivalent security!) is beneficial for NodeMCU's limited RAM.
https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
details how to create ECDSA keys and certificates.
!!! tip The severe memory constraints of the ESP8266 mean that the `tls` module
The complete configuration is stored in [user_mbedtls.h](../../app/include/user_mbedtls.h). This is the file to edit if you build your own firmware and want to change mbed TLS behavior. is by far better suited for communication with custom, purpose-built
endpoints with small certificate chains (ideally, even self-signed)
than it is with the Internet at large. By default, our mbedTLS
configuration requests TLS fragments of at most 4KiB and is unwilling
to process fragmented messages, meaning that the entire ServerHello,
which includes the server's certificate chain, must conform to this
limit. We do not believe it useful or easy to be fully compliant with
the TLS specification, which requires a 16KiB recieve buffer and,
therefore, 32KiB of heap within mbedTLS, even in the steady-state.
While it is possible to slightly raise the buffer sizes with custom
nodeMCU builds, connecting to endpoints out of your control will remain
a precarious position, and so we strongly suggest that TLS connections
be made only to endpoints under your control, whose TLS configurations
can ensure that their ServerHello messages are small. A reasonable
compromise is to have a "real" computer do TLS proxying for you; the
[socat](http://www.dest-unreach.org/socat/) program is one possible
mechanism of achieving such a "bent pipe" with TLS on both halves.
!!! warning !!! warning
The TLS glue provided by Espressif provides no interface to TLS SNI. The TLS glue provided by Espressif provides no interface to TLS SNI.
As such, NodeMCU TLS should not be expected to function with endpoints As such, NodeMCU TLS should not be expected to function with endpoints
requiring the use of SNI, which is a growing fraction of the Internet requiring the use of SNI, which is a growing fraction of the Internet
...@@ -43,15 +52,38 @@ most common features supported. Specifically, it provides: ...@@ -43,15 +52,38 @@ most common features supported. Specifically, it provides:
pair. pair.
!!! warning !!! warning
The TLS handshake is very heap intensive, requiring between 25 and 30 The TLS handshake is very heap intensive, requiring between 25 and 30
**kilobytes** of heap. Some, but not all, of that is made available **kilobytes** of heap, even with our reduced buffer sizes. Some, but
again once the handshake has completed and the connection is open. not all, of that is made available again once the handshake has
Because of this, we have disabled mbedTLS's support for connection completed and the connection is open. Because of this, we have
renegotiation. You may find it necessary to restructure your disabled mbedTLS's support for connection renegotiation. You may find
application so that connections happen early in boot when heap is it necessary to restructure your application so that connections happen
relatively plentiful, with connection failures inducing reboots. early in boot when heap is relatively plentiful, with connection
failures inducing reboots. LFS may also be of utility in freeing up
For a list of features have a look at the [mbed TLS features page](https://tls.mbed.org/core-features). heap space, should you wish to attempt re-establishing connections
without rebooting.
!!! tip
If possible, you will likely be much better served by using the ECDSA
signature and key exchange algorithms than by using RSA. An
increasingly large fraction of the Internet understands ECDSA, and most
server software can speak it as well. The much smaller key size (at
equivalent security!) is beneficial for NodeMCU's limited RAM.
https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations
details how to create ECDSA keys and certificates.
!!! tip
The complete configuration is stored in
[user_mbedtls.h](../../app/include/user_mbedtls.h). This is the file to
edit if you build your own firmware and want to change mbed TLS
behavior.
For a list of possible features have a look at the
[mbed TLS features page](https://tls.mbed.org/core-features).
This module handles certificate verification when SSL/TLS is in use. This module handles certificate verification when SSL/TLS is in use.
......
...@@ -43,9 +43,11 @@ The NodeMCU firmware supports the following displays in I²C and SPI mode: ...@@ -43,9 +43,11 @@ The NodeMCU firmware supports the following displays in I²C and SPI mode:
- sh1106 128x64 - sh1106 128x64
- sh1107 - variants 64x128, seeed 96x96, 128x128 - sh1107 - variants 64x128, seeed 96x96, 128x128
- sh1108 160x160 - sh1108 160x160
- ssd0323 os128064
- ssd1305 128x32 - ssd1305 128x32
- ssd1306 - variants 128x32, 128x64, 64x48, and 96x16 - ssd1306 - variants 128x32, 128x64, 64x48, and 96x16
- ssd1309 128x64 - ssd1309 128x64
- ssd1318 128x96, 128x96_xcp
- ssd1325 128x63 - ssd1325 128x63
- ssd1326 er 256x32 - ssd1326 er 256x32
- ssd1327 - variants 96x96, ea w128128, and midas 128x128 - ssd1327 - variants 96x96, ea w128128, and midas 128x128
...@@ -73,15 +75,15 @@ SPI only: ...@@ -73,15 +75,15 @@ SPI only:
- ssd1322 nhd 256x64 and nhd 128x64 variants - ssd1322 nhd 256x64 and nhd 128x64 variants
- ssd1329 128x96 - ssd1329 128x96
- ssd1606 172x72 - ssd1606 172x72
- ssd1607 200x200 - ssd1607 200x200, gd_200x200, ws_200x200
- st7565 - variants 64128n, dogm128/132, erc12864, lm6059, c12832/c12864, and zolen 128x64 - st7565 - variants 64128n, dogm128/132, erc12864, erc12864_alt, lm6059, c12832/c12864, and zolen 128x64
- st7567 - variants 132x64, jlx12864, and enh_dg128064i - st7567 - variants 132x64, jlx12864, and enh_dg128064i
- st7586 - s028hn118a and erc240160 variants - st7586 - s028hn118a and erc240160 variants
- st75256 - jlx172104 and jlx256128 variants - st75256 - jlx172104 and jlx256128 variants
- t6963 - variants 240x128, 240x64, 256x64, 128x64, and 160x80 - t6963 - variants 240x128, 240x64, 256x64, 128x64, and 160x80
- uc1701 - dogs102 and mini12864 variants - uc1701 - dogs102 and mini12864 variants
This integration uses full "RAM" memory buffer without picture loop and calls u8g2's `begin()` internally when creating a display object. It is based on [v2.23.18](https://github.com/olikraus/U8g2_Arduino/releases/tag/2.23.18). This integration uses full "RAM" memory buffer without picture loop and calls u8g2's `begin()` internally when creating a display object. It is based on [v2.25.10](https://github.com/olikraus/U8g2_Arduino/releases/tag/2.25.10).
## Overview ## Overview
...@@ -165,6 +167,7 @@ Initialize a display via I²C. ...@@ -165,6 +167,7 @@ Initialize a display via I²C.
- `u8g2.sh1107_i2c_seeed_96x96()` - `u8g2.sh1107_i2c_seeed_96x96()`
- `u8g2.sh1107_i2c_128x128()` - `u8g2.sh1107_i2c_128x128()`
- `u8g2.sh1108_i2c_160x160()` - `u8g2.sh1108_i2c_160x160()`
- `u8g2.ssd0323_i2c_os128064()`
- `u8g2.ssd1305_i2c_128x32_noname()` - `u8g2.ssd1305_i2c_128x32_noname()`
- `u8g2.ssd1306_i2c_128x32_univision()` - `u8g2.ssd1306_i2c_128x32_univision()`
- `u8g2.ssd1306_i2c_128x64_noname()` - `u8g2.ssd1306_i2c_128x64_noname()`
...@@ -174,6 +177,8 @@ Initialize a display via I²C. ...@@ -174,6 +177,8 @@ Initialize a display via I²C.
- `u8g2.ssd1306_i2c_128x64_alt0()` - `u8g2.ssd1306_i2c_128x64_alt0()`
- `u8g2.ssd1306_i2c_64x48_er()` - `u8g2.ssd1306_i2c_64x48_er()`
- `u8g2.ssd1306_i2c_96x16_er()` - `u8g2.ssd1306_i2c_96x16_er()`
- `u8g2.ssd1318_i2c_128x96()`
- `u8g2.ssd1318_i2c_128x96_xcp()`
- `u8g2.ssd1325_i2c_nhd_128x64()` - `u8g2.ssd1325_i2c_nhd_128x64()`
- `u8g2.ssd1326_i2c_er_256x32()` - `u8g2.ssd1326_i2c_er_256x32()`
- `u8g2.ssd1327_i2c_seeed_96x96()` - `u8g2.ssd1327_i2c_seeed_96x96()`
...@@ -249,6 +254,7 @@ Initialize a display via Hardware SPI. ...@@ -249,6 +254,7 @@ Initialize a display via Hardware SPI.
- `u8g2.sh1107_128x128()` - `u8g2.sh1107_128x128()`
- `u8g2.sh1108_160x160()` - `u8g2.sh1108_160x160()`
- `u8g2.sh1122_256x64()` - `u8g2.sh1122_256x64()`
- `u8g2.ssd0323_os128064()`
- `u8g2.ssd1305_128x32_noname()` - `u8g2.ssd1305_128x32_noname()`
- `u8g2.ssd1306_128x32_univision()` - `u8g2.ssd1306_128x32_univision()`
- `u8g2.ssd1306_128x64_noname()` - `u8g2.ssd1306_128x64_noname()`
...@@ -258,6 +264,8 @@ Initialize a display via Hardware SPI. ...@@ -258,6 +264,8 @@ Initialize a display via Hardware SPI.
- `u8g2.ssd1306_96x16_er()` - `u8g2.ssd1306_96x16_er()`
- `u8g2.ssd1309_128x64_noname0()` - `u8g2.ssd1309_128x64_noname0()`
- `u8g2.ssd1309_128x64_noname2()` - `u8g2.ssd1309_128x64_noname2()`
- `u8g2.ssd1318_128x96()`
- `u8g2.ssd1318_128x96_xcp()`
- `u8g2.ssd1322_nhd_128x64()` - `u8g2.ssd1322_nhd_128x64()`
- `u8g2.ssd1326_er_256x32()` - `u8g2.ssd1326_er_256x32()`
- `u8g2.ssd1327_ea_w128128()` - `u8g2.ssd1327_ea_w128128()`
...@@ -269,10 +277,13 @@ Initialize a display via Hardware SPI. ...@@ -269,10 +277,13 @@ Initialize a display via Hardware SPI.
- `u8g2.sed1520_122x32()` - `u8g2.sed1520_122x32()`
- `u8g2.ssd1606_172x72()` - `u8g2.ssd1606_172x72()`
- `u8g2.ssd1607_200x200()` - `u8g2.ssd1607_200x200()`
- `u8g2.ssd1607_gd_200x200()`
- `u8g2.ssd1607_ws_200x200()`
- `u8g2.st7565_64128n()` - `u8g2.st7565_64128n()`
- `u8g2.st7565_ea_dogm128()` - `u8g2.st7565_ea_dogm128()`
- `u8g2.st7565_ea_dogm132()` - `u8g2.st7565_ea_dogm132()`
- `u8g2.st7565_erc12864()` - `u8g2.st7565_erc12864()`
- `u8g2.st7565_erc12864_alt()`
- `u8g2.st7565_lm6059()` - `u8g2.st7565_lm6059()`
- `u8g2.st7565_nhd_c12832()` - `u8g2.st7565_nhd_c12832()`
- `u8g2.st7565_nhd_c12864()` - `u8g2.st7565_nhd_c12864()`
...@@ -590,3 +601,13 @@ See [u8g2 setFontRefHeightText()](https://github.com/olikraus/u8g2/wiki/u8g2refe ...@@ -590,3 +601,13 @@ See [u8g2 setFontRefHeightText()](https://github.com/olikraus/u8g2/wiki/u8g2refe
Activate or disable power save mode of the display. Activate or disable power save mode of the display.
See [u8g2 setPowerSave()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setpowersave). See [u8g2 setPowerSave()](https://github.com/olikraus/u8g2/wiki/u8g2reference#setpowersave).
## u8g2.disp:updateDisplay()
Updates the display.
See [u8g2 updateDisplay()](https://github.com/olikraus/u8g2/wiki/u8g2reference#updateDisplay).
## u8g2.disp:updateDisplayArea()
Updates the specified rectangle area of the display.
See [u8g2 updateDisplayArea()](https://github.com/olikraus/u8g2/wiki/u8g2reference#updateDisplayArea).
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
--defsym=strncmp=ets_strncmp --defsym=strncmp=ets_strncmp
--defsym=strncpy=ets_strncpy --defsym=strncpy=ets_strncpy
--defsym=strstr=ets_strstr --defsym=strstr=ets_strstr
--defsym=strdup=ets_strdup
--defsym=memcmp=ets_memcmp --defsym=memcmp=ets_memcmp
--defsym=memcpy=ets_memcpy --defsym=memcpy=ets_memcpy
--defsym=memmove=ets_memmove --defsym=memmove=ets_memmove
......
...@@ -5,6 +5,7 @@ MEMORY ...@@ -5,6 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3FF00000, len = 0x10 dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000 dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000 iram1_0_seg : org = 0x40100000, len = 0x8000
iram0_0_seg : org = 0x4010E000, len = 0x2000
irom0_0_seg : org = 0x40210000, len = 0xE0000 irom0_0_seg : org = 0x40210000, len = 0xE0000
} }
...@@ -14,12 +15,13 @@ PHDRS ...@@ -14,12 +15,13 @@ PHDRS
dram0_0_phdr PT_LOAD; dram0_0_phdr PT_LOAD;
dram0_0_bss_phdr PT_LOAD; dram0_0_bss_phdr PT_LOAD;
iram1_0_phdr PT_LOAD; iram1_0_phdr PT_LOAD;
iram0_0_phdr PT_LOAD;
irom0_0_phdr PT_LOAD; irom0_0_phdr PT_LOAD;
} }
/* Default entry point: */ /* Default entry point: */
ENTRY(user_start_trampoline) ENTRY(call_user_start)
EXTERN(_DebugExceptionVector) EXTERN(_DebugExceptionVector)
EXTERN(_DoubleExceptionVector) EXTERN(_DoubleExceptionVector)
EXTERN(_KernelExceptionVector) EXTERN(_KernelExceptionVector)
...@@ -102,26 +104,23 @@ SECTIONS ...@@ -102,26 +104,23 @@ SECTIONS
*(.entry.text) *(.entry.text)
*(.init.literal) *(.init.literal)
*(.init) *(.init)
/*
/* SDK libraries that used in bootup process, interruption handling * SDK libraries that used in bootup process, interruption handling
* and other ways where flash cache (iROM) is unavailable: */ * and other ways where flash cache (iROM) is unavailable:
*libmain.a:*(.literal .literal.* .text .text.*) */
*libnet80211.a:*(.literal .text) *libmain.a:*( .literal .literal.* .text .text.*)
*libphy.a:*(.literal .text) *libphy.a:*( .literal .literal.* .text .text.*)
*libpp.a:*(.literal .text) *libpp.a:*( .literal .literal.* .text .text.*)
*libgcc.a:*(.literal .text) *libgcc.a:*( .literal .literal.* .text .text.*)
*libnet80211.a:*(.literal .text )
/* Following SDK libraries have .text sections, but not included in iRAM: */ /*
/* *libat.a:*(.literal .text) - not used anywhere in NodeMCU */ * The following SDK libraries have .literal and .text sections, but are
/* *libcrypto.a:*(.literal .text) - tested that safe to keep in iROM */ * either not used in NodeMCU or are safe to execute out of in iROM:
/* *libdriver.a:*(.literal .text) - not used anywhere in NodeMCU */ * libat.a libcrypto.a libdriver.a libnet80211.a libespnow.a
/* *libespnow.a:*(.literal .text) - not used anywhere in NodeMCU */ * liblwip_536.a ibpwm.a libwpa.a ibwps.a
/* *liblwip_536.a:*(.literal .text) - source-based library used instead */ */
/* *libpwm.a:*(.literal .text) - our own implementation used instead */
/* *libwpa.a:*(.literal .text) - tested that safe to keep in iROM */
/* *libwps.a:*(.literal .text) - tested that safe to keep in iROM */
*(.iram.text .iram0.text .iram0.text.*) *(.iram.text .iram0.text .iram0.text.*)
*(.iram0.data.*)
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
...@@ -221,11 +220,21 @@ SECTIONS ...@@ -221,11 +220,21 @@ SECTIONS
_lit4_end = ABSOLUTE(.); _lit4_end = ABSOLUTE(.);
} >iram1_0_seg :iram1_0_phdr } >iram1_0_seg :iram1_0_phdr
.pre_init_ram : ALIGN(0x1000)
{
_iram0_start = ABSOLUTE(.);
*(*.pre_init)
_iram0_end = ABSOLUTE(.);
} >iram0_0_seg :iram0_0_phdr
.irom0.text : ALIGN(0x1000) .irom0.text : ALIGN(0x1000)
{ {
_irom0_text_start = ABSOLUTE(.); _irom0_text_start = ABSOLUTE(.);
KEEP(*(.irom0.ptable))
. = ALIGN(0x1000);
*(.servercert.flash) *(.servercert.flash)
*(.clientcert.flash) *(.clientcert.flash)
. = ALIGN(0x1000);
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
*(.literal .text .literal.* .text.*) *(.literal .text .literal.* .text.*)
*(.rodata*) *(.rodata*)
...@@ -247,7 +256,6 @@ SECTIONS ...@@ -247,7 +256,6 @@ SECTIONS
/* Reserved areas, flash page aligned and last */ /* Reserved areas, flash page aligned and last */
. = ALIGN(4096); . = ALIGN(4096);
KEEP(*(.irom.reserved .irom.reserved.*))
_irom0_text_end = ABSOLUTE(.); _irom0_text_end = ABSOLUTE(.);
_flash_used_end = ABSOLUTE(.); _flash_used_end = ABSOLUTE(.);
......
...@@ -65,7 +65,7 @@ finalise = function(sck) ...@@ -65,7 +65,7 @@ finalise = function(sck)
sck:close() sck:close()
local s = file.stat(image) local s = file.stat(image)
if (s and size == s.size) then if (s and size == s.size) then
wifi.setmode(wifi.NULLMODE) wifi.setmode(wifi.NULLMODE, false)
collectgarbage();collectgarbage() collectgarbage();collectgarbage()
-- run as separate task to maximise RAM available -- run as separate task to maximise RAM available
node.task.post(function() node.flashreload(image) end) node.task.post(function() node.flashreload(image) end)
......
...@@ -56,8 +56,11 @@ if node.flashindex() == nil then ...@@ -56,8 +56,11 @@ if node.flashindex() == nil then
node.flashreload('flash.img') node.flashreload('flash.img')
end end
tmr.alarm(0, 1000, tmr.ALARM_SINGLE, local initTimer = tmr.create()
function() initTimer:register(1000, tmr.ALARM_SINGLE,
local fi=node.flashindex; return pcall(fi and fi'_init') function()
end) local fi=node.flashindex; return pcall(fi and fi'_init')
end
)
initTimer:start()
{
"files": [ "main.lc", "supporfile.lc", "othercontent.txt" ],
"secret": "supersekrit"
}
...@@ -31,7 +31,7 @@ call which invokes the `luaOTA` module by a `require "luaOTA.check"` statement. ...@@ -31,7 +31,7 @@ call which invokes the `luaOTA` module by a `require "luaOTA.check"` statement.
The `config.json` file which provides the minimum configuration parameters to connect to The `config.json` file which provides the minimum configuration parameters to connect to
the WiFi and provisioning server, however these can by overridden through the UART by the WiFi and provisioning server, however these can by overridden through the UART by
first doing a `tmr.stop(0)` and then a manual initialisation as described in the first doing a `abortOTA()` and then a manual initialisation as described in the
[init.lua](#initlua) section below. [init.lua](#initlua) section below.
`luaOTA` configures the wifi and connects to the required sid in STA mode using the `luaOTA` configures the wifi and connects to the required sid in STA mode using the
...@@ -90,13 +90,17 @@ require "LuaOTA.check" ...@@ -90,13 +90,17 @@ require "LuaOTA.check"
however if the configuration is incomplete then this can be aborted as manual process however if the configuration is incomplete then this can be aborted as manual process
by entering the manual command through the UART by entering the manual command through the UART
```Lua ```Lua
tmr.stop(0); require "luaOTA.check":_init {ssid ="SOMESID" --[[etc. ]]} abortOTA(); require "luaOTA.check":_init {ssid ="SOMESID" --[[etc. ]]}
``` ```
where the parameters to the `_init` method are: where the parameters to the `_init` method are:
- `ssid` and `spwd`. The SSID of the Wifi service to connect to, together with its - `ssid` and `spwd`. The SSID of the Wifi service to connect to, together with its
password. password.
- `server` and `port`. The name or IP address and port of the provisioning server. - `server` and `port`. The name or IP address and port of the provisioning server.
- `app`. The filename of the module which will be `required` after provisioning is
complete. Defaults to LuaOTA/default.
- `entry`. The method that will be called on the module indicated by `app`. Defaults
to `init`
- `secret`. A site-specific secret shared with the provisioning server for MD5-based - `secret`. A site-specific secret shared with the provisioning server for MD5-based
signing of the protocol messages. signing of the protocol messages.
- `leave`. If true the STA service is left connected otherwise the wifi is shutdown - `leave`. If true the STA service is left connected otherwise the wifi is shutdown
...@@ -129,6 +133,12 @@ Note that even though this file is included in the `luaOTA` subdirectory within ...@@ -129,6 +133,12 @@ Note that even though this file is included in the `luaOTA` subdirectory within
examples, this is designed to run on the host and should not be included in the examples, this is designed to run on the host and should not be included in the
ESP SPIFFS. ESP SPIFFS.
The example server expects a repository directory, which is expected to contain
the to-be-provisioned files (.lua files, .lc files...). Additionally, it expects
a .json file for every ESP that is to be provisioned, containing the "secret"
as well as the relevant filenames. This file should be called 'ESP-xxxxxxxx.json',
with 'xxxxxxxx' replaced with the ChipID.
## Implementation Notes ## Implementation Notes
- The NodeMCu build must include the following modules: `wifi`, `net`, `file`, `tmr`, - The NodeMCu build must include the following modules: `wifi`, `net`, `file`, `tmr`,
...@@ -156,11 +166,6 @@ called using the object form self:someFunc() to get the context as a parameter. ...@@ -156,11 +166,6 @@ called using the object form self:someFunc() to get the context as a parameter.
- This coding also makes a lot of use of tailcalls (See PiL 6.3) to keep the stack size - This coding also makes a lot of use of tailcalls (See PiL 6.3) to keep the stack size
to a minimum. to a minimum.
- The update process uses a master timer in `tmr` slot 0. The index form is used here
in preference to the object form because of the reduced memory footprint. This also
allows the developer to abort the process early in the boot sequence by issuing a
`tmr.stop(0)` through UART0.
- The command protocol is unencrypted and uses JSON encoding, but all exchanges are - The command protocol is unencrypted and uses JSON encoding, but all exchanges are
signed by a 6 char signature taken extracted from a MD5 based digest across the JSON signed by a 6 char signature taken extracted from a MD5 based digest across the JSON
string. Any command which fails the signature causes the update to be aborted. Commands string. Any command which fails the signature causes the update to be aborted. Commands
...@@ -205,7 +210,7 @@ function using an object constructor `self:self:somefunction()`, but where the f ...@@ -205,7 +210,7 @@ function using an object constructor `self:self:somefunction()`, but where the f
can have a self argument then the alternative is to use an upvalue binding. See the can have a self argument then the alternative is to use an upvalue binding. See the
`tmr` alarm call at the end of `_init.lua` as an example: `tmr` alarm call at the end of `_init.lua` as an example:
```Lua ```Lua
tmr.alarm(0, 500, tmr.ALARM_AUTO, self:_doTick()) self.timer:alarm( 500, tmr.ALARM_AUTO, self:_doTick())
``` ```
- The `self:_doTick()` is evaluated before the alarm API call. This autoloads - The `self:_doTick()` is evaluated before the alarm API call. This autoloads
`luaOTA/_doTick.lc` which stores `self` as a local and returns a function which takes `luaOTA/_doTick.lc` which stores `self` as a local and returns a function which takes
......
tmr.stop(0)--SAFETRIM if (self.timer) then self.timer:stop() end--SAFETRIM
-- function _doTick(self) -- function _doTick(self)
-- Upvals -- Upvals
...@@ -32,7 +32,7 @@ tmr.stop(0)--SAFETRIM ...@@ -32,7 +32,7 @@ tmr.stop(0)--SAFETRIM
-- some resources that are no longer needed and set backstop timer for general -- some resources that are no longer needed and set backstop timer for general
-- timeout. This also dereferences the previous doTick cb so it can now be GCed. -- timeout. This also dereferences the previous doTick cb so it can now be GCed.
collectgarbage() collectgarbage()
tmr.alarm(0, 30000, tmr.ALARM_SINGLE, self.startApp) self.timer:alarm(0, 30000, tmr.ALARM_SINGLE, self.startApp)
return self:_provision(socket,rec) return self:_provision(socket,rec)
end end
...@@ -67,7 +67,7 @@ tmr.stop(0)--SAFETRIM ...@@ -67,7 +67,7 @@ tmr.stop(0)--SAFETRIM
return self.startApp("OK: Timeout on waiting for wifi station setup") return self.startApp("OK: Timeout on waiting for wifi station setup")
elseif (tick_count == 26) then -- wait up to 2.5 secs for TCP response elseif (tick_count == 26) then -- wait up to 2.5 secs for TCP response
tmr.unregister(0) self.timer:unregister()
pcall(conn.close, conn) pcall(conn.close, conn)
self.socket=nil self.socket=nil
return startApp("OK: Timeout on waiting for provision service response") return startApp("OK: Timeout on waiting for provision service response")
......
...@@ -45,5 +45,5 @@ ...@@ -45,5 +45,5 @@
package.loaded[self.modname] = nil package.loaded[self.modname] = nil
self.modname=nil self.modname=nil
tmr.alarm(0, 500, tmr.ALARM_AUTO, self:_doTick()) self.timer:alarm( 500, tmr.ALARM_AUTO, self:_doTick())
-- end -- end
...@@ -17,7 +17,7 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -17,7 +17,7 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
-- Note that for 2nd and subsequent responses, we assme that the service has -- Note that for 2nd and subsequent responses, we assme that the service has
-- "authenticated" itself, so any protocol errors are fatal and lkely to -- "authenticated" itself, so any protocol errors are fatal and lkely to
-- cause a repeating boot, throw any protocol errors are thrown. -- cause a repeating boot, throw any protocol errors are thrown.
local buf, config, file, log = buf, self.config, file, self.log local config, file, log = self.config, file, self.log
local cmdlen = (rec:find('\n',1, true) or 0) - 1 local cmdlen = (rec:find('\n',1, true) or 0) - 1
local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen) local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen)
if cmdlen < 16 or if cmdlen < 16 or
...@@ -89,9 +89,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto ...@@ -89,9 +89,9 @@ local function receiveRec(socket, rec) -- upval: self, buf, crypto
end end
if s then if s then
print("Updated ".. name) print("Updated ".. cmd.name)
else else
file.remove(name) file.remove(cmd.name)
resp.s = "write failed" resp.s = "write failed"
end end
buf = {} buf = {}
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- upvals -- upvals
local crypto, file, json, net, node, table, tmr, wifi = local crypto, file, json, net, node, table, wifi =
crypto, file, sjson, net, node, table, tmr, wifi crypto, file, sjson, net, node, table, wifi
local error, pcall = error, pcall local error, pcall = error, pcall
local loadfile, gc = loadfile, collectgarbage local loadfile, gc = loadfile, collectgarbage
local concat, unpack = table.concat, unpack or table.unpack local concat, unpack = table.concat, unpack or table.unpack
...@@ -19,7 +19,11 @@ local self = {post = node.task.post, prefix = "luaOTA/", conf = {}} ...@@ -19,7 +19,11 @@ local self = {post = node.task.post, prefix = "luaOTA/", conf = {}}
self.log = (DEBUG == true) and print or function() end self.log = (DEBUG == true) and print or function() end
self.modname = ... self.modname = ...
self.timer = tmr.create()
_G["stopOTA"] = function()
self.timer:stop()
end
-------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------
-- Utility Functions -- Utility Functions
...@@ -40,9 +44,9 @@ function self.sign(arg) --upval: crypto, json, self ...@@ -40,9 +44,9 @@ function self.sign(arg) --upval: crypto, json, self
return arg .. crypto.toHex(crypto.hmac("MD5", arg, self.secret):sub(-3)) .. '\n' return arg .. crypto.toHex(crypto.hmac("MD5", arg, self.secret):sub(-3)) .. '\n'
end end
function self.startApp(arg) --upval: gc, self, tmr, wifi function self.startApp(arg) --upval: gc, self, wifi
gc();gc() gc();gc()
tmr.unregister(0) self.timer.unregister()
self.socket = nil self.socket = nil
if not self.config.leave then wifi.setmode(wifi.NULLMODE,false) end if not self.config.leave then wifi.setmode(wifi.NULLMODE,false) end
local appMod = self.config.app or "luaOTA.default" local appMod = self.config.app or "luaOTA.default"
......
# Coroutine Helper Module
Documentation for this Lua module is available in the [Lua Modules->cohelper](../../docs/lua-modules/cohelper.md) MD file and in the [Official NodeMCU Documentation](https://nodemcu.readthedocs.io/) in `Lua Modules` section.
--[[ A coroutine Helper T. Ellison, June 2019
This version of couroutine helper demonstrates the use of corouting within
NodeMCU execution to split structured Lua code into smaller tasks
]]
--luacheck: read globals node
local modname = ...
local function taskYieldFactory(co)
local post = node.task.post
return function(nCBs) -- upval: co,post
post(function () -- upval: co, nCBs
coroutine.resume(co, nCBs or 0)
end)
return coroutine.yield() + 1
end
end
return { exec = function(func, ...) -- upval: modname
package.loaded[modname] = nil
local co = coroutine.create(func)
return coroutine.resume(co, taskYieldFactory(co), ... )
end }
# FIFO Module
Documentation for this Lua module is available in the [fifo.md](../../docs/lua-modules/fifo.md) file and in the [Official NodeMCU Documentation](https://nodemcu.readthedocs.io/) in `Lua Modules` section.
...@@ -68,9 +68,8 @@ pages: ...@@ -68,9 +68,8 @@ pages:
- 'cron': 'modules/cron.md' - 'cron': 'modules/cron.md'
- 'crypto': 'modules/crypto.md' - 'crypto': 'modules/crypto.md'
- 'dht': 'modules/dht.md' - 'dht': 'modules/dht.md'
- 'ds18b20': 'modules/ds18b20.md'
- 'encoder': 'modules/encoder.md' - 'encoder': 'modules/encoder.md'
- 'enduser setup': 'modules/enduser-setup.md' - 'enduser setup / captive portal / WiFi manager': 'modules/enduser-setup.md'
- 'file': 'modules/file.md' - 'file': 'modules/file.md'
- 'gdbstub': 'modules/gdbstub.md' - 'gdbstub': 'modules/gdbstub.md'
- 'gpio': 'modules/gpio.md' - 'gpio': 'modules/gpio.md'
...@@ -89,6 +88,7 @@ pages: ...@@ -89,6 +88,7 @@ pages:
- 'pcm' : 'modules/pcm.md' - 'pcm' : 'modules/pcm.md'
- 'perf': 'modules/perf.md' - 'perf': 'modules/perf.md'
- 'pwm' : 'modules/pwm.md' - 'pwm' : 'modules/pwm.md'
- 'pwm2' : 'modules/pwm2.md'
- 'rc' : 'modules/rc.md' - 'rc' : 'modules/rc.md'
- 'rfswitch' : 'modules/rfswitch.md' - 'rfswitch' : 'modules/rfswitch.md'
- 'rotary' : 'modules/rotary.md' - 'rotary' : 'modules/rotary.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