Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update README.md #3450

Merged
merged 10 commits into from
Feb 18, 2024
36 changes: 22 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# NodeMCU 3.0.0
# NodeMCU Firmware 3.0.0
MichaelCurrin marked this conversation as resolved.
Show resolved Hide resolved
> Lua-based firmware for ESP8266 WiFi SOC
marcelstoer marked this conversation as resolved.
Show resolved Hide resolved

[![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://img.shields.io/gitter/room/badges/shields.svg)](https://gitter.im/nodemcu/nodemcu-firmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware)
[![CI](https://github.com/nodemcu/nodemcu-firmware/workflows/CI/badge.svg)](https://github.com/nodemcu/nodemcu-firmware/actions?query=workflow:"CI")
[![Documentation Status](https://img.shields.io/badge/docs-release-yellow.svg?style=flat)](http://nodemcu.readthedocs.io/en/release/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/nodemcu/nodemcu-firmware/blob/release/LICENSE)

### A Lua based firmware for ESP8266 WiFi SOC
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](#license)

NodeMCU is an open source [Lua](https://www.lua.org/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/) and uses an on-module flash-based [SPIFFS](https://github.com/pellepl/spiffs) file system. NodeMCU is implemented in C and is layered on the [Espressif NON-OS SDK](https://github.com/espressif/ESP8266_NONOS_SDK).

The firmware was initially developed as is a companion project to the popular ESP8266-based [NodeMCU development modules]((https://github.com/nodemcu/nodemcu-devkit-v1.0)), but the project is now community-supported, and the firmware can now be run on _any_ ESP module.

# Summary
## Summary

- Easy to program wireless node and/or access point
- Based on Lua 5.1.4 or Lua 5.3 but without `debug`, `io`, `os` and (most of the) `math` modules
- Asynchronous event-driven programming model
- more than **70 built-in C modules** and **close to 20 Lua modules**
- More than **70 built-in C modules** and **close to 20 Lua modules**
- Firmware available with or without floating point support (integer-only uses less memory)
- Up-to-date documentation at [https://nodemcu.readthedocs.io](https://nodemcu.readthedocs.io)

### LFS support

In July 2018 support for a Lua Flash Store (LFS) was introduced. LFS allows Lua code and its associated constant data to be executed directly out of flash-memory; just as the firmware itself is executed. This now enables NodeMCU developers to create **Lua applications with up to 256Kb** Lua code and read-only constants executing out of flash. All of the RAM is available for read-write data!

# Programming Model
## Programming Model

The NodeMCU programming model is similar to that of [Node.js](https://en.wikipedia.org/wiki/Node.js), only in Lua. It is asynchronous and event-driven. Many functions, therefore, have parameters for callback functions. To give you an idea what a NodeMCU program looks like study the short snippets below. For more extensive examples have a look at the [`/lua_examples`](lua_examples) folder in the repository on GitHub.

Expand All @@ -44,27 +44,35 @@ wifi.setmode(wifi.STATION)
wifi.sta.config{ssid="SSID", pwd="password"}
```

# Documentation
## Documentation

The entire [NodeMCU documentation](https://nodemcu.readthedocs.io) is maintained right in this repository at [/docs](docs). The fact that the API documentation is maintained in the same repository as the code that *provides* the API ensures consistency between the two. With every commit the documentation is rebuilt by Read the Docs and thus transformed from terse Markdown into a nicely browsable HTML site at [https://nodemcu.readthedocs.io](https://nodemcu.readthedocs.io).


Pages:

- How to [build the firmware](https://nodemcu.readthedocs.io/en/release/build/)
- How to [flash the firmware](https://nodemcu.readthedocs.io/en/release/flash/)
- How to [upload code and NodeMCU IDEs](https://nodemcu.readthedocs.io/en/release/upload/)
- API documentation for every module

# Releases

## Releases

Due to the ever-growing number of modules available within NodeMCU, pre-built binaries are no longer made available. Use the automated [custom firmware build service](http://nodemcu-build.com/) to get the specific firmware configuration you need, or consult the [documentation](http://nodemcu.readthedocs.io/en/release/build/) for other options to build your own firmware.

This project uses two main branches, `release` and `dev`. `dev` is actively worked on and it's also where PRs should be created against. `release` thus can be considered "stable" even though there are no automated regression tests. The goal is to merge back to `release` roughly every 2 months. Depending on the current "heat" (issues, PRs) we accept changes to `dev` for 5-6 weeks and then hold back for 2-3 weeks before the next snap is completed.

A new tag is created every time `dev` is merged back to `release`. They are listed in the [releases section here on GitHub](https://github.com/nodemcu/nodemcu-firmware/releases). Tag names follow the \<SDK-version\>-release_yyyymmdd pattern.
A new tag is created every time the `dev` branch is merged back to `release`. They are listed in this repo's [releases](https://github.com/nodemcu/nodemcu-firmware/releases).

Tag names follow the `<SDK-version>-release_yyyymmdd` pattern.
marcelstoer marked this conversation as resolved.
Show resolved Hide resolved

# Support
## Support

See [https://nodemcu.readthedocs.io/en/release/support/](https://nodemcu.readthedocs.io/en/release/support/).

# License
## License

Licensed under [MIT](/LICENSE) © [zeroday](https://github.com/NodeMCU)/[nodemcu.com](http://nodemcu.com/index_en.html)
MichaelCurrin marked this conversation as resolved.
Show resolved Hide resolved

[MIT](https://github.com/nodemcu/nodemcu-firmware/blob/release/LICENSE) © [zeroday](https://github.com/NodeMCU)/[nodemcu.com](http://nodemcu.com/index_en.html)
[NodeMCU documentation]: https://nodemcu.readthedocs.io
MichaelCurrin marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions app/uzlib/uzlib_deflate.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* under the standard NodeMCU MIT licence, but is available to the other
* contributors to this source under any permissive licence.
*
* My primary algorthmic reference is RFC 1951: "DEFLATE Compressed Data
* My primary algorithmic reference is RFC 1951: "DEFLATE Compressed Data
* Format Specification version 1.3", dated May 1996.
*
* Also because the code in this module is drawn from different sources,
Expand Down Expand Up @@ -161,7 +161,7 @@ struct outputBuf {
* Set up the constant tables used to drive the compression
*
* Constants are stored in flash memory on the ESP8266 NodeMCU firmware
* builds, but only word aligned data access are supported in hardare so
* builds, but only word aligned data access are supported in hardware so
* short and byte accesses are handled by a S/W exception handler and are
* SLOW. RAM is also at premium, so these short routines are driven by
* byte vectors copied into RAM and then used to generate temporary RAM
Expand Down
6 changes: 3 additions & 3 deletions app/uzlib/uzlib_inflate.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,22 +525,22 @@ static int uncompress_stream (UZLIB_DATA *d) {
}

/*
* This implementation has a different usecase to Paul Sokolovsky's
* This implementation has a different use case to Paul Sokolovsky's
* uzlib implementation, in that it is designed to target IoT devices
* such as the ESP8266. Here clarity and compact code size is an
* advantage, but the ESP8266 only has 40-45Kb free heap, and has to
* process files with an unpacked size of up 256Kb, so a streaming
* implementation is essential.
*
* I have taken the architectural decision to hide the implementation
* detials from the uncompress routines and the caller must provide
* details from the uncompress routines and the caller must provide
* three support routines to handle the streaming:
*
* void get_byte(void)
* void put_byte(uchar b)
* uchar recall_byte(uint offset)
*
* This last must be able to recall an output byte with an offet up to
* This last must be able to recall an output byte with an offset up to
* the maximum dictionary size.
*/

Expand Down
2 changes: 1 addition & 1 deletion docs/lcd.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Essentially testing any eLua compiler or runtime changes are a total pain, becau

I tested my patch in standard Lua built with "make generic" and against the [Lua 5.1 suite](http://lua-users.org/lists/lua-l/2006-03/msg00723.html). The test suite was an excellent testing tool, and it revealed a number of cases that exposed logic flaws in my approach, resulting from Lua's approach of not carrying out inline status testing by instead implementing a throw / catch strategy. In fact I realised that I had to redesign the vector generation algorithm to handle this robustly.

As with all eLua builds the patch assumes Lua will not be executing in a multithreaded environment with OS threads running different lua_States. (This is also the case for the NodeMCU firmware). It executes the full test suite cleanly as maximum test levels and I also added some specific tests to cover new **stripdebug** usecases.
As with all eLua builds the patch assumes Lua will not be executing in a multithreaded environment with OS threads running different lua_States. (This is also the case for the NodeMCU firmware). It executes the full test suite cleanly as maximum test levels and I also added some specific tests to cover new **stripdebug** use cases.

Once this testing was completed, I then ported the patch to the NodeMCU build. This was pretty straight forward as this code is essentially independent of the NodeMCU functional changes. The only real issue as to ensure that the NodeMCU `c_strlen()` calls replaced the standard `strlen()`, etc.

Expand Down
6 changes: 3 additions & 3 deletions docs/lfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Another good use of this technique is when you have resources such as CSS, HTML

- Linux users can just use these tools natively. Windows users can also to do this in a linux VM or use our standard Docker image. Another alternative is to get yourself a Raspberry Pi or equivalent SBC and use a package like [DietPi](http://www.dietpi.com/) which makes it easy to install the OS, a Webserver and Samba and make the RPi look like a NAS to your PC. It is also straightforward to write a script to automatically recompile a Samba folder after updates and to make the LFS image available on the webservice so that your ESP modules can update themselves OTA using the new `HTTP_OTA.lua` example.

- In principle, only the environment component needed to support application development is `luac.cross`, built by the `app/lua/lua_cross` make. (Some developers might also use the `spiffsimg` exectable, made in the `tools/spifsimg` subdirectory). Both of these components use the host toolchain (that is the compiler and associated utilities), rather than the Xtensa cross-compiler toolchain, so it is therefore straightforward to make under any environment which provides POSIX runtime support, including WSL, MacOS and Cygwin.
- In principle, only the environment component needed to support application development is `luac.cross`, built by the `app/lua/lua_cross` make. (Some developers might also use the `spiffsimg` executable, made in the `tools/spifsimg` subdirectory). Both of these components use the host toolchain (that is the compiler and associated utilities), rather than the Xtensa cross-compiler toolchain, so it is therefore straightforward to make under any environment which provides POSIX runtime support, including WSL, MacOS and Cygwin.

Most Lua developers seem to start with the [ESPlorer](https://github.com/4refr0nt/ESPlorer) tool, a 'simple to use' IDE that enables beginning Lua developers to get started. ESPlorer can be slow cumbersome for larger ESP application, and it requires a direct UART connection. So many experienced Lua developers switch to a rapid development cycle where they use a development machine to maintain your master Lua source. Going this route will allow you use your favourite program editor and source control, with one of various techniques for compiling the lua on-host and downloading the compiled code to the ESP:

Expand All @@ -198,7 +198,7 @@ My current practice is to use a small bootstrap `init.lua` file in SPIFFS to con

Under rare circumstances, for example a power fail during the flashing process, the flash can be left in a part-written state following a `flashreload()`. The Lua RTS start-up sequence will detect this and take the failsafe option of resetting the LFS to empty, and if this happens then the LFS `_init` function will be unavailable. Your `init.lua` should therefore not assume that the LFS contains any modules (such as `_init`), and should contain logic to detect if LFS reset has occurred and if necessary reload the LFS again. Calling `node.flashindex("_init")()` directly will result in a panic loop in these circumstances. Therefore first check that `node.flashindex("_init")` returns a function or protect the call, `pcall(node.flashindex("_init"))`, and decode the error status to validate that initialisation was successful.

No doubt some standard usecase / templates will be developed by the community over the next six months.
No doubt some standard use case / templates will be developed by the community over the next six months.

A LFS image can be loaded in the LFS store by either during provisioning of the initial firmware image or programmatically at runtime as discussed further in [Compiling and Loading LFS Images](#compiling-and-loading-lfs-images) below.
one of two mechanisms:
Expand All @@ -219,5 +219,5 @@ A separate `node.flashindex()` function creates a new Lua closure based on a mod

- **Flash caching coherency**. The ESP chipset employs hardware enabled caching of the `ICACHE_FLASH` address space, and writing to the flash does not flush this cache. However, in this restart model, the CPU is always restarted before any updates are read programmatically, so this (lack of) coherence isn't an issue.

- **Failsafe reversion**. Since the entire image is precompiled and validated before loading into LFS, the chances of failure during reload are small. The loader uses the Flash NAND rules to write the flash header flag in two parts: one at start of the load and again at the end. If on reboot, the flag in on incostent state, then the LFS is cleared and disabled until the next reload.
- **Failsafe reversion**. Since the entire image is precompiled and validated before loading into LFS, the chances of failure during reload are small. The loader uses the Flash NAND rules to write the flash header flag in two parts: one at start of the load and again at the end. If on reboot, the flag is in an inconsistent state, then the LFS is cleared and disabled until the next reload.

2 changes: 1 addition & 1 deletion docs/lua-developer-faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ If you are used coding in a procedural paradigm then it is understandable that y

If you look at the `app/modules/tmr.c` code for this function, then you will see that it executes a low level `ets_delay_us(delay)`. This function isn't part of the NodeMCU code or the SDK; it's actually part of the xtensa-lx106 boot ROM, and is a simple timing loop which polls against the internal CPU clock. `tmr.delay()` is really intended to be used where you need to have more precise timing control on an external hardware I/O (e.g. lifting a GPIO pin high for 20 μSec). It does this with interrupts enabled, because so there is no guarantee that the delay will be as requested, and the Lua RTS itself may inject operations such as GC, so if you do this level of precise control then you should encode your application as a C library.

It will achieve no functional purpose in pretty much every other usecase, as any other system code-based activity will be blocked from execution; at worst it will break your application and create hard-to-diagnose timeout errors. We therefore deprecate its general use.
It will achieve no functional purpose in pretty much every other use case, as any other system code-based activity will be blocked from execution; at worst it will break your application and create hard-to-diagnose timeout errors. We therefore deprecate its general use.

### How do I avoid a PANIC loop in init.lua?

Expand Down
2 changes: 1 addition & 1 deletion docs/lua53.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ The same Lua51 ROTable functionality and limitations also apply to Lua53 in orde

### Proto Structures

Standard Lua 5.3 contains a new peep hole optimisation relating to closures: the Proto structure now contains one RW field pointing to the last closure created, and the GC adopts a lazy approach to recovering these closures. When a new closure is created, if the old one exists _and the upvals are the same_ then it is reused instead of creating a new one. This allows peephole optimisation of a usecase where a function closure is embedded in a do loop, so the higher cost closure creation is done once rather than `n` times.
Standard Lua 5.3 contains a new peep hole optimisation relating to closures: the Proto structure now contains one RW field pointing to the last closure created, and the GC adopts a lazy approach to recovering these closures. When a new closure is created, if the old one exists _and the upvals are the same_ then it is reused instead of creating a new one. This allows peephole optimisation of a use case where a function closure is embedded in a do loop, so the higher cost closure creation is done once rather than `n` times.

This reduces runtime at the cost of RAM overhead. However for RAM limited IoTs this change introduced two major issues: first, LFS relies on Protos being read-only and this RW `cache` field breaks this assumption; second closures can now exist past their lifetime, and this delays their GC. Memory constrained NodeMCU applications rely on the fact that dead closed upvals can be GCed once the closure is complete. This optimisation changes this behaviour. Not good.

Expand Down
2 changes: 1 addition & 1 deletion docs/spiffs.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ file system will start on a 64k boundary. A newly formatted file system will sta
system will survive lots of reflashing and at least 64k of firmware growth.

The standard build process for the firmware builds the `spiffsimg` tool (found in the `tools/spiffsimg` subdirectory).
The top level Makfile also checks if
The top level Makefile also checks if
there is any data in the `local/fs` directory tree, and it will then copy these files
into the flash disk image. Two images will normally be created -- one for the 512k flash part and the other for the 4M flash part. If the data doesn't
fit into the 512k part after the firmware is included, then the file will not be generated.
Expand Down
4 changes: 2 additions & 2 deletions tools/spiffsimg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

Ever wished you could prepare a SPIFFS image offline and flash the whole
thing onto your microprocessor's storage instead of painstakingly upload
file-by-file through your app on the micro? With spiffsimg you can!
file-by-file through your app on the micro? With `spiffsimg` you can!

For the full gory details see [spiffs.md](../../docs/en/spiffs.md)
For the full gory details see [spiffs.md](../../docs/spiffs.md)