Welcome to Sming Framework¶
Let’s do smart things!!!
Sming is an asynchronous C/C++ framework with superb performance and multiple network features. Sming is open source and is tailored towards embedded devices. It supports multiple architectures as ESP8266 for example.
Summary¶
- Superb performance and memory usage (Sming compiles to native firmware!)
- Fast and user friendly development
- Simple yet powerful hardware API wrappers
- Compatible with standard Libraries - use any popular hardware in few lines of code
- Built-in file system: SPIFFS for Sming
- Built-in powerful wireless modules
- Powerful asynchronous (async) network stack.
- Async TCP and UDP stack based on LWIP.
- With clients supporting: HTTP, MQTT, WebSockets and SMTP.
- And servers for: DNS, FTP, HTTP(+ WebSockets), Telnet.
- With SSL support for all network clients and servers. Based on axTLS and BearSSL.
- Out of the box support for OTA over HTTPS.
- ESP8266 specific features
- Integrated boot loader rBoot with support for 1MB ROMs, OTA firmware updating and ROM switching.
- Crash handlers for analyzing/handling system restarts due to fatal errors or WDT resets.
- PWM support based on Stefan Bruens PWM.
- Optional custom heap allocation based on Umm Malloc.
- Based on Espressif NONOS SDK. Tested with versions 1.5, 2.0 and 3.0.
- Linux/Windows features
- Sming has a host emulator that allows libraries and sample applications to be compiled on a Linux/Windows host system and be tested before uploading them to an actual microcontroller.
Getting Started¶
Development System Installation¶
Sming supports multiple architectures. Choose the architecture of your choice to install the needed development software and toolchain(s).
Getting Started: ESP8266¶
Development Environment¶
Please select the appropriate instructions for setting up the development environment for your platform:
Note
See ESP Quick Toolchain for experimental support for the latest compilers.
Toolchains can all be found in the SmingTools repository.
Contents¶
Ubuntu:
sudo apt-get install make unrar autoconf automake libtool libtool-bin gcc g++ gperf \
flex bison texinfo gawk ncurses-dev libexpat1-dev python sed python-serial \
python-dev srecord bc git help2man unzip bzip2
Fedora:
sudo dnf install make autoconf automake libtool gcc gcc-c++ gperf flex bison texinfo \
gawk ncurses-devel expat-devel python sed pyserial srecord bc git patch \
unzip help2man python-devel
This builds the cross-compiler, linker, etc. required for the ESP8266:
git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
cd esp-open-sdk
# be careful this command can do damage if used
# in the wrong directory, try without sudo first!
sudo chown -R [username] ./
# This will take a while...
make STANDALONE=y
You can find pre-compiled toolchains in the SmingTools repository.
Sming uses the Espressif 3.0.1 SDK which is pulled in automatically during the build.
Previous versions are no longer officially supported.
From the command line:
export ESP_HOME=/opt/esp-open-sdk
export SMING_HOME=/opt/Sming/Sming
To set these permanently, add them to your home .profile
file.
You can alternatively add them to /etc/environment
for all users, like this:
SMING_HOME="/opt/Sming/Sming"
See also Setting up Sming and Netbeans (external page).
Clone the Sming develop
branch to your working directory:
cd $SMING_HOME/../..
git clone https://github.com/SmingHub/Sming.git
# Warning: Do NOT use the --recursive option for the command above.
# Our build mechanism will take care to get the third-party
# sources and patch them, if needed.
# You will get a copy of our `develop` branch which intended for developers
# and it is the one where all new cool (unstable) features are landing.
cd Sming
If you want to use our stable branch:
git checkout origin/master
Change to the application directory and build:
cd $SMING_HOME/../samples/Basic_Blink
make
Flash to your device (using ttyUSB0):
cd $SMING_HOME/../samples/Basic_Blink
make flash
Proceed to Configuring your Esp8266 device.
(You might already have it)
xcode-select --install
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Required for the makefile build system:
brew install binutils coreutils automake wget gawk libtool gettext gperf grep
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
Install gnu-sed and make sure that it is the default sed
command line application:
brew install gnu-sed --with-default-names
If you have already installed gnu-sed
but it is not the default one,
then make sure to uninstall it and install it again with the correct options:
brew uninstall gnu-sed
brew install gnu-sed --with-default-names
We pull this in from the SmingTools repository:
cd ~/
curl -L -O https://github.com/SmingHub/SmingTools/releases/download/1.0/esp-open-sdk-macosx.tar.gz
sudo mkdir -p /opt/
sudo tar -zxf esp-open-sdk-macosx.tar.gz -C /opt/
sudo chmod -R 775 /opt/esp-open-sdk
You can also build it yourself with Homebrew or with MacPorts.
Clone from the Sming repository:
cd <your-favourite-development-folder>/
git clone https://github.com/SmingHub/Sming.git
cd Sming
Warning
Do NOT use the –recursive option for the command above. Our build mechanism will take care to get the third-party sources and patch them, if needed.
You will get a copy of our develop branch which intended for developers. It is the one where all new cool (unstable) features are landing.
If you want to use our stable branch then use the master branch:
git checkout origin/master
Finally, set the SMING_HOME
environment variable to point to <your-favourite-development-folder>/Sming/Sming:
export SMING_HOME=`pwd`
Open with a text editor the .profile
file in your home directory, and add these lines:
export ESP_HOME=/opt/esp-open-sdk
export SMING_HOME=<your-favourite-development-folder>/Sming/Sming
Make sure to replace <your-favourite-development-folder>
in the
command above with the actual directory on your local disk.
(used by Make and Eclipse - make sure to quit Eclipse first)
If you installed Eclipse manually, substitute
/opt/homebrew-cask/Caskroom/eclipse-cpp/4.5.1/Eclipse.app
to
/Applications/Eclipse/eclipse.app
:
sudo /usr/libexec/PlistBuddy -c "Add :LSEnvironment:ESP_HOME string '/opt/esp-open-sdk'" /opt/homebrew-cask/Caskroom/eclipse-cpp/4.5.1/Eclipse.app/Contents/Info.plist
sudo /usr/libexec/PlistBuddy -c "Add :LSEnvironment:SMING_HOME string '/opt/sming/Sming'" /opt/homebrew-cask/Caskroom/eclipse-cpp/4.5.1/Eclipse.app/Contents/Info.plist
sudo /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -v -f /opt/homebrew-cask/Caskroom/eclipse-cpp/4.5.1/Eclipse.app
If you are using Eclipse to build the samples you need to make sure the path is set correctly for the make process.
Your project must also be configured to use the correct serial port for your ESP8266. You can change it like this:
make COM_PORT=/dev/tty.usbserial
Next, ensure that you can build the Basic Blink from a terminal window:
cd $SMING_HOME/samples/Basic_Blink
make
This will also build the required framework components, so may take a few minutes.
If this works without errors then type echo $PATH
and copy the resulting path
to the clipboard.
Now fire up Eclipse and go to
Eclipse ==> Preferences ==> C/C++ ==> Build ==> Environment
and add a new variable PATH. Paste in the path saved from the terminal
session above. You can also add SMING_HOME
and ESP_HOME
variables here
the same way as you set in the export commands above which will then be
set for all the projects.
The standard make files use miniterm.py
to provide a serial Terminal for
debugging the ESP8266. Miniterm does not work inside Eclipse so you
should disable it like this:
make KILL_TERM= TERMINAL=
This will prevent Eclipse from trying to launch miniterm and throwing an error about Inappropriate ioctl for device.
You can use the built in terminal in Eclipse Oxygen by adding it using
Window ==> Show View ==> Terminal
then setting terminal type to Serial
and setting the port to the port
the ESP8266 is connected to. Remember to disconnect before tying to
re-flash the device though.
See Sample Projects for a list of all examples provided with Sming:
cd $SMING_HOME/../samples/
If you want to test some of the examples, try this:
cd $SMING_HOME/../samples
cd Basic_Blink
make
# The command below will upload the sample code to your ESP8266 device
make flash
Proceed to Configuring your Esp8266 device.
This is a package manager, like apt-get but for Windows. Official website: https://chocolatey.org
Note
You may prefer a Manual Windows Installation.
Open an administrative cmd.exe command prompt and paste the text from the box below and press enter:
# Install Latest Chocolatey
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
Choco requires recent version of .NET in order to be able to access successfully HTTPS links. To check if you need upgrade type the following command:
choco --v
If you see a warning similar to the one below then make sure to upgrade your .NET version:
Choco prefers to use TLS v1.2 if it is available, but this client is running on .NET 4.3,
which uses an older SSL. It's using TLS 1.0 or earlier, which makes it susceptible to BEAST
and also doesn't implement the 1/n-1 record splitting mitigation for Cipher-Block Chaining.
Upgrade to at least .NET 4.5 at your earliest convenience.
You can upgrade the .NET version from this direct link or search in internet for “.NET upgrade”.
choco sources add -name smingrepo -source 'https://www.myget.org/F/sming/'
# Powershell - run as Administrator
choco install -y sming
This will install:
- Unofficial Espressif Development Kit for Windows (source)
- Mingw & required packages (source)
- Python
- Latest stable version of Sming (source)
If for some reason you don’t want UDK, MinGW and Environment configured just run:
choco install sming.core -y -source 'https://www.myget.org/f/sming/'
Configure your git client to leave line-endings intact or else patching will fail:
git config --global core.autocrlf input
This will install:
- Java Runtime 8
- Eclipse C/C++ (source)
sming
package
and will create desktop shortcut Sming Examples:
# Run as Administrator
choco install sming.examples -y
You might want to configure your project before building. Edit component.mk to the proper values.
Make sure the MinGW make.exe is the only one in the path. This will correct most “make: ** No rule to make target” problems.*:
# should only show one make
where make.exe
"C:\Tools\mingw64\msys\1.0\bin\make.exe"
- Open Eclipse via “Sming Examples” Desktop link
- Find Basic_Blink project
- Build
Sming is very dynamic and updates are usually announced in gitter. The
command below will get for you the latest stable
release:
choco upgrade sming -y
In case something is broken, this will overwrite the current Sming installation:
choco install sming -y -force -source 'https://www.myget.org/F/sming/'
Proceed to Configuring your Esp8266 device.
Code built for the ESP8266 uses a separate Espressif compiler, but Components such as SPIFFS require additional tools which are built as Windows executable applications.
MinGW provides a (mostly) POSIX-compliant development environment for Windows, including GNU Make and various other command-line tools.
Note
There are two versions of MinGW.
MinGW is the original, and the version recommended for use with Sming.
MinGW-w64 was forked from MinGW in 2007 in order to provide support for 64 bits and new APIs. (Which we don’t need!)
To find out if you already have GCC on your system, type:
where gcc
If it shows C:\MinGW\bin\gcc.exe
then you have a standard MinGW installation. Check the gcc version:
gcc --version
The current version is 8.2.0. You can upgrade by renaming or removing your existing installation then following these instructions.
Download MinGW.7z from the SmingTools repository.
Unzip to default location:
7z -oC:\ x MinGW.7z
Note
You can obtain 7-zip from https://www.7-zip.org/.
Update
PATH
environment variable:SETX PATH "C:\mingw\bin;C:\mingw\msys\1.0\bin;%PATH%"
Make sure it is in this exact order. If you have Cygwin installed make sure the above entries appear first.
You will need to restart your command prompt (and Eclipse, if already running) for these changes to take effect.
To install from the original MinGW source repository:
Get the MingGW Setup and run it. This will create the
C:\MinGW
directory with minimal content.Set PATH environment variable as above.
Install required MinGW packages:
mingw-get install mingw32-base-bin mingw-developer-toolkit-bin mingw32-gcc-g++-bin mingw32-pthreads-w32-dev mingw32-libmingwex
Note that you can upgrade packages using:
mingw-get update mingw-get upgrade
However this will not upgrade a 6.3.0 installation to 8.2.0.
Download toolchain esp-udk-win32.7z.
Unzip to default location:
7z -oC:\Espressif x esp-udk-win32.7z
Set
ESP_HOME
environment variable:SETX ESP_HOME C:\Espressif
Note
There is NO trailing slash on the path!
If you want to set environment variables system-wide, append /M to the command. You’ll need to do this from an administrative command prompt.
Get the current version from https://www.python.org/.
By default, python gets installed here:
C:\Users\xxx\AppData\Local\Programs\Python\Python38\python.exe
Wherever it ends up will either need to be in the path:
setx PATH "C:\Users\xxx\AppData\Local\Programs\Python\Python38;%PATH%"
or located using the PYTHON
environment variable:
setx PYTHON "C:\Users\xxx\AppData\Local\Programs\Python\Python38"
Important
The PYTHON variable may not contain spaces. This is a MinGW restriction.
This is required to fetch and update Sming code from its repository.
- Install command-line GIT client.
These steps are optional, but highly recommended:
- Install Graphical client Git Extensions.
- Create an account at https://github.com. This will allow you to participate in discussions, raise issues and, if you like, Contributing to the framework!
You can put Sming anywhere convenient, provided there are no spaces in the path! For example, C:\tools\sming:
mkdir C:\tools cd /d C:\tools
To obtain the latest develop code with all the latest features and fixes:
git clone https://github.com/SmingHub/Sming
To obtain the latest release:
git clone https://github.com/SmingHub/Sming --branch master
Set
SMING_HOME
environment variable:SETX SMING_HOME C:\tools\Sming\Sming
Note: there is NO trailing slash on the path!
Note
Whilst Windows filenames are not (by default) case-sensitive, the compiler tools are.
Please take care to type paths exactly as shown.
At this stage you should be able to build a sample:
cd samples\Basic_Blink
make -j
If you want to try out the Host emulator, do this:
make -j SMING_ARCH=Host
For build options:
make help
Whilst building and configuring your application is generally easier and faster using the command prompt, developing and debugging code is greatly simplified using an Integrated Development Environment (IDE).
- Install Java Runtime Environment.
- Install Eclipse IDE for C++ Developers.
- Start Eclipse IDE. When prompted, enter
C:\tools\sming
as the workspace path. - Select File -> Import -> General -> Existing Project into Workspace.
In the line Select root directory, select the directory
C:\tools\sming\Sming
and import everything. - Go have a cup of coffee while Eclipse scans all the source code. It can take a while!
- To build a project, right-click and select Build project. Alternatively, select the project and press F9.
The only variable you should need to set within Eclipse is SMING_HOME
.
You can set this within the Eclipse IDE via Window > Preferences -> C/C++ > Build > Environment.
If you set this via global environment variable before starting Eclipse then this step is not necessary.
Note
Variables set within the IDE won’t be accessible in other Eclipse sessions or the command prompt.
All other configuration should be done either in your project’s component.mk file or via command line.
For example, to switch to a Host emulator build, do this:
make SMING_ARCH=Host list-config
This also displays the current configuration settings. Whether you build from command line or Eclipse, the same settings will be used.
Proceed to Configuring your Esp8266 device.
Visit the official Docker Installation Page and follow the instructions tailored for your operating system.
Docker Compose makes dealing with the orchestration processes of Docker containers (such as starting up, shutting down, and setting up intra-container linking and volumes) really easy.
With docker compose we can define the entire multi-container application in single file and then the application can be spinned up using one command.
Visit the official Docker Compose Installation Page and follow the instructions tailored for your operating system.
sming-ide:
build: .
volumes:
- ../../Sming/:/opt/sming/
ports:
#choose a free port to connect to the web C9 editor
- "10080:80"
devices:
# uncomment to map your serial USB adaptor
#- "/dev/ttyUSB0:/dev/ttyUSB0"
privileged: true
cd /opt/sming/docker/ && docker-compose -f sming-ide.yml up -d
Attention
This is pre-release documentation and subject to change.
In Sming 4.0.1 support was added for the ESP Quick Toolchain for GCC 9.2.0.
This also updates the runtime libraries (NewLib) to version 2.2 with integrated PROGMEM handling code.
See Pull Request #1825 for further details.
The new toolchain is consistent across development platforms and adds support for the latest compiler features, as discussed in What are the new features in C++17?.
The toolchains are currently at pre-release, available here.
Download links for the 3.0.0-gnu5
release (8 December 2019) as follows:
- Linux 32-bit: i686-linux-gnu.xtensa-lx106-elf.tar.gz
- Linux 64-bit: x86_64-linux-gnu.xtensa-lx106-elf.tar.gz
- MacOS: x86_64-apple-darwin14.xtensa-lx106-elf.tar.gz
- Windows 32-bit: i686-w64-mingw32.xtensa-lx106-elf.zip
- Windows 64-bit: x86_64-w64-mingw32.xtensa-lx106-elf.zip
Extract the toolchain to a suitable location, such as:
/opt/esp-quick-toolchain
C:\tools\esp-quick-toolchain
and set ESP_HOME
accordingly.
You may need to configure your project to support the specific device being programmed.
Note
Arduino has a system which allows these values to be set based on a board selection. At present Sming does not have such a system so this must be done manually.
Here are a few important ones:
SPI_MODE
Change this if your device fails to program or runSPI_SIZE
If using a device with reduced memory you may need to change this value. Note also that samples using SPIFFS for Sming may not work.COM_PORT
If you haven’t set this already, it will need to match the port you’re using to talk to the Esp8266.COM_SPEED_ESPTOOL
The default value should work fine but you can usually set a much faster speed.
You can set these initially on the command line, like this:
make SMING_ARCH=Esp8266 SPI_MODE=dio SPI_SIZE=4M COM_SPEED_ESPTOOL=921600
Once you’re happy with the settings, you can add them to your project.mk
file.
You can list the current set of configuration variables like this:
make list-config
If you want to reset back to default values, do this:
make config-clean
- See Sming build system for further details about configuring your project.
- See Features for configuring Sming options.
Getting Started: ESP32¶
Requirements¶
In order to be able to compile for the ESP32 architecture you should have ESP-IDF v4.0 installed. A detailed installation manual can be found in the ESP-IDF documentation.
Building¶
Make sure that the IDF_PATH environmental variable is set. Also make sure that the other ESP-IDF environmental variables are set. For example on Linux this can be done using the following command:
source $IDF_PATH/export.sh
Build the framework and application as usual, specifying SMING_ARCH
=Esp32. For example:
cd $SMING_HOME/../samples/Basic_Serial
make SMING_ARCH=Esp32
This builds the application. Once built the application needs to be flashed on a real Esp32 microcontroller to run. Flashing can be done using the following command:
make flash
SDK¶
Sming comes with pre-compiled libraries and configuration files. If needed you can re-configure ESP-IDF using the command below:
make SMING_ARCH=Esp32 sdk-menuconfig
A re-compilation is required after the change of the configuration. This can be done with the following command:
make SMING_ARCH=Esp32 sdk-build
If you want to revert to using the default pre-compiled SDK then issue the following command:
make SMING_ARCH=Esp32 sdk-default
Getting Started: Linux/Windows¶
The latest versions of Sming allow most of components of the library and the sample applications to be compiled on a Linux/Windows host system and be tested before uploading them to the microcontroller.
If you want to try it we have an interactive tutorial that can be run directly from your browser.
Requirements (Linux)¶
Most popular modern distributions should be fine. At the moment we develop only with Ubuntu 16.04 and 18.04.
If your OS is 64 bit then you should install also 32 bit C/C++ compiler and libraries. For Ubuntu, install like this:
sudo apt-get install gcc-multilib g++-multilib
You may wish to install the latest compilers for testing alongside the recent ESP Quick Toolchain updates. Here’s a summary of how to do this:
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install gcc-9 g++-9
# For 64-bit systems
sudo apt install gcc-9-multilib g++-9-multilib
# Set GCC 9 as default
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-9
The current version is GCC 9.2.1.
For the compilation of LWIP CMake
version 3.8 or newer is required.
In order to get newer CMake version under Ubuntu 16.04, do this:
cd /tmp
wget https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4-Linux-x86_64.sh
sudo mkdir /opt/cmake
sudo sh cmake-3.14.4-Linux-x86_64.sh --prefix=/opt/cmake
sudo mv /usr/bin/cmake /usr/bin/cmake.orig
sudo ln -s /opt/cmake/bin/cmake /usr/bin/cmake
Requirements (Windows)¶
For Windows, make sure your MinGW
distro is up to date.
The current version is GCC 8.2.0.
Note
If you don’t already have MinGW installed, see Windows Installation for the Esp8266.
Compilation¶
SMING_ARCH
must be set to use Host
as the desired architecture:
export SMING_ARCH=Host
If you plan to use a debugger make sure to set ENABLE_GDB
and (optionally)
ENABLE_LWIPDEBUG
before compiling the code:
export ENABLE_GDB=1
export ENABLE_LWIPDEBUG=1 # <!-- this will compile also LWIP with debug symbols
Make sure that you are working on a clean source code tree. The following commands may help:
cd $SMING_HOME
make dist-clean
You may need to modify your existing applications to work with the
emulator. Architecture-specific code should be moved into separate code
modules. Code that is specific to the ESP8266 may be conditionally
compiled using #ifdef ARCH_ESP8266
. Similarly, you can check if the
code is compiled for the emulator using #ifdef ARCH_HOST
.
Running on the host¶
Once the sample is compiled, initialise the Virtual Flasher:
make flash
If enabled, this will also create a SPIFFS file system and write it to flash.
To run the application, do this:
make run
Support is provided via TAP network interface (a virtual network layer
operating at the ethernet frame level). A TAP interface must be created
first, and requires root privilege. You can use the
Sming/Arch/Host/Tools/setup-network-linux.sh
. Here is the manual approach:
sudo ip tuntap add dev tap0 mode tap user `whoami`
sudo ip a a dev tap0 192.168.13.1/24
sudo ifconfig tap0 up
# The following lines are needed if you plan to access Internet
sudo sysctl net.ipv4.ip_forward=1
sudo sysctl net.ipv6.conf.default.forwarding=1
sudo sysctl net.ipv6.conf.all.forwarding=1
export INTERNET_IF=wlan0 # <!--- Make sure to replace wlan0 with the network interface connected to Internet
sudo iptables -t nat -A POSTROUTING -o $INTERNET_IF -j MASQUERADE
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i tap0 -o $INTERNET_IF -j ACCEPT
This creates the tap0
interface. The emulator will automatically
select the first tap
interface found. To override this, use the
--ifname
option.
Troubleshooting¶
Make sure to install the 32bit version of the GNU C and C++ compiler, development package and libraries.
Make sure to install the 32bit version of the GNU C and C++ compiler, development package and libraries.
Further reading¶
Allows Sming applications to be built as an executable to run on the development host (Windows or Linux).
This is a source-level emulator for developing and testing new framework code prior to flashing a real device.
This is not a machine emulator; if you need something operating at a lower level take a look at QEMU.
CMake
is required to build LWIP
Ensure you are using relatively recent compilers, with 32-bit libraries available.
For Linux, you may require the gcc-multilib
and g++-multilib
packages to build 32-bit executables on a 64-bit OS.
For Windows, make sure your MinGW
distro is up to date.
See Manual Windows Installation for further details.
Build the framework and application as usual, specifying SMING_ARCH
=Host. For example:
cd $SMING_HOME
make SMING_ARCH=Host
cd $SMING_HOME/../samples/Basic_Serial
make SMING_ARCH=Host
This builds the application as an executable in, for example,
out/Host/firmware/app.exe
. Various command-line options are
supported, use --help
for details.
The easiest way to run the emulator is via make run
. Variables are
used to pass the appropriate options to the command line.
To find out what options are in force, use make list-config
.
This Component builds a library containing architecture-specific code, and defines dependencies for Sming to build for the Host Emulator.
- Source Code
- Host Drivers Component
- Host ESP HAL Component
- Host WiFi Component
- GDB Stub for Host Component
- Heap Component
- Host Library Component
- libc Component
- LWIP Component
- SPI Flash Component
- Virtual Flasher Component
- rBoot Component
- Sming (main) ,Component
Provides low-level peripheral support classes.
Stub functions are provided which insert an appropriate ‘sampling’ delay and return 0.
The emulator does not provide any low-level GPIO support, this is handled at a higher level
using DigitalHooks
.
-
class
DigitalHooks
¶ Class to customise behaviour for digital functions.
- Note
- By default, actions get output to console but this can get very busy. The easiest way to change the behaviour is by sub-classing DigitalHooks and passing the new class instance to
setDigitalHooks()
.
Public Functions
-
virtual void
badPin
(const char *function, uint16_t pin)¶ Report invalid pin number.
- Parameters
function
: Name of function which was calledpin
: The pin number
-
virtual bool
pinMode
(uint16_t pin, uint8_t mode)¶ Set pin mode.
- Parameters
pin
: Has already been range checkedmode
:
- Return Value
true
: if mode can be set for this pin, will be stored
-
virtual void
digitalWrite
(uint16_t pin, uint8_t val)¶ Change pin output.
- Parameters
pin
: Has already been range checkedval
: New pin value
-
virtual uint8_t
digitalRead
(uint16_t pin, uint8_t mode)¶ Read pin state.
- Parameters
pin
: Has already been range checkedmode
: The currently set mode for this pinval
: State for pin
-
virtual void
pullup
(uint16_t pin, bool enable)¶ Set or clear pullup state for a pin.
- Parameters
pin
: Has already been range checkedenable
: true for pullup, false for no pullup
-
virtual unsigned long
pulseIn
(uint16_t pin, uint8_t state, unsigned long timeout)¶ Measure duration of pulse on GPIO.
- Parameters
pin
: GPIO to measurestate
: State of pulse to measure [HIGH | LOW]timeout
: Maximum duration of pulse
- Return Value
unsigned
: long Pulse duration in microseconds
Hardware timers are emulated using a background thread. The O/S scheduler timeslice granularity is quite coarse and for time-critical threads is typically 1ms. Therefore, when a timer becomes close to expiry the thread sits (‘spins’) in a loop to get better resolution. For the rest of the time the thread is suspended or in a wait state.
A header is provided to allow code to compile but the emulator does not provide any further PWM support.
Implements a UART driver to connect via TCP sockets, allowing terminal emulation using telnet.
By default, output to UART0 is sent to the console and keyboard input is written to the UART0 receive queue. If emulation is enabled on any ports then this behaviour is disabled.
-
ENABLE_HOST_UARTID
¶ To enable emulation for a UART, set this value to the numbers required. You would normally add this to a project’s component.mk file.
For example:
ENABLE_HOST_UARTID = 0 1
If setting it on the command line, remember to use quotes:
make ENABLE_HOST_UARTID="0 1"
See Basic Serial which uses both serial ports like this.
-
HOST_UART_PORTBASE
¶ The base port number to use for telnet. Default is 10000, which corresponds to UART0.
This is passed to the command line
--uartport
option.
-
HOST_UART_OPTIONS
¶ By default, this value combines the above options.
Allows full customisation of UART command-line options for
make run
.You should not need to change this for normal use.
Set required ports for emulation using the ENABLE_HOST_UARTID
, then execute make run
.
Note
As an alternative to make run
, you can run the compiled application manually like this:
out/Host/debug/firmware/app --pause --uart=0 --uart=1
Now start a telnet session for each serial port, in separate command windows:
telnet localhost 10000
telnet localhost 10001
In the application window, press Enter. This behaviour is enabled by the
pause
option, which stops the emulator after initialisation so
telnet can connect to it. Without pause
you’ll lose any serial
output at startup.)
Note
For Windows users, putty
is a good alternative to telnet. It also
has options for things like carriage-return/linefeed translation
(“\n” -> “\r\n`”). Run using:
putty telnet://localhost:10000
Port numbers are allocated sequentially from 10000. If you want to use
different port numbers, set HOST_UART_PORTBASE
.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Provides implementations for various low-level functions similar to the Esp8266.
- Task queues
- Timer queues
- System functions
- Source Code
- Host Library Component
- Sming (Esp32) ,Component
- Sming (Host) ,Component
Provides WiFi / network functions. The actual implementations are provided in LWIP
- Source Code
- LWIP Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
HOST_NETWORK_OPTIONS
This Component is required to allow some samples to compile for the Host, however it doesn’t provide any functionality at present.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
This defines the command line to use when make gdb
is run. No additional code is required to debug for the Host.
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
This Component implements heap-related housekeeping functions. Heap usage is tracked using malloc_count. This also provides some validation (using sentinels to detect if memory blocks are overwritten).
-
ENABLE_MALLOC_COUNT
¶ We require malloc_count to keep track of heap usage for system_get_free_heap_size(). It does this by hooking the memory allocation routines (malloc, free, etc.). If you wish to disable this behaviour, set ENABLE_MALLOC_COUNT=0. If using tools such as Valgrind, this will provide a cleaner trace.
- Source Code
- malloc_count Component
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
This Components provides the core funcionality for the Host Emulator:
Classes to provide simple Berkeley socket support for both Linux and Windows
Command line argument parsing
Initialises SPI Flash, Uart server (in Host Drivers) and LWIP
networking, then enters the main task loop. This loop services LWIP plus the task and timer queues
(implemented in Host ESP HAL).
The Ctrl+C
keypress is trapped to provide an orderly exit. If the system has become stuck in a loop or is otherwise
unresponsive, subsquent Ctrl+C presses will force a process termination.
The emulator uses Posix threads (pthread library) to perform background processing which would probably be done in hardware or which is outside of the framework.
Ideally we’d use SCHED_FIFO to disable time-slicing and more closely resemble how interrupts work on a single-core CPU. However, this mode isn’t supported in Windows, and Linux requires priviledged access and can potentially crash the system. Best avoided, I think.
All ESP code runs at a specific interrupt level, where 0 represents regular code. When an interrupt occurs, the level is raised according to the priority of that interrupt. Until that code has finished, only interrupts of a higher priority will pre-empt it.
The set_interrupt_level
function is used to ensure that threads running at different interrupt
levels do not pre-empty each other, as this would introduce problems that do not exist on real hardware.
The main thread is also suspended during interrupt execution.
-
LWIP_SERVICE_INTERVAL
¶ Default: 2ms
LWIP stack is serviced via polling, this determines the interval.
- Source Code
- Host Drivers Component
- Host WiFi Component
- LWIP Component
- SPI Flash Component
- Host ESP HAL ,Component
- Sming (Host) ,Component
Contains implementations of any non-standard C library functions.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Uses LWIP version 2 to enable networking for Sming running on a Windows or Linux Host system.
Note
Network support is enabled by default. If you don’t need it, use the --nonet
command-line option.
-
ENABLE_LWIPDEBUG
¶ - 0 (default)
- Standard build
- 1
- Enable debugging output
-
ENABLE_CUSTOM_LWIP
¶ 2 (default)
Setting this to any other value will cause a build error.
Support is provided via TAP network interface (a virtual network layer operating at the ethernet frame level). A TAP interface must be created first, and requires root priviledge:
sudo ip tuntap add dev tap0 mode tap user `whoami`
sudo ip a a dev tap0 192.168.13.1/24
sudo ifconfig tap0 up
This creates the tap0
interface. The emulator will automatically
select the first tap
interface found. To override this, use the
--ifname
option. An IP address will be assigned, but can be changed
using the --ipaddr
option.
If your application needs to access the internet, additional setup is required:
sudo sysctl net.ipv4.ip_forward=1
sudo sysctl net.ipv6.conf.default.forwarding=1
sudo sysctl net.ipv6.conf.all.forwarding=1
export INTERNET_IF=wlan0 # <!--- Make sure to replace wlan0 with the network interface connected to Internet
sudo iptables -t nat -A POSTROUTING -o $INTERNET_IF -j MASQUERADE
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i tap0 -o $INTERNET_IF -j ACCEPT
Requires NPCAP library to be installed. Provided with current (3.0.2) version of Wireshark.
By default, the first valid network adapter will be used, with address assigned via DHCP.
If the adapter is wrong, get a list thus:
out\Host\Windows\debug\firmware\app --ifname=?
or
make run HOST_NETWORK_OPTIONS=--ifname=?
produces a listing:
Available adapters:
- 0: {ACC6BFB2-A15B-4CF8-B93A-8D97644D0AAC} - Oracle
192.168.56.1 / 255.255.255.0
- 1: {A12D4DD0-0EA8-435D-985E-A1F96F781EF0} - NdisWan Adapter
- 2: {3D66A354-39DD-4C6A-B9C4-14EE223FC3D1} - MS NDIS 6.0 LoopBack Driver
0.0.0.0 / 255.0.0.0
- 3: {BC53D919-339E-4D70-8573-9D7A8AE303C7} - NdisWan Adapter
- 4: {3CFD43EA-9CC7-44A7-83D4-EB04DD029FE7} - NdisWan Adapter
- 5: {530640FF-A9C3-436B-9EA2-65102C788119} - Realtek PCIe GBE Family Controller
192.168.1.70 / 255.255.255.0
- 6: {0F649280-BAC2-4515-9CE3-F7DFBB6A1BF8} - Kaspersky Security Data Escort Adapter
10.102.37.150 / 255.255.255.252
Then use the appropriate number (or GUID), with the gateway IP address - an address will be assigned via DHCP:
make run HOST_NETWORK_OPTIONS="--ifname=5 --gateway=192.168.1.254"
You can find gateway addresses using the ipconfig
command.
If you want to use a specific IP address, the appropriate adapter will be selected but you still need to specify the gateway address:
make run HOST_NETWORK_OPTIONS="--ipaddr=192.168.1.10 --gateway=192.168.1.254"
- Host WiFi ,Component
- Host Library ,Component
- Sming (Host) ,Component
lwIP is a small independent implementation of the TCP/IP protocol suite.
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This making lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.
lwIP was originally developed by Adam Dunkels at the Computer and Networks Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS) and is now developed and maintained by a worldwide network of developers.
- IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over multiple network interfaces
- ICMP (Internet Control Message Protocol) for network maintenance and debugging
- IGMP (Internet Group Management Protocol) for multicast traffic management
- MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2
- ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration)
- DHCP, AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection) and (stateless) DHCPv6
- UDP (User Datagram Protocol) including experimental UDP-lite extensions
- TCP (Transmission Control Protocol) with congestion control, RTT estimation fast recovery/fast retransmit and sending SACKs
- raw/native API for enhanced performance
- Optional Berkeley-like socket API
- TLS: optional layered TCP (“altcp”) for nearly transparent TLS for any TCP-based protocol (ported to mbedTLS) (see changelog for more info)
- PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet)
- DNS (Domain name resolver incl. mDNS)
- 6LoWPAN (via IEEE 802.15.4, BLE or ZEP)
- HTTP server with SSI and CGI (HTTPS via altcp)
- SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp
- SNTP (Simple network time protocol)
- NetBIOS name service responder
- MDNS (Multicast DNS) responder
- iPerf server implementation
- MQTT client (TLS support via altcp)
lwIP is freely available under a BSD license.
lwIP has grown into an excellent TCP/IP stack for embedded devices, and developers using the stack often submit bug fixes, improvements, and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for software development, maintenance and distribution. Everyone can help improve lwIP by use of Savannah’s interface, Git and the mailing list. A core team of developers will commit changes to the Git source tree.
The lwIP TCP/IP stack is maintained in the ‘lwip’ Git module and contributions (such as platform ports) are in the ‘contrib’ Git module.
See doc/savannah.txt for details on Git server access for users and developers.
The current Git trees are web-browsable: http://git.savannah.gnu.org/cgit/lwip.git http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git
Submit patches and bugs via the lwIP project page: http://savannah.nongnu.org/projects/lwip/
Continuous integration builds (GCC, clang): https://travis-ci.org/lwip-tcpip/lwip
Self documentation of the source code is regularly extracted from the current Git sources and is available from this web page: http://www.nongnu.org/lwip/
Also, there are mailing lists you can subscribe at http://savannah.nongnu.org/mail/?group=lwip plus searchable archives: http://lists.nongnu.org/archive/html/lwip-users/ http://lists.nongnu.org/archive/html/lwip-devel/
There is a wiki about lwIP at http://lwip.wikia.com/wiki/LwIP_Wiki You might get questions answered there, but unfortunately, it is not as well maintained as it should be.
lwIP was originally written by Adam Dunkels: http://dunkels.com/adam/
Reading Adam’s papers, the files in docs/, browsing the source code documentation and browsing the mailing list archives is a good way to become familiar with the design of lwIP.
Adam Dunkels adam@sics.se Leon Woestenberg leon.woestenberg@gmx.net
This Component emulates an embedded flash memory device using a backing file. It includes additional checks on addresses, sizes and alignments to detect common issues which can be more difficult to find when running on target hardware.
The default backing file is called flash.bin
, located in the same directory as the host executable.
See Virtual Flasher for configuration details.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Flash memory access is emulated using SPI Flash.
This Component implements make targets to operate on the flash backing file in a similar way to flashing a real device.
The following options are interpreted and used to provide command-line parameters to the emulator executable:
-
FLASH_BIN
¶ Full path to the flash backing file
-
HOST_FLASH_OPTIONS
¶ This defaults to a combination of the above variables, but you can override if necessary.
The size of the flash memory is set via SPI_SIZE
.
See Esptool for details and other applicable variables.
make flashinit
to clear and reset the file.make flashfs
to copy the generated SPIFFS image into the backing file.make flash
writes out all required images to the backing file. For now, this is the same asmake flashfs
but that will change when support is added for custom user images.
- Sming (Host) ,Component
- Add passthrough support for real serial ports to permit connection of physical devices.
- Consider how this mechanism might be used to support emulation of other devices (SPI, I2C, etc).
- Development platforms with SPI or I2C (e.g. Raspberry Pi) could be supported.
- Are there any generic device emulators available? For example, to simulate specific types of SPI slave.
You can also try Sming without installing anything locally. We have an interactive tutorial that can be run directly from your browser.
Documentation¶
In addition to our online documentation, you can also generate a complete documentation locally by following these instructions.
Examples¶
The examples are a great way to learn the API and brush up your C/C++ knowledge. Once you have completed the installation of the development tools, you can get the latest source code.
git clone https://github.com/SmingHub/Sming.git
And check some of the examples.
- Basic Blink
- Simple GPIO input/output
- Start Serial communication
- Connect to WiFi
- Read DHT22 sensor
- HTTP client
- OTA application update based on rBoot
- Embedded HTTP Web Server
- Email Client
Further documentation about the Sample Projects is available too.
Basic Blink¶
Blinking is something like the “Hello World” example for the embedded world. You can check it using the commands below:
cd Sming/samples
cd Basic_Blink
make # -- compiles the application
make flash # -- tries to upload the application to your ESP8266 device.
See Basic Blink for more information.
Simple GPIO input/output¶
#define LED_PIN 2 // GPIO2
...
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
For a complete example take a look at the Basic Blink sample.
Start Serial communication¶
Serial.begin(9600);
Serial.println("Hello Sming! Let's do smart things.");
Connect to WiFi¶
WifiStation.enable(true);
WifiStation.config("LOCAL-NETWORK", "123456789087"); // Put you SSID and Password here
Read DHT22 sensor¶
#include <Libraries/DHTesp/DHTesp.h> // This is just a popular Arduino library!
#define DHT_PIN 0 // GPIO0
DHTesp dht;
void init()
{
dht.setup(DHT_PIN, DHTesp::DHT22);
float h = dht.getHumidity();
float t = dht.getTemperature();
}
Take a look at the code of the DHT22 Humidity Sensor sample.
HTTP client¶
HttpClient thingSpeak;
...
thingSpeak.downloadString("http://api.thingspeak.com/update?key=XXXXXXX&field1=" + String(sensorValue), onDataSent);
void onDataSent(HttpClient& client, bool successful)
{
if (successful) {
Serial.println("Successful!");
}
else {
Serial.println("Failed");
}
}
For more examples take a look at the HTTP Client, HttpClient Instapush and ThingSpeak Http Client samples.
OTA application update based on rBoot¶
void OtaUpdate()
{
uint8 slot;
rboot_config bootconf;
Serial.println("Updating...");
// need a clean object, otherwise if run before and failed will not run again
if (otaUpdater) {
delete otaUpdater;
}
otaUpdater = new RbootHttpUpdater();
// select rom slot to flash
bootconf = rboot_get_config();
slot = bootconf.current_rom;
if (slot == 0) {
slot = 1;
}
else {
slot = 0;
}
// flash rom to position indicated in the rBoot config rom table
otaUpdater->addItem(bootconf.roms[slot], ROM_0_URL);
// and/or set a callback (called on failure or success without switching requested)
otaUpdater->setCallback(OtaUpdate_CallBack);
// start update
otaUpdater->start();
}
For a complete example take a look at the Basic rBoot sample.
Embedded HTTP Web Server¶
server.listen(80);
server.paths.set("/", onIndex);
server.paths.set("/hello", onHello);
server.paths.setDefault(onFile);
Serial.println("=== WEB SERVER STARTED ===");
Serial.println(WifiStation.getIP());
...
void onIndex(HttpRequest &request, HttpResponse &response)
{
TemplateFileStream *tmpl = new TemplateFileStream("index.html");
auto &vars = tmpl->variables();
vars["counter"] = String(counter);
vars["IP"] = WifiStation.getIP().toString();
vars["MAC"] = WifiStation.getMacAddress().toString();
response.sendTemplate(tmpl);
}
void onFile(HttpRequest &request, HttpResponse &response)
{
String file = request.getPath();
if (file[0] == '/')
file = file.substring(1);
response.setCache(86400, true);
response.sendFile(file);
}
For more examples take a look at the HttpServer Config Network, Bootstrap Http Server, HttpServer Websockets and AJAX Http Server samples.
Email client¶
SmtpClient emailClient;
emailClient.connect(Url("smtp://user:password@domain.com"));
MailMessage* mail = new MailMessage();
mail->from = "developers@sming";
mail->to = "iot-developers@world";
mail->subject = "Greetings from Sming";
mail->setBody("Hello");
FileStream* file= new FileStream("image.png");
mail->addAttachment(file);
emailClient.onMessageSent(onMailSent);
emailClient.send(mail);
...
int onMailSent(SmtpClient& client, int code, char* status)
{
MailMessage* mail = client.getCurrentMessage();
...
if(client.countPending() == 0) {
client.quit();
}
return 0;
}
See the SMTP Client sample for details.
Live Debugging¶
Applications based on Sming Framework that are flashed and running on an ESP8266 device can be debugged using interactive debuggers. In order to debug an application it has to be re-compiled with the ENABLE_GDB=1 directive. And then flashed on the device. As shown below:
cd $SMING_HOME/../samples/LiveDebug
make clean
make ENABLE_GDB=1
make flashapp # <-- this will update only the application firmware.
Once the debuggable application is flashed on the device the developers have to run GDB. The easiest way to run the command-line GDB is to execute the following command:
make gdb
Developers using Eclipse CDT can have debugging sessions like the one below:
See Live Debug sample for details.
Features¶
There are multiple custom features that can be enabled by default. For example: SSL support, custom LWIP, open PWM, custom heap allocation, more verbose debugging, etc.
The features available are dependent upon the architecture for which Sming is being built.
Sming (main)¶
This is the main Sming Component containing all architecture-independent code. All architecture-specific stuff is in either Sming (Esp8266) or Sming (Host).
Configuration variables¶
Serial Communications¶
-
COM_SPEED
¶ Default baud rate for serial port.
This will recompile your application to use the revised baud rate. Note that this will change the default speed used for both flashing and serial comms. See also Esptool and Terminal for further details.
The default rate for serial ports is 115200 baud. You can change it like this:
make COM_SPEED=921600
Debug information log level and format¶
-
DEBUG_VERBOSE_LEVEL
¶ When compiled in debug mode (:envvar:SMING_RELEASE undefined) there are four debug levels in increasing level of verbosity:
- 0: errors
- 1: warnings
- 2: information (default)
- 3: debug
Change it like this:
make DEBUG_VERBOSE_LEVEL=3
-
DEBUG_PRINT_FILENAME_AND_LINE
¶ Set this to 1 to include the filename and line number in every line of debug output. This will require extra space on flash.
Note
If you change these settings and want them applied to Sming, not just your project, then you’ll need to recompile all components like this:
make components-clean
make DEBUG_VERBOSE_LEVEL=3
Release builds¶
-
SMING_RELEASE
¶ By default, this value is undefined to produce a build with debug output. To build for release, do this:
make SMING_RELEASE=1
This remains in force until you change it back:
make SMING_RELEASE=
Localisation¶
-
LOCALE
¶ Sming can format dates/time values based on a country code identified by this value. This is provided as a #define symbol for your application to use. See Sming/Core/SmingLocale.h for further details.
Components¶
FlashString¶
Introduction¶ This is a C++ library to simplify the definition and use of data structures stored in program (flash) memory in an embedded microcontroller.
It was developed for use with Sming and the ESP8266 but could be ported to other platforms relatively easily.
Perhaps the most common use for PROGMEM data is passing strings around, usually as a pointer to a ‘C’ NUL-terminated char array. There are a couple of problems with this:
- If we need to know how long the string is, we need to call
strlen_P()
, which is really expensive computationally.- We can’t include NUL characters in the string.
Both of these are easily solved by passing the length along with the string, like this:
char myString[] PROGMEM = "hello, this is a string"; Serial.println(FPSTR(myString), sizeof(myString) - 1);Of course, passing two parameters instead of one gets tiresome and is not very C++, is it?
This library implements C++ objects stored in flash memory, using macros to create the data structures. The object interfaces are implemented using class templates for performance and flexibility.
The classes are all in the
FSTR
namespace.Objects¶ Introduction¶ An
FSTR::Object
is a class template with array-like behaviour, though it is not used directly.Instead, use one of the four classes in the library:
Each type has its own set of macros for easy data construction, and creation of the appropriate Object class which may then be used directly.
Macros follow the same pattern:
DEFINE_FSTR_*
- Creates a static data structure with an associated Object reference. The _LOCAL variant makes the reference
static constexpr
.DECLARE_FSTR_*
- Use this in a header to declare an Object reference so it can be used across translation units.
Created symbols are C++ and adopt any enclosing namespaced.
Reading Object content¶ To read parts of an Object, use the
FSTR::Object::read()
method.If the data isn’t used very often, use the
FSTR::Object::readFlash()
method instead as it avoids disrupting the cache. TheFSTR::Stream
class (aliasFlashMemoryStream
) does this by default.Object Internals¶ This section provides some examples of how structures are created, but in normal use you should use the provided macros as they simplify the task and include structure validity checks.
FSTR::ObjectBase
is a non-template POD base class, and looks like this (methods omitted):class ObjectBase { uint32_t flashLength_; // uint8_t data[]; };Attention
flashLength_
must not be accessed directly; use thelength()
method instead.Data structures are created like this:
constexpr const struct { ObjectBase object; char data[8]; } flashHelloData PROGMEM = { {5}, "hello" };The
object
field may then be cast to a reference of the required type, like this:auto& str = flashHelloData.object.as<FSTR::String>();If you want to access it as an array, do this:
auto& arr = str.as<FSTR::Array<char>>();References are an efficient and convenient way to access an Object, and should not consume any memory themselves as the compiler/linker resolve them to the actual object.
However, in practice the Espressif compiler stores a full pointer to most things to support relative addressing, and if the references aren’t declared PROGMEM they’ll consume RAM.
Copy behaviour¶ Whilst references are the preferred way to access flash Objects, they can also be created dynamically:
FSTR::String emptyString; FSTR::String stringCopy(FS("Inline string"));Such instances are stored in RAM but only consume 4 bytes as they simply keep a pointer to the real flash Object.
Note
Don’t try to copy ObjectBase!
Here’s a somewhat contrived example to demonstrate:
DEFINE_FSTR_DATA_LOCAL(flashHelloData, "Hello"); auto myCopy = flashHelloData.object; Serial.print("myCopy.length() = "); Serial.println(myCopy.length());In debug builds, this will throw an assertion. In release builds, you’ll get a zero-length object.
Aggregate initialization¶ We use aggregate initialization to set up the structures so the data is fixed at link time without any constructor or initialiser functions.
This means classes cannot have:
- user-provided constructors
- brace-or-equal-initializers for non-static data members
- private or protected non-static data members
- virtual functions
- base classes (until C++17)
This is why
FSTR::ObjectBase
is used to define data structures.Classes created using the
FSTR::Object
template ensures the necessary constructors are available to do this:auto myCopy = flashHelloData.object.as<FSTR::String>(); Serial.print("myCopy.length() = "); Serial.println(myCopy.length());The macros create an appropriate Object& reference for you.
Structure checks¶ The construction macros include a sanity check to ensure the initialization is truly just Plain Old Data, without any hidden initialisers.
You may encounter one of the following errors during compilation:
- The value of ‘X’ is not usable in a constant expression
- FSTR structure not POD
This generally means one or more of the arguments in the initialisation data is not
constexpr
. Most compilers are quite relaxed about this butGCC 4.8.5
is particularly thick.In testing, this happens with references for global Objects, which of course cannot be constexpr. To fix it, the offending Object either needs to be redefined LOCAL, or if the Object data is in scope (i.e. defined in the same source file) then you can get a direct pointer to it using the
FSTR_PTR()
macro.Macros¶
DECLARE_FSTR_OBJECT
(name, ObjectType)¶Declare a global Object reference.
- Parameters
name
:ObjectType
:
DEFINE_FSTR_REF
(name, ObjectType, object)¶Define a reference to an object.
- Parameters
name
: Name for referenceObjectType
: Fully qualified typename of object required, e.g. FSTR::String, FlashString, FSTR::Vector<int>, etc.object
: Object instance to cast
DEFINE_FSTR_REF_NAMED
(name, ObjectType)¶
FSTR_DATA_NAME
(name)¶Provide internal name for generated flash string structures.
FSTR_PTR
(objref)¶Given an Object& reference, return a pointer to the actual object.
However, some older compilers such as GCC 4.8.5 requires such references to be declared constexpr. For example, this fails with
FSTR structure not POD
:DEFINE_FSTR(globalStringRef, "This creates a global reference"); DEFINE_VECTOR(myVector, FSTR::String, &globalStringRef); ^^^
- Parameters
objref
: When an Object pointer is required, such when defining entries for a Vector or Map, it is usually sufficient to use &objref.Global references cannot be declared constexpr, so changing DEFINE_FSTR to DEFINE_FSTR_LOCAL will fix the problem.
Another solution is to get a direct pointer to the actual data structure:
DEFINE_VECTOR(myVector, FSTR::String, FSTR_PTR(globalStringRef));We can only do this of course if the data structure is in scope.
FSTR_CHECK_STRUCT
(name)¶Check structure is POD-compliant and correctly aligned.
IMPORT_FSTR_OBJECT
(name, ObjectType, file)¶Import an object from an external file with reference.
- See
- See also
IMPORT_FSTR_DATA
- Note
- Can only be used at file scope
- Parameters
name
: Name for the objectObjectType
: Object type for referencefile
: Absolute path to the file containing the content
IMPORT_FSTR_OBJECT_LOCAL
(name, ObjectType, file)¶Like IMPORT_FSTR_OBJECT except reference is declared static constexpr.
Class Template¶
- template <class ObjectType, typename ElementType>
classObject
: public FSTR::ObjectBase¶Base class template for all types.
- See
- https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
- Template Parameters
ObjectType
: The object type actually being instantiatedElementType
:Public Types
- template<>
usingIterator
= ObjectIterator<ObjectType, ElementType>¶Public Functions
Object
()¶Creates a null object.
Object
(const Object &obj)¶Copy constructor.
- Note
- Objects are usually passed around by reference or as a pointer, but for ease of use we need a working copy constructor.
- Iterator
begin
() const
- Iterator
end
() const
- size_t
length
() constGet the length of the content in elements.
- template <typename ValueType>
intindexOf
(const ValueType &value) const
- ElementType
valueAt
(unsigned index) const
- ElementType
operator[]
(unsigned index) constArray operator[].
- size_t
elementSize
() const
- const ElementType *
data
() const
- size_t
read
(size_t index, ElementType *buffer, size_t count) constRead content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t index, ElementType *buffer, size_t count) constRead content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
size
() constGet the object data size in bytes.
- Note
- Always an integer multiple of 4 bytes
- template <class ObjectType>
constexpr const ObjectType &as
() constCast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- size_t
read
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- bool
isCopy
() constPublic Members
- uint32_t
flashLength_
Public Static Functions
- static const ObjectType &
empty
()Return an empty object which evaluates to null.
Flash Strings¶ Introduction¶ Strings are basically just arrays of char, but have additional methods to allow them to be used more easily. These methods are consistent with Wiring
String
, so should be reasonably familiar.
length()
returns the number of characters in the String, excluding the NUL terminatorsize()
returns the number of bytes of storage usedFor example, “123” is actually stored as
{ '1', '2', '3', '\0' }
so the length is 3 and the size is 4. However, “1234” is stored as{ '1', '2', '3', '4', '\0' }
so the length is 4 and the size is 8.Using Strings¶ Note
You can use
FSTR::String
or the Sming-providedFlashString
alias to work with Strings.Within a function:
DEFINE_FSTR_LOCAL(myFlashString, "This is my flash string"); Serial.println(myFlashString); Serial.printf("myFlashString has %u chars and occupies %u bytes\n", myFlashString.length(), myFlashString.size());To use Strings across translation units, we do this in the header:
DECLARE_FSTR(myFlashString);And in a source file:
DEFINE_FSTR(myFlashString, "I am a flash string\0I've got a Naughty NUL.");You can generally use a Flash String anywhere you can use a regular Wiring String as it has an implicit ::String() operator. Note that
WString
is used within the library for disambiguation.Inline Strings¶ Use the
FS()
macro to create Flash Strings inline:Serial.println(FS("A Flash String"));Note
The macro makes use of
FS_PTR()
which creates the structure and returns a pointer to it. It behaves like a function call, although the compiler inlines the code.Therefore FS() may only be used within functions. At file scope you’ll get this error:
statement-expressions are not allowed outside functions nor in template-argument listsThe example above doesn’t provide any improvement over
F
as there are no Flash String overloads available, so is equivalent to this:String s = FS("A Flash String"); Serial.println(s);However, it’s rather different if you pass it to a function which recognises Flash Strings, like this:
FSTR::println(Serial, FS("A Flash String"));This is equivalent to:
FS("A Flash String").printTo(Serial); Serial.println();
FSTR::String::printTo()
uses no heap and imposes no restriction on the string length.Nested Inline Strings¶ It would be really useful to be able to use inline Strings this within nested structures, and this can be done provided those structures are in RAM.
Important
Inline Strings cannot be used when defining Vectors or Maps.
Here’s is a simplified structure we will attempt to initialize:
static const struct { FlashString* string; } flashData PROGMEM = { FS_PTR("Inline Flash String") }; Serial.println(*flashData.string);The static flashData structure gets initialised at runtime on first use, as per C++ rules. This attempts to copy our pointer into the flashData structure which clearly it cannot do as it’s in
PROGMEM
, so we get a LOAD/STORE error. We must remove PROGMEM.Avoiding the heap¶ Instead of using a temporary Wiring String, you can use
LOAD_FSTR()
to load the content into a temporary stack buffer:DEFINE_FSTR(globalTest, "This is a testing string"); void func() { LOAD_FSTR(local, globalTest); printf("%s, %u characters, buffer is %u bytes\n", local, globalTest.length(), sizeof(local)); }You can do this with inline Flash Strings using
FSTR_ARRAY()
:FSTR_ARRAY(buffer, "text");Is roughly equivalent to:
char name[] = "text";Except the buffer is word aligned, so sizeof(name) may differ.
Macros¶
FS_PTR
(str)¶Define an inline String and return a pointer to it.
- Note
- The rather obscure
asm
statement is required to prevent the compiler from discarding the symbol at link time, which leads to an ‘undefined reference’ error
FS
(str)¶Define an inline FSTR::String and return it as a copy.
Example:
Serial.println(FS("This is a Flash String"));
DECLARE_FSTR
(name)¶Declare a global FSTR::String& reference.
- Note
- Define the FSTR::String object using DEFINE_STR()
- Parameters
name
:
DEFINE_FSTR
(name, str)¶Define a FSTR::String object with global reference.
Example:
- Parameters
name
: Name of FSTR::String& reference to definestr
: Content of the FSTR::StringDEFINE_FSTR(test, “This is a test\0Another test\0hello”)
The data includes the nul terminator but the length does not.
DEFINE_FSTR_LOCAL
(name, str)¶Like DEFINE_FSTR except reference is declared static constexpr.
DEFINE_FSTR_DATA
(name, str)¶Define a FSTR::String data structure.
- Parameters
name
: Name of data structurestr
: Quoted string content
LOAD_FSTR
(name, fstr)¶Load a FSTR::String object into a named local (stack) buffer.
Example:
DEFINE_FSTR(globalTest, "This is a testing string") ... LOAD_FSTR(local, globalTest) printf("%s, %u characters, buffer is %u bytes\n", local, globalTest.length(), sizeof(local));
FSTR_ARRAY
(name, str)¶Define a flash FSTR::String and load it into a named char[] buffer on the stack.
- Note
- Equivalent to
char name[] = "text"
except the buffer is word aligned. Faster than using a temporary Wiring String and avoids using the heap.- Parameters
name
: Name of char[] bufferstr
: Content of FSTR::String
IMPORT_FSTR
(name, file)¶Define a FSTR::String containing data from an external file.
- See
- See also
IMPORT_FSTR_DATA
- Parameters
name
: Name for the FSTR::String objectfile
: Absolute path to the file containing the content
IMPORT_FSTR_LOCAL
(name, file)¶Like IMPORT_FSTR except reference is declared static constexpr.
FSTR_TABLE
(name)¶declare a table of FlashStrings
- Parameters
name
: name of the tableDeclares a simple table. Example:
DEFINE_FSTR(fstr1, "Test string #1"); DEFINE_FSTR(fstr2, "Test string #2"); FSTR_TABLE(table) = { &fstr1, &fstr2, };Table entries may be accessed directly as they are word-aligned. Examples:
debugf("fstr1 = '%s'", FSTR::String(*table[0]).c_str()); debugf("fstr2.length() = %u", table[1]->length());String Class¶
- class
String
: public FSTR::Object<String, char>¶describes a counted string stored in flash memory
Public Functions
- size_t
size
() const¶Get the number of bytes used to store the String.
- Note
- Always an integer multiple of 4 bytes
- flash_string_t
data
() const¶Get a WString-compatible pointer to the flash data.
- bool
equals
(const char *cstr, size_t len = 0) const¶Check for equality with a C-string.
- Note
- loads string into a stack buffer for the comparison, no heap required
- Parameters
cstr
:len
: Length of cstr (optional)- Return Value
bool
: true if strings are identical
- bool
equals
(const String &str) const¶Check for equality with another String.
- Parameters
str
:- Return Value
bool
: true if strings are identical
- bool
operator==
(const char *str) const¶
- bool
operator!=
(const char *str) const¶
operator WString
() const¶
- bool
equals
(const WString &str) const¶
- bool
equalsIgnoreCase
(const WString &str) const¶
- bool
operator==
(const WString &str) const¶
- bool
operator!=
(const WString &str) const¶
- StringPrinter
printer
() const¶Supports printing of large String objects.
Avoids implicit String() cast when working with large FlashStrings:
IMPORT_FSTR(largeString, PROJECT_DIR "/files/large-text.txt"); Serial.println(largeString.printer());
- size_t
printTo
(Print &p) const¶
- Iterator
begin
() const
- Iterator
end
() const
- size_t
length
() constGet the length of the content in elements.
- int
indexOf
(const ValueType &value) const
- char
valueAt
(unsigned index) const
- char
operator[]
(unsigned index) constArray operator[].
- size_t
elementSize
() const
- size_t
read
(size_t index, char *buffer, size_t count) const¶Read content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
read
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t index, char *buffer, size_t count) const¶Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- template <class ObjectType>
constexpr const ObjectType &as
() constCast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- bool
isCopy
() constPublic Members
- uint32_t
flashLength_
Public Static Functions
- static const String &
empty
()Return an empty object which evaluates to null.
Arrays¶ Introduction¶ Supports arrays of simple types, such as char, int, double, or POD structures (i.e. basic C structures).
FSTR::Array
is a class template, so requires an additionalElementType
parameter:#include <FlashString/Array.hpp> DEFINE_FSTR_ARRAY(myDoubleArray, double, PI, 53.0, 100, 1e8, 47 ); Serial.print("My double array: "); myDoubleArray.printTo(Serial); Serial.println();Note
Objects do not inherit from Printable because it is a virtual base class.
Therefore, statements like
Serial.println(myDoubleArray)
are not supported.This also avoids ambiguity between implicit WString conversions.
There are some Print helper functions in the library you can use:
FSTR::println(Serial, myDoubleArray);These are templated so will handle both simple data types and Objects.
You can share Arrays between translation units by declaring it in a header:
DECLARE_FSTR_ARRAY(table);Macros¶
DECLARE_FSTR_ARRAY
(name, ElementType)¶Declare a global Array& reference.
- Note
- Use
DEFINE_FSTR_ARRAY
to instantiate the global Object- Parameters
name
:ElementType
:
DEFINE_FSTR_ARRAY
(name, ElementType, ...)¶Define an Array Object with global reference.
- Note
- Unlike String, array is not NUL-terminated
- Parameters
name
: Name of Array& reference to defineElementType
:...
: List of ElementType items
DEFINE_FSTR_ARRAY_LOCAL
(name, ElementType, ...)¶Like DEFINE_FSTR_ARRAY except reference is declared static constexpr.
DEFINE_FSTR_ARRAY_DATA
(name, ElementType, ...)¶Define an Array data structure.
- Parameters
name
: Name of data structureElementType
:...
: List of ElementType items
LOAD_FSTR_ARRAY
(name, array)¶Load an Array object into a named local (stack) buffer.
- Note
- Example:
DEFINE_FSTR_ARRAY(fsArray, double, 5.33, PI) ... LOAD_FSTR_ARRAY(arr, fsArray) printf("arr[0] = %f, %u elements, buffer is %u bytes\n", arr[0], fsArray.length(), sizeof(arr));
FSTR_ARRAY_ARRAY
(name, ElementType, ...)¶Define an Array and load it into a named buffer on the stack.
- Note
- Equivalent to
ElementType name[] = {a, b, c}
except the buffer is word-aligned
IMPORT_FSTR_ARRAY
(name, ElementType, file)¶Define an Array containing data from an external file.
- See
- See also
IMPORT_FSTR_DATA
- Parameters
name
: Name for the Array objectElementType
: Array element typefile
: Absolute path to the file containing the content
IMPORT_FSTR_ARRAY_LOCAL
(name, ElementType, file)¶Like IMPORT_FSTR_ARRAY except reference is declared static constexpr.
Classes¶
- template <typename ElementType>
classArray
: public FSTR::Object<Array<ElementType>, ElementType>¶Class to access an array of integral values stored in flash.
- Template Parameters
ElementType
:Public Functions
- ArrayPrinter<Array>
printer
() const¶Returns a printer object for this array.
- Note
- ElementType must be supported by Print
- size_t
printTo
(Print &p) const¶
- Iterator
begin
() const¶
- Iterator
end
() const¶
- size_t
length
() const¶Get the length of the content in elements.
- int
indexOf
(const ValueType &value) const¶
- ElementType
valueAt
(unsigned index) const¶
- ElementType
operator[]
(unsigned index) const¶Array operator[].
- size_t
elementSize
() const¶
- const ElementType *
data
() const¶
- size_t
read
(size_t index, ElementType *buffer, size_t count) const¶Read content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
read
(size_t offset, void *buffer, size_t count) const¶Read contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t index, ElementType *buffer, size_t count) const¶Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) const¶Read contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
size
() const¶Get the object data size in bytes.
- Note
- Always an integer multiple of 4 bytes
- template <class ObjectType>
constexpr const ObjectType &as
() const¶Cast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- bool
isCopy
() const¶Public Members
- uint32_t
flashLength_
¶Tables¶ Introduction¶ Simple tables can be implemented using Arrays, like this:
struct TableRow { float columns[3]; int operator[](size_t index) const { return columns[index]; } }; DEFINE_FSTR_ARRAY(table, TableRow, {0.1, 0.2, 0.3}, {0.6, 0.7, 0.8} ); for(auto row: table) { Serial.printf("%f, %f, %f\n", row[0], row[1], row[2]); }Each row is a fixed size. The
FSTR::TableRow
class template is provided to simplify this:#include <FlashString/Table.hpp> using FloatRow = FSTR::TableRow<float, 3>; DEFINE_FSTR_ARRAY(table, FloatRow, {0.1, 0.2, 0.3}, {0.6, 0.7, 0.8} ); table.printTo(Serial); table.println();If you want to create a table with rows of different sizes or types, use a Vector.
Class Template¶
- template <typename ElementType, size_t Columns>
classTableRow
¶Class template to define the row of a table.
Use with an
Array Object to construct simple tables. Methods provide Object-like access.
- Template Parameters
ElementType
:Columns
: Number of columns in the tablePublic Functions
- ElementType
operator[]
(size_t index) const¶Array operator.
- Parameters
index
:- Return Value
ElementType
:
- size_t
length
() const¶Get number of columns.
- Return Value
size_t
:Public Members
- template<>
ElementTypevalues
[Columns
]¶Vectors¶ Introduction¶ A
FSTR::Vector
is an array of Object pointers:struct Vector<ObjectType> { FSTR::Object object; ObjectType* entries[]; };A key use for this is the construction of string tables.
Defining Vectors¶ Inline Strings are not supported, so the content has to be defined first:
DEFINE_FSTR_LOCAL(str1, "Test string #1"); DEFINE_FSTR_LOCAL(str2, "Test string #2"); IMPORT_FSTR_LOCAL(str3, PROJECT_DIR "/files/somedata.json");Now we can define the Vector:
#include <FlashString/Vector.hpp> DEFINE_FSTR_VECTOR(myTable, FlashString, &str1, &str2, nullptr, &str3 );Note the use of
nullptr
to indicate an invalid vector entry, as distinct from an empty String.Using Vectors¶ Now we can access the data using Vector methods:
debugf("table.length() = %u", table.length()); debugf("fstr1 = '%s'", String(table[0]).c_str()); debugf("fstr2.length() = %u", table[1].length()); debugf("fstr3.length() = %u", table[2].length());You can share Vectors between translation units by declaring it in a header:
DECLARE_FSTR_VECTOR(table);To search a Vector:
int i = table.indexOf("TEST STRING #1");Note
By default, searches in Vector<String> are not case-sensitive.
The
indexOf
method has an extraignoreCase
parameter, which defaults totrue
.Structure¶ The above example generates a structure like this:
const struct { ObjectBase object; String* entries[4]; } __fstr__myTable PROGMEM = { {16}, &str1, &str2, nullptr, &str3, }; const Vector<String>& myTable PROGMEM = __fstr__myTable.as<Vector<String>>();Note:
FSTR::
namespace qualifier omitted for clarity.Macros¶
DECLARE_FSTR_VECTOR
(name, ObjectType)¶Declare a global Vector& reference.
- Note
- Use
DEFINE_VECTOR
to instantiate the global Object- Parameters
name
:ObjectType
:
DEFINE_FSTR_VECTOR
(name, ObjectType, ...)¶Define a Vector Object with global reference.
- Note
- Size will be calculated
- Parameters
name
: Name of Vector& reference to defineObjectType
:...
: List of ObjectType* pointers
DEFINE_FSTR_VECTOR_LOCAL
(name, ObjectType, ...)¶Like DEFINE_FSTR_VECTOR except reference is declared static constexpr.
DEFINE_FSTR_VECTOR_SIZED
(name, ObjectType, size, ...)¶Define a Vector Object with global reference, specifying the number of elements.
- Note
- Use in situations where the array size cannot be automatically calculated
- Parameters
name
: Name of Vector& reference to defineObjectType
:size
: Number of elements...
: List of ObjectType* pointers
DEFINE_FSTR_VECTOR_SIZED_LOCAL
(name, ObjectType, size, ...)¶Like DEFINE_FSTR_VECTOR_SIZED except reference is declared static constexpr.
DEFINE_FSTR_VECTOR_DATA
(name, ObjectType, ...)¶Define a Vector data structure.
- Note
- Size will be calculated
- Parameters
name
: Name of data structureObjectType
:...
: List of ObjectType* pointers
DEFINE_FSTR_VECTOR_DATA_SIZED
(name, ObjectType, size, ...)¶Define a Vector data structure and specify the number of elements.
- Note
- Use in situations where the array size cannot be automatically calculated
- Parameters
name
: Name of data structureObjectType
:size
: Number of elements...
: List of ObjectType* pointersClass Template¶
- template <class ObjectType>
classVector
: public FSTR::Object<Vector<ObjectType>, ObjectType *>¶Class to access a Vector of objects stored in flash.
- Template Parameters
ObjectType
:Public Functions
- template <typename ValueType, typename T = ObjectType>
std::enable_if<std::is_same<T, String>::value, int>::typeindexOf
(const ValueType &value, bool ignoreCase = true) const¶
- const ObjectType &
valueAt
(unsigned index) const¶
- const ObjectType &
operator[]
(unsigned index) const¶
- size_t
printTo
(Print &p) const¶
- Iterator
begin
() const
- Iterator
end
() const
- size_t
length
() constGet the length of the content in elements.
- int
indexOf
(const ValueType &value) const
- size_t
elementSize
() const
- const ObjectType **
data
() const
- size_t
read
(size_t index, ObjectType **buffer, size_t count) const¶Read content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
read
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t index, ObjectType **buffer, size_t count) const¶Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
size
() constGet the object data size in bytes.
- Note
- Always an integer multiple of 4 bytes
- template <class ObjectType>
constexpr const ObjectType &as
() constCast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- bool
isCopy
() constPublic Members
- uint32_t
flashLength_
Public Static Functions
- static const Vector<ObjectType> &
empty
()Return an empty object which evaluates to null.
Maps¶ Introduction¶ A
FSTR::Map
is analogous to the WiringHashMap
class, allowing content to be indexed using a key value.The Map contains an array of
FSTR::MapPair
structures:struct MapPair<KeyType, ContentType> { KeyType key_; ContentType* content_; };
KeyType
can be any simple type such aschar
,int
,float
,enum
etc. It may also be aString
Object (or, more precisely,String*
).
ContentType
can be any Object type (String, Array, Vector or Map). This allows hierarchical structures to be created.Example: int ⇒ String¶ Here’s a basic example using integer keys:
#include <FlashString/Map.hpp> IMPORT_FSTR_LOCAL(content1, PROJECT_DIR "/files/index.html"); IMPORT_FSTR_LOCAL(content2, PROJECT_DIR "/files/favicon.html"); DEFINE_FSTR_MAP(intmap, int, FSTR::String, {35, &content1}, {180, &content2} );You should generally use
IMPORT_FSTR_LOCAL()
when referencing imported objects. If you need global access to imported data as well, then useIMPORT_FSTR()
.Note
Older toolchains (generally GCC earlier than version 6) will fail to compile with error: the value of ‘FS_content1’ is not usable in a constant expression.
You can work around this as follows:
IMPORT_FSTR(content1, PROJECT_DIR "/files/index.html"); // Make this a global reference IMPORT_FSTR_LOCAL(content2, PROJECT_DIR "/files/favicon.html"); DEFINE_FSTR_MAP(intmap, int, FSTR::String, {35, &FSTR_DATA_NAME(FS_content1).as<FSTR::String>()}, // Cast the actual content {180, &content2} );We can now do this:
void printValue(int key) { auto value = intmap[key]; if(value) { Serial.printf("Found '%u' in map, containing %u chars\n", value.key(), value.content().length()); Serial.println(value.printer()); } else { Serial.printf("Couldn't find '%u' in map\n", key); } }Example: String ⇒ String¶ Both the key and the content are stored as Strings:
#include <FlashString/Map.hpp> DEFINE_FSTR_LOCAL(key1, "index.html"); DEFINE_FSTR_LOCAL(key2, "favicon.ico"); IMPORT_FSTR_LOCAL(content1, PROJECT_DIR "/files/index.html"); IMPORT_FSTR_LOCAL(content2, PROJECT_DIR "/files/favicon.html"); DEFINE_FSTR_MAP(fileMap, FlashString, FlashString, {&key1, &content1}, {&key2, &content2}, );We can now do this:
void onFile(HttpRequest& request, HttpResponse& response) { String fileName = request.uri.getRelativePath(); auto& value = fileMap[fileName]; if(value) { // Found Serial.printf("Found '%s' in fileMap\n", String(value.key()).c_str()); auto stream = new FlashMemoryStream(value); response.sendDataStream(stream, ContentType::fromFullFileName(fileName)); } else { Serial.printf("File '%s' not found\n", fileName.c_str()); } }Note
As with
Vector<String>
,Map<String, ...>
lookups are by default case-insensitive.If you require a case-sensitive lookup, use the
indexOf
method withignoreCase = false
.Structure¶ The macro in the first example above produces a structure like this:
constexpr const struct { ObjectBase object; MapPair<int, String> data[2]; } __fstr__intmap PROGMEM = { {16}, {35, &content1}, {180, &content2}, }; const Map<int, String>& intmap = __fstr__intmap.object.as<Map<int, String>>();Note:
FSTR::
namespace qualifier omitted for clarity.Usually, each MapPair is 8 bytes, but if the key is a double or int64 it would be 12 bytes.
Macros¶
DEFINE_FSTR_MAP
(name, KeyType, ContentType, ...)¶
DEFINE_FSTR_MAP_LOCAL
(name, KeyType, ContentType, ...)¶Like DEFINE_FSTR_MAP except reference is declared static constexpr.
DEFINE_FSTR_MAP_SIZED
(name, KeyType, ContentType, size, ...)¶
DEFINE_FSTR_MAP_SIZED_LOCAL
(name, KeyType, ContentType, size, ...)¶Like DEFINE_FSTR_MAP_SIZED except reference is declared static.
DEFINE_FSTR_MAP_DATA
(name, KeyType, ContentType, ...)¶Define a Map data structure.
- Note
- Size will be calculated
- Parameters
name
: Name of data structureKeyType
: Integral type to use for keyContentType
: Object type to declare for content...
: List of MapPair definitions { key, &content }
DEFINE_FSTR_MAP_DATA_SIZED
(name, KeyType, ContentType, size, ...)¶Define a Map data structure, specifying the number of elements.
- Parameters
name
: Name of data structureKeyType
: Integral type to use for keyContentType
: Object type to declare for contentsize
: Number of elements...
: List of MapPair definitions { key, &content }
- const Pair
FSTR::Map
::
valueAt
(unsigned index) const¶Get a map entry by index, if it exists.
- Note
- Result validity can be checked using if()
- template <typename TRefKey, typename T = KeyType>
std::enable_if<!std::is_class<T>::value, int>::typeFSTR::Map
::
indexOf
(const TRefKey &key) const¶Lookup an integral key and return the index.
- Parameters
key
: Key to locate, must be compatible with KeyType for equality comparison- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey, typename T = KeyType>
std::enable_if<std::is_same<T, String>::value, int>::typeFSTR::Map
::
indexOf
(const TRefKey &key, bool ignoreCase = true) const¶Lookup a String key and return the index.
- Parameters
key
:ignoreCase
: Whether search is case-sensitive (default: true)- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey>
const PairFSTR::Map
::
operator[]
(const TRefKey &key) const¶Lookup a key and return the entry, if found.
- Note
- Result validity can be checked using if()
- Parameters
key
:
- MapPrinter<Map>
FSTR::Map
::
printer
() const¶Returns a printer object for this array.
- Note
- ElementType must be supported by Print
DECLARE_FSTR_MAP
(name, KeyType, ContentType)¶Declare a global Map& reference.
- Note
- Use DEFINE_FSTR_MAP to instantiate the global object
- Parameters
name
:KeyType
: Integral type to use for keyContentType
: Object type to declare for content
- template <typename KeyType, class ContentType, class Pair = MapPair<KeyType, ContentType>>
classMap
: public FSTR::Object<Map<KeyType, ContentType>, Pair>¶- #include <Map.hpp>
Class template to access an associative map.
- Template Parameters
KeyType
:ContentType
:Public Types
- template<>
usingIterator
= ObjectIterator<Map<KeyType, ContentType>, Pair>¶Public Functions
- const Pair
valueAt
(unsigned index) constGet a map entry by index, if it exists.
- Note
- Result validity can be checked using if()
- template <typename TRefKey, typename T = KeyType>
std::enable_if<!std::is_class<T>::value, int>::typeindexOf
(const TRefKey &key) constLookup an integral key and return the index.
- Parameters
key
: Key to locate, must be compatible with KeyType for equality comparison- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey, typename T = KeyType>
std::enable_if<std::is_same<T, String>::value, int>::typeindexOf
(const TRefKey &key, bool ignoreCase = true) constLookup a String key and return the index.
- Parameters
key
:ignoreCase
: Whether search is case-sensitive (default: true)- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey>
const Pairoperator[]
(const TRefKey &key) constLookup a key and return the entry, if found.
- Note
- Result validity can be checked using if()
- Parameters
key
:
- MapPrinter<Map>
printer
() constReturns a printer object for this array.
- Note
- ElementType must be supported by Print
- size_t
printTo
(Print &p) const
- Iterator
begin
() const
- Iterator
end
() const
- size_t
length
() constGet the length of the content in elements.
- int
indexOf
(const ValueType &value) const
- Pair
operator[]
(unsigned index) constArray operator[].
- size_t
elementSize
() const
- const Pair *
data
() const
- size_t
read
(size_t index, Pair *buffer, size_t count) const¶Read content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
read
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t index, Pair *buffer, size_t count) const¶Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
size
() constGet the object data size in bytes.
- Note
- Always an integer multiple of 4 bytes
- template <class ObjectType>
constexpr const ObjectType &as
() constCast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- bool
isCopy
() constPublic Members
- uint32_t
flashLength_
Public Static Functions
- static const Map<KeyType, ContentType> &
empty
()Return an empty object which evaluates to null.
- template <typename KeyType, class ContentType>
classMapPair
¶- #include <MapPair.hpp>
describes a pair mapping key => data for a specified key type
- Template Parameters
KeyType
: Integral, floating point, enum or StringContentType
: Object type to use for contentPublic Types
- template<>
typedef void (MapPair
::*IfHelperType
)() const¶Public Functions
- void
IfHelper
() const¶
operator IfHelperType
() const¶Provides bool() operator to determine if Pair is valid.
- template <typename T = KeyType>
std::enable_if<!std::is_class<T>::value, KeyType>::typekey
() const¶Get the key (non-class key types)
- template <typename T = KeyType>
std::enable_if<std::is_same<T, String>::value, const KeyType&>::typekey
() constGet the key (String key type)
- const ContentType &
content
() const¶Accessor to get a reference to the content.
operator const ContentType&
() const¶
operator WString
() const¶
- size_t
printTo
(Print &p) const¶Class Templates¶
- template <typename KeyType, class ContentType, class Pair = MapPair<KeyType, ContentType>>
classMap
: public FSTR::Object<Map<KeyType, ContentType>, Pair>Class template to access an associative map.
- Template Parameters
KeyType
:ContentType
:Public Types
- template<>
usingIterator
= ObjectIterator<Map<KeyType, ContentType>, Pair>Public Functions
- const Pair
valueAt
(unsigned index) constGet a map entry by index, if it exists.
- Note
- Result validity can be checked using if()
- template <typename TRefKey, typename T = KeyType>
std::enable_if<!std::is_class<T>::value, int>::typeindexOf
(const TRefKey &key) constLookup an integral key and return the index.
- Parameters
key
: Key to locate, must be compatible with KeyType for equality comparison- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey, typename T = KeyType>
std::enable_if<std::is_same<T, String>::value, int>::typeindexOf
(const TRefKey &key, bool ignoreCase = true) constLookup a String key and return the index.
- Parameters
key
:ignoreCase
: Whether search is case-sensitive (default: true)- Return Value
int
: If key isn’t found, return -1
- template <typename TRefKey>
const Pairoperator[]
(const TRefKey &key) constLookup a key and return the entry, if found.
- Note
- Result validity can be checked using if()
- Parameters
key
:
- MapPrinter<Map>
printer
() constReturns a printer object for this array.
- Note
- ElementType must be supported by Print
- size_t
printTo
(Print &p) const
- Iterator
begin
() const
- Iterator
end
() const
- size_t
length
() constGet the length of the content in elements.
- int
indexOf
(const ValueType &value) const
- Pair
operator[]
(unsigned index) constArray operator[].
- size_t
elementSize
() const
- const Pair *
data
() const
- size_t
read
(size_t index, Pair *buffer, size_t count) constRead content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
read
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
readFlash
(size_t index, Pair *buffer, size_t count) constRead content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read- Return Value
size_t
: Number of elements actually read
- size_t
readFlash
(size_t offset, void *buffer, size_t count) constRead contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.
- See
- See also
FlashMemoryStream
class.- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read- Return Value
size_t
: Number of bytes actually read
- size_t
size
() constGet the object data size in bytes.
- Note
- Always an integer multiple of 4 bytes
- template <class ObjectType>
constexpr const ObjectType &as
() constCast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
- bool
isCopy
() constPublic Members
- uint32_t
flashLength_
Public Static Functions
- static const Map<KeyType, ContentType> &
empty
()Return an empty object which evaluates to null.
- template <typename KeyType, class ContentType>
classMapPair
describes a pair mapping key => data for a specified key type
- Template Parameters
KeyType
: Integral, floating point, enum or StringContentType
: Object type to use for contentPublic Types
- template<>
typedef void (MapPair
::*IfHelperType
)() constPublic Functions
- void
IfHelper
() const
operator IfHelperType
() constProvides bool() operator to determine if Pair is valid.
- template <typename T = KeyType>
std::enable_if<!std::is_class<T>::value, KeyType>::typekey
() constGet the key (non-class key types)
- template <typename T = KeyType>
std::enable_if<std::is_same<T, String>::value, const KeyType&>::typekey
() constGet the key (String key type)
- const ContentType &
content
() constAccessor to get a reference to the content.
operator const ContentType&
() const
operator WString
() const
- size_t
printTo
(Print &p) constPublic Static Functions
- static const MapPair
empty
()Get an empty Pair object, identifies as invalid when lookup fails.
Streams¶
- class
FSTR
::
Stream
: public IDataSourceStream¶Alias:
FlashMemoryStream
This is a Sming
IDataSourceStream
descendant which you can use to stream the contents of any FlashString object. It’s especially useful when used in conjuction withIMPORT_FSTR
:IMPORT_FSTR(myLargeFile, PROJECT_DIR "/files/lots-of-stuff.txt"); FSTR::Stream fs(myLargeFile); Serial.println(myLargefile);Because the data is read in sections, it’s not limited by available RAM.
Note
Unless you need
myLargeFile
to be a global symbol, you’ll generally want to useIMPORT_FSTR_LOCAL()
.Like a
FileStream
, you can also seek randomly within aFlashMemoryStream
, so you can use it as the basis for an elementary read-only filesystem.See Maps for a more useful example.
- class
FSTR
::
TemplateStream
: public TemplateStream¶Alias:
TemplateFlashMemoryStream
Standard templating stream for tag replacement.
Utilities¶ Importing files¶ For String and Array objects you can import data directly from a file using
IMPORT_FSTR()
orIMPORT_FSTR_ARRAY()
. For example:IMPORT_FSTR(myData, PROJECT_DIR "/files/myData.bin");This defines a C++ reference to the data called
myData
so it can be referred to usingDECLARE_FSTR()
if required.Attention
File paths must be absolute or the compiler won’t be able to locate it reliably.
Sming provides
PROJECT_DIR
andCOMPONENT_PATH
to help with this.Note
A corresponding C symbol will also be defined, based on the provided name, to provide linkage with the imported data.
You generally shouldn’t have an issue with this as the symbols are restricted to file scope, but it is something to be aware of.
One use for imported files is to serve content via HTTP, like this:
void onFile(HttpRequest& request, HttpResponse& response) { Serial.printf("myData is %u bytes long\n", myData.length()); auto fs = new FSTR::Stream(myData); response.sendDataStream(fs); }Therefore files can be bound into the firmware and accessed without requiring a filing system. This idea is extended further using Maps.
Custom Imports¶ Use
IMPORT_FSTR_DATA()
to import the contents of a file without defining any C/C++ variable:IMPORT_FSTR_DATA(myCustomData, PROJECT_DIR "/files/data.bin");You’ll need to define an appropriate symbol:
struct MyCustomStruct { uint32_t length; char name[12]; char description[20]; uint8_t data[1024]; }; extern "C" const MyCustomStruct myCustomData;You’ll still have to consider how the data is accessed. If it’s small and un-complicated you can just copy it into RAM:
MyCustomStruct buf; memcpy_P(&buf, &myCustomData, sizeof(buf));Custom Objects¶ A better way to handle large, complex structures is to define a custom Object to handle it. You can find an example of how to do this in
test/app/custom.cpp
, which does this:
Define
MyCustomStruct
:struct MyCustomStruct { FSTR::ObjectBase object; char name[12]; char description[20]; FSTR::ObjectBase dataArray; };Define a base object type (
CustomObject
) using theFSTR::Object
class template. This determines the underlying element type, generallychar
oruint8_t
are most useful.Derive an Object class (
MyCustomObject
) to encapsulate access toMyCustomStruct
.Use the
IMPORT_FSTR_OBJECT()
macro to import the custom data and define a global reference (customObject
) of typeMyCustomObject&
.Use
DECLARE_FSTR_OBJECT()
macro to declare the reference in a header.More complex examples may involve multiple custom Object types.
API Reference¶
DECL
(t)¶Wrap a type declaration so it can be passed with commas in it.
Example:
template <typename ElementType, size_t Columns> struct MultiRow { ElementType values[Columns]; }These fail:
DECLARE_FSTR_ARRAY(myArray, MultiRow<double, 3>); DECLARE_FSTR_ARRAY(myArray, (MultiRow<double, 3>));Use DECL like this:
DECLARE_FSTR_ARRAY(myArray, DECL((MultiRow<double, 3>)) );Although for this example we should probably do this:
using MultiRow_double_3 = MultiRow<double, 3>; DECLARE_FSTR_ARRAY(myArray, MultiRow_double_3);
IMPORT_FSTR_DATA
(name, file)¶Link the contents of a file.
This provides a more efficient way to read constant (read-only) file data. The file content is bound into firmware image at link time.
We need inline assembler’s
.incbin
instruction to actually import the data. We use a macro STR() so that if required the name can be resolved from a#defined
value.Use PROJECT_DIR to locate files in your project’s source tree:
IMPORT_FSTR_DATA(myFlashData, PROJECT_DIR "/files/my_flash_file.txt");Use COMPONENT_PATH within a component.
No C/C++ symbol is declared, this is type-dependent and must be done separately:
extern "C" FSTR::String myFlashData;If the symbol is not referenced the content will be discarded by the linker.
STR
(x)¶
XSTR
(x)¶
IROM_SECTION
¶Sming Integration¶ Sming provides several aliases to provide compatibility with existing code:
FlashString
->FSTR::String
FlashMemoryStream
->FSTR::Stream
TemplateFlashMemoryStream
->FSTR::TemplateStream
Other pages¶ Upgrade notes¶ Version 1.0¶ FlashString was first introduced in Sming 3.7.0 on 17 November 2018, as a single file in the Wiring directory. Other than bugfixes and Host Emulator support it hasn’t had any significant updates.
Version 2.0¶ This library was introduced to Sming in version 4.0.1. If you are migrating from Sming 3.7.0 or later and have used FlashString in your projects, some minor changes may be necessary.
FlashString¶ This has been moved inside the
FSTR
namespace and renamed toString
.FlashString has been retained as an alias for convenience to avoid ambiguity when used with Wiring String.
FlashString::isEqual()
has been renamed toequal()
for consistency with Wiring String.Tables¶ Table support has been improved and formalised using the
Vector
class. Previously:DEFINE_FSTR_LOCAL(fstr1, "Test string #1"); DEFINE_FSTR_LOCAL(fstr2, "Test string #2"); static FSTR_TABLE(table) = { FSTR_PTR(fstr1), FSTR_PTR(fstr2), }; Serial.println("FSTR tables[%u]\n", ARRAY_SIZE(table)); Serial.printf(" fstr1 = '%s'\n", String(*table[0]).c_str()); Serial.printf(" fstr1.length() = %u\n", table[0]->length());Now you can do this:
DEFINE_FSTR_LOCAL(str1, "Test string #1"); DEFINE_FSTR_LOCAL(str2, "Test string #2"); DEFINE_FSTR_VECTOR(table, FlashString, &str1, &str2); Serial.printf("FSTR table[%u]\n", table.length()); Serial.printf(" fstr1 = '%s'\n", String(table[0]).c_str()); Serial.printf(" fstr1.length() = %u\n", table[0].length());And perform lookups:
Serial.print(” indexOf(‘Test STRING #1’) = “); Serial.println(table.indexOf(“Test STRING #1”));Maps and other features¶ Associative maps have been added to support keys using a Flash String or an integral type. Content is typically a String, but can also be another Table or Map for building hierarchical structures.
Moving to class templates has added a lot of possibilities so I hope you have fun finding out what can be done with this library!
Suggestions for improvements and fixes always welcome :-)
Change Log¶ Sming 3.7.0¶ Here’s the PR summary from the original repository. The ‘pull-request’ links are rendered during Sming documentation build.
- Thu Sep 20 18:00:58 2018 Pull Request #1438
- Initial commit, the FlashString class plus macros
- Fri Oct 5 14:52:24 2018 Pull Request #1459
- Add FSTR_TABLE() macro to define a FlashString* pointer. Very basic table support so we can use it for looking up HTTP status strings, etc.
- Wed Oct 24 09:13:50 2018 Pull Request #1502
- Add streaming support - Add FlashMemoryStream class - Add FlashTemplateStream class - Add IMPORT_FSTR macro to bind a file into firmware image as FlashString object - Demonstrate usage using HttpServer_ConfigNetwork sample application. Note behaviour is unchanged, but settings.html is statically linked rather than using SPIFFS.
- Sat May 11 14:25:05 2019 Pull Request #1690
Mark const FlashString& references as PROGMEM. The compiler still stores a pointer to long address so it can use relative addressing modes, and it puts these in RAM unless you tell it not to.
Also added DEFINE_FSTR_LOCAL macro to allow correct use inside function definitions.
- Thu May 30 14:49:06 2019 Pull Request #1692
- Sming Host Emulator! The IMPORT_FSTR feature requires architecture-dependent compiler support, so a separate version was added to support WIN32. The standard version works as-is for Linux.
- Tue Jun 4 07:43:29 2019 Pull Request #1709
- Fix array bounds issue detected via GCC-8 on Host build (#1709)
- Mon Jul 8 07:21:58 2019 Pull Request #1757
- Bugfix: LOAD_FSTR() doesn’t NUL-terminate buffered string (#1757)
- Tue Jul 30 19:55:50 2019 Pull Request #1786
- Revise IMPORT_FSTR macro so the name can itself be #defined (#1786)
- Mon Oct 21 08:00:48 2019 Pull Request #1899
- Add optional len parameter to Flashstring::isEqual(const char*)
Sming 4.0.0¶ Sat Nov 2 13:01:20 2019
Sming version 4.0.0 is due for release next week, and FlashString has proven to be a useful addition to the toolkit. Time for an upgrade.
Sming 4.0.1¶ FlashString has been expanded from a single file into its own Component library to:
- Improve support for tables and add associative mapping
- Ensure each class has its own header file
- Add methods so users don’t need to muck about with memcpy_P, etc.
- Move some code out of the header into a separate .cpp source file
- Add proper documentation
- Make it easier to port to other frameworks (e.g. Arduino)
- Get it out of Wiring - doesn’t really belong there and certainly don’t want to clutter up that directory
- Improve maintainability
- Fix compatibility with ArduinoJson 6.13.0
Change summary:
- Move FlashString into a separate Component
- Add FlashString::read() and readFlash() methods
- Revise internals to be more consistent with naming
- Improve table handling using new Vector class
- Add associative mapping support with Map class
- Revise structures so it contains only the length, obtaining data position using pointer arithmetic. This fixes an error with GCC 8.2.0 which didn’t like accessing zero-length arrays.
- Use ObjectBase as the first element in a data structure to allow use of ‘safe’ static casting, handled using the as() method template
- Documentation!
Technobabble¶ Why not just use a wrapper class?¶ A wrapper class would require this:
const struct { ... } myFlashData PROGMEM = { ... }; void func() { FlashString fs(myFlashData); Serial.println(fs); }Easy enough, just create a wrapper every time you need to use the data.
It does get a bit clunky though when you have a lot of strings, lists of strings or where strings are used in several places.
How about global/static wrappers¶ Like this:
FlashString fs(myFlashData); void func() { Serial.println(fs); }Each wrapper uses 4 bytes of RAM. We also need to bear in mind that at startup objects are being initialised so we cannot necessarily guarantee that our FlashString wrappers have been created by the time they’re needed in other code. Result: hang/crash.
How about a macro to create the wrapper?¶ Something like this:
void func() { Serial.println(FS(myFlashData)); }To be honest, I hadn’t really considered that one, but it is worth exploring.
Can’t I put the wrapper in PROGMEM?¶ A wrapper requires a constructor, each of which needs an initialiser which gets called at startup.
Which is why FlashString isn’t a wrapper.
FlashStrings can be used anywhere you can use PROGMEM data, including globally initialised classes.
There is a disadvantage to this approach: You can’t make copies of FlashString objects. They must always be accessed as references or pointers.
Reasons to use FlashString¶
- Easy to use, treat like read-only
String
object- Use methods of FlashString instead of calls to memcpy_P, strcpy_P, etc.
- Blocks of data stored in flash can be passed around easily as the length is known
- Can be passed to functions instead of a String parameter, but without having to load it into RAM first
- Can be streamed directly using FlashMemoryStream
- Can be read randomly using FlashString::read()
- Aligned read and copy operations provide excellent performance
- Fast equality comparisons using length field to short-circuit comparison
- Data can be imported and linked directly into the program image from a local file, and accessed as a FlashString
- Custom structures can be defined and accessed as a FlashString
- Operates transparently with ArduinoJson (patched as from version 6.13.0)
Reasons not to use FlashString¶
Storing lots of small strings can be inefficient because of length and alignment, and because a NUL terminator is always appended by DEFINE_FSTR macros even though it’s not generally required. (This is because of how C requires string arrays to be declared.)
For example, “A” requires 8 bytes:
01 00 00 00 // Length 41 00 00 00 // "A\0" padded to word boundary However, this disadvantage can be overcome by storing such strings in a single block and accessing them using a :source:`Sming/Core/Data/CStringArray`.Note
Some counted string implementations store the length field at offset -4 so we always point to the actual data. In this case, that doesn’t offer any advantages as directly accessing the data is discouraged. Therefore, the length field always comes first.
Structure packing¶ When using Arrays with 64-bit types (including double) this is what we define:
struct { Array<int64_t> object; int64_t data[5]; } x;The object is a structure containing a single 32-bit value. Data arrays with uint8, uint16 or uint32 elements will start on the next 32-bit boundary, which is what we want.
With 64-bit values this is what the compiler does:
struct { Array<int64_t> object; uint32_t; // Packing added by compiler int64_t values[5]; } x;Which messes things up of course. Therefore Array classes and data are packed.
This is currently only an issue for Array types, but it also means that if you want to use Array with custom data structures then they should also be packed. That means you need to pay careful attention to member alignment and if packing is required then add it manually.
TODO List¶
- Missing methods
- Behaviour of String should reflect WString. Review and add any missing methods. Note that implementations for some are likely non-trivial since we cannot assume the content will fit into RAM.
- Benchmark filemap
Compare SPIFFS vs. file map:
- File access times
- File transfer times
- Implement stream operator <<
For simpler printing. This is a large architectural decision as Sming doesn’t have any of this, neither it seems does Arduino although some libraries add support for it.
The advantage over Print/Printable is that support can be added using template functions without modifying the classes themselves. Formatting statements can be inserted to customise the output.
- Formatted print output
We have separate argument for Array printing, but if we want to customise the text for each item as well then we have to use a regular for-loop and handle the separators as well.
Easiest is probably to just add format arguments to printTo() method.
Simple example: print an array of integers in HEX.
Need to consider with text escaping, probably leave that for external libraries.
- Multi-dimensional arrays
This could be an array of structs, so operator[] returns an entire row. As an optimisation, could we define additional accessors for nested levels?
Alternatives:
- Vector<Array>. Each array has to be defined before table.
- Specialize operator for 2x2 case as it’s quite common. e.g. SubElementType operator[](unsigned row, unsigned col) const
- Type Information
The flashLength_ value can be redefined like this:
length: 20; elementSize: 3; ///< Number of bytes in each element, less one type: 5; ///< Enumeration identifying element type Char = 0, Signed, Unsigned, Float, Enum, String, Array, Vector, Map, UserDefined = 16 // Start of user-defined types- Variant Object
- Interprets objects based on type information at runtime. This would allow complex data structures to be defined and used without knowing the object types. For example, translated JSON or XML documents.
- Translation tools
Say we wanted to access a read-only JSON document. How might we do that?
Easy. We write a Host application, so we can use all the existing libraries. Memory not an issue.
- Load the JSON document using ArduinoJson
- Serialize the document into FlashString-compatible declarations, producing a header file and a source file.
All we need to do then is write a JSON serializer to produce the appropriate structures.
About FlashString¶ FlashString was first introduced in Sming 3.7.0 on 17 November 2018.
I created it as a one-file solution to address these specific issues:
Regular Strings are really useful for passing around any kind of heap-allocated data, but it’s limited by available RAM.
The https://github.com/mikalhart/Flash library for Arduino provides a good approach, creating a wrapper class around the flash data. But I wanted it to be able to treat my FlashString classes as if they were just stored in flash so I wouldn’t have to wrap everything in a macro, like F() does.
Solution: The
FlashString
class.Using PROGMEM directly for data is cumbersome, slow and fraught with danger: It’s inherently unsafe because of the alignment issues. Some smart cookie came up with a compiler patch so it could insert the correct instructions and thus avoid alignment exceptions. However, that still causes execution of inefficient code since the hardware requires we perform aligned accesses. Generating the structures correctly in the first place felt the best way forward.
Solution:
DEFINE_FSTR()
Sharing flash data structures globally
Solution:
DECLARE_FSTR()
How to get content into PROGMEM without having to manually convert everything into C structures. One solution to this is using external tools but that complicates the build process and felt un-necessary.
Solution:
IMPORT_FSTR()
Relying on SPIFFS for serving fixed content is inefficient and problematic if/when the filesystem gets corrupted. I needed a solution which allowed large content to be served up without requiring a filesystem. The long term solution to this is, of course, a read-only filesystem but that is a complex thing indeed to do properly.
Solution:
FlashMemoryStream
Embedded microsystems¶ Back in the golden era of the Commodore 64 and the ZX81, embedded really meant something. You had to get your hands dirty and poke about in the hardware.
With modern hardware it’s cheating. I mean, how on earth can a basic Android ‘App’ weigh in at 20MB? I cannot get my head around that.
Of course, it’s just economics - far cheaper to throw lots of hardware resources at a problem than actually build it right in the first place. With all that memory kicking about it’s just pure laziness. IMHO. And of course that trend will continue because it feeds the hardware manufacturers in this disposable world.
Not a fan.
Anyway, before I lose the plot my point was that as the term ‘embedded’ has been hijacked it needs at least some qualification.
So I’ll say that this library, and my other work, is focused on embedded microsystems (EMS).
Why bother?¶ The main limitation of the ESP8266 is probably its RAM. So why not just use an ESP32? It’s got lots more RAM.
But it’s still a finite resource, and I can think of far better ways to use it than filling it up with constant data.
QED. RAM will always be a scarce commodity in an EMS.
Thanks¶ This library may have never been written if not for ArduinoJson. Of specific interest is the way class templates are used, the high quality of documentation, ease of use and test-driven approach. I have attempted to emulate those particular attributes here.
Special thanks to Slavey Karadzhov for his support and assistance over the past year mentoring me through the process of upgrading the Sming embedded framework. I’ve learned a phenomenal amount about modern development practices and it’s really given my coding practices a kick up the arse. Awesome :-)
References¶
- Source Code (submodule, may be patched).
Used by¶
- Sming (main) ,Component
AXTLS 8266¶
SSL support using the AXTLS library
References¶
- Source Code
- Cryptographic Support Component
Used by¶
- SSL: Secure Sockets Layer ,Component
Submodule: axtls-8266¶ This is an ESP8266 port of axTLS library, currently based on axTLS 2.1.4 (SVN version 277).
This library supports TLS 1.2, and the following cipher suites:
Cipher suite name (RFC) OpenSSL name Key exchange Encryption Hash TLS_RSA_WITH_AES_128_CBC_SHA AES128-SHA RSA AES-128 SHA-1 TLS_RSA_WITH_AES_256_CBC_SHA AES256-SHA RSA AES-256 SHA-1 TLS_RSA_WITH_AES_128_CBC_SHA256 AES128-SHA256 RSA AES-128 SHA-256 TLS_RSA_WITH_AES_256_CBC_SHA256 AES256-SHA256 RSA AES-256 SHA-256 Using the library¶ This is not a self-sufficient library. In addition to the standard C library functions, application has to provide the following functions:
ax_port_read ax_port_write ax_port_open ax_port_close ax_get_file phy_get_rand (provided by the IoT SDK) ets_printf (in ESP8266 ROM) ets_putc (in ESP8266 ROM)For use with LwIP raw TCP API, see compat/README.md
Building .. image:: https://travis-ci.org/igrr/axtls-8266.svg
target: https://travis-ci.org/igrr/axtls-8266 alt: Build status
To build, add xtensa toolchain to your path, and run
make
. The library will be built inbin/
directory.Cryptographic Support¶
Introduction¶ Contains basic cryptographic support classes for Sming.
This provides a strongly typed and flexible C++ library for commonly used routines, such as MD5, SHA hashes and HMAC.
Architecture-specific ROM or SDK routines are used where appropriate to reduce code size and improve performance.
The intention is that this library will provide the optimal implementations for any given architecture but maintain a consistent interface and allow it to be easily extended.
Hashes¶ You must #include the appropriate header for the hash family, for example:
#include <Crypto/Sha1.h>
All hash operations are then performed via the
Crypto::Sha1
class.Here’s a basic example showing how to calculate a SHA1 hash on a C string:
#include <Crypto/Sha1.h> void sha1Test(const char* buffer) { // Returns a Crypto::Sha1::Hash object auto hash = Crypto::Sha1().calculate(buffer, strlen(buffer)); Serial.print("SHA1: "); Serial.println(Crypto::toString(hash)); }If your data has multiple chunks, use the longer form:
#include <Crypto/Sha2.h> void sha256Test(const String& s1, const String& s2) { Crypto::Sha256 ctx; ctx.update(s1); ctx.update(s2); Serial.print("SHA256: "); Serial.println(Crypto::toString(ctx.getHash())); } sha256Test(F("This is some text to be hashed"), F("Hello"));Some hashes have additional optional parameters, for example:
#include <Crypto/Blake2s.h> void blake2sTest(const String& key, const String& content) { Crypto::Blake2s256 ctx(key); ctx.update(content); Serial.print("BLAKE2S-256: "); Serial.println(Crypto::toString(ctx.getHash())); }HMAC¶ The HMAC algorithm is commonly used for verifying both the integrity and authenticity of a message. It can be used with any defined hash, commonly MD5 or SHA1.
For example, an MD5 HMAC (as used with CRAM-MD5) may be done like this:
#include <Crypto/Md5.h> void printHmacMd5(const String& key, const String& data) { auto hash = Crypto::HmacMd5(key).calculate(data); Serial.print("HMAC.MD5 = "); Serial.println(Crypto::toString(hash)); }‘C’ API¶ The library also defines a standard ‘C’ api so it can be used from within existing code, such as AXTLS 8266 and Bear SSL. These definitions may be found in
Crypto/HashApi
.API Documentation¶
- namespace
Crypto
¶Typedefs
- using
Crypto::Blake2s = typedef HashContext<Blake2sEngine<hashsize> >
- using
Crypto::Blake2s256 = typedef Blake2s<32>
- using
Crypto::Blake2s128 = typedef Blake2s<16>
- using
Crypto::HmacBlake2s = typedef HmacContext<Blake2s<hashsize> >
- using
Crypto::HmacBlake2s256 = typedef HmacBlake2s<32>
- using
Crypto::HmacBlake2s128 = typedef HmacBlake2s<16>
- using
Crypto::Secret = typedef Blob
Identifies data which should be treated with care.
- using
Crypto::ByteArray = typedef std::array<uint8_t, size_>
Class template for fixed byte array.
- Note
- Until C++17 (and GCC > 5.5) inheriting from std::array<> breaks aggregate initialization.
- using
Crypto::Md5 = typedef HashContext<Md5Engine>
- using
Crypto::HmacMd5 = typedef HmacContext<Md5>
- using
Crypto::Sha1 = typedef HashContext<Sha1Engine>
- using
Crypto::HmacSha1 = typedef HmacContext<Sha1>
- using
Crypto::Sha224 = typedef HashContext<Sha224Engine>
- using
Crypto::Sha256 = typedef HashContext<Sha256Engine>
- using
Crypto::Sha384 = typedef HashContext<Sha384Engine>
- using
Crypto::Sha512 = typedef HashContext<Sha512Engine>
- using
Crypto::HmacSha224 = typedef HmacContext<Sha224>
- using
Crypto::HmacSha256 = typedef HmacContext<Sha256>
- using
Crypto::HmacSha384 = typedef HmacContext<Sha384>
- using
Crypto::HmacSha512 = typedef HmacContext<Sha512>
Functions
CRYPTO_HASH_ENGINE_STD
(Md5, md5, MD5_SIZE, MD5_STATESIZE, MD5_BLOCKSIZE)¶
CRYPTO_HASH_ENGINE_STD
(Sha1, sha1, SHA1_SIZE, SHA1_STATESIZE, SHA1_BLOCKSIZE)¶
CRYPTO_HASH_ENGINE_STD
(Sha224, sha224, SHA224_SIZE, SHA224_STATESIZE, SHA224_BLOCKSIZE)¶
CRYPTO_HASH_ENGINE_STD
(Sha256, sha256, SHA256_SIZE, SHA256_STATESIZE, SHA256_BLOCKSIZE)¶
CRYPTO_HASH_ENGINE_STD
(Sha384, sha384, SHA384_SIZE, SHA384_STATESIZE, SHA384_BLOCKSIZE)¶
CRYPTO_HASH_ENGINE_STD
(Sha512, sha512, SHA512_SIZE, SHA512_STATESIZE, SHA512_BLOCKSIZE)¶
- class
Blob
¶- #include <Blob.h>
Wraps a pointer to some data with size.
- template <class Engine_>
classHashContext
¶- #include <HashContext.h>
Class template for a Hash implementation ‘Context’.
- Template Parameters
Engine
: The HashEngine implementationSubclassed by OtaUpgrade::ChecksumVerifier
Update hash over a given block of data
- HashContext &
update
(const Blob &blob)¶
- HashContext &
update
(const FSTR::ObjectBase &obj)¶
- HashContext &
update
(const void *data, size_t size)¶
- template <size_t size_>
HashContext &update
(const ByteArray<size_> &array)¶Public Functions
- template <typename... EngineArgs>
HashContext
(EngineArgs&&... engineArgs)¶
- template <typename... EngineArgs>
HashContext &reset
(EngineArgs&&... engineArgs)¶Reset the context for a new calculation.
- template <typename... Ts>
Hashcalculate
(Ts&&... args)¶Calculate hash on some data.
- Parameters
args
: See update() methods- Return Value
Hash
:
- Hash
getHash
()¶Finalise and return the final hash value.
- Return Value
Hash
:
- State
getState
()¶Get intermediate hash state.
- Note
- This method is only required for core hashes, used by Bear SSL
- Parameters
state
: OUT: current state- Return Value
uint64_t
: Number of bytes processed so far
- void
setState
(const State &state)¶Restore intermediate hash state.
Parameter values obtained via previous getState() call
- Note
- This method is only required for core hashes, used by Bear SSL
- Parameters
state
:count
:
- struct
State
¶- #include <HashContext.h>
- template <class HashContext>
classHmacContext
¶- #include <HmacContext.h>
HMAC class template.
Implements the HMAC algorithm using any defined hash context
Public Types
- template<>
usingEngine
= typename HashContext::Engine¶
- template<>
usingHash
= typename HashContext::Hash¶Public Functions
HmacContext
(const Secret &key)¶Initialise HMAC context with key.
- HmacContext &
init
(const Secret &key)¶Initialise HMAC with key.
- Return Value
Reference
: to enable method chaining
- template <typename... Ts>
HmacContext &update
(Ts&&... args)¶Update HMAC with some message content.
- Parameters
args
: See HashContext update() methods- Return Value
Reference
: to enable method chaining
- Hash
getHash
()¶
- template <typename... Ts>
Hashcalculate
(Ts&&... args)¶Calculate hash for some data.
Use like this:
auto hash = Crypto::HmacMd5(mySecret).calculate(myData);
- Parameters
args
: See HashContext update() methods- Return Value
Hash
:Public Static Attributes
- constexpr size_t
blocksize
= Engine::blocksize¶References¶ Used by¶
- AXTLS 8266 ,Component
- SSL: Secure Sockets Layer ,Component
- libsodium Library
HTTP Parser¶
![]()
This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP applications. It does not make any syscalls nor allocations, it does not buffer data, it can be interrupted at anytime. Depending on your architecture, it only requires about 40 bytes of data per message stream (in a web server that is per connection).
Features:
- No dependencies
- Handles persistent streams (keep-alive).
- Decodes chunked encoding.
- Upgrade support
- Defends against buffer overflow attacks.
The parser extracts the following information from HTTP messages:
- Header fields and values
- Content-Length
- Request method
- Response status code
- Transfer-Encoding
- HTTP version
- Request URL
- Message body
Usage¶ One
http_parser
object is used per TCP connection. Initialize the struct usinghttp_parser_init()
and set the callbacks. That might look something like this for a request parser:http_parser_settings settings; settings.on_url = my_url_callback; settings.on_header_field = my_header_field_callback; /* ... */ http_parser *parser = malloc(sizeof(http_parser)); http_parser_init(parser, HTTP_REQUEST); parser->data = my_socket;When data is received on the socket execute the parser and check for errors.
size_t len = 80*1024, nparsed; char buf[len]; ssize_t recved; recved = recv(fd, buf, len, 0); if (recved < 0) { /* Handle error. */ } /* Start up / continue the parser. * Note we pass recved==0 to signal that EOF has been received. */ nparsed = http_parser_execute(parser, &settings, buf, recved); if (parser->upgrade) { /* handle new protocol */ } else if (nparsed != recved) { /* Handle error. Usually just close the connection. */ }
http_parser
needs to know where the end of the stream is. For example, sometimes servers send responses without Content-Length and expect the client to consume input (for the body) until EOF. To tellhttp_parser
about EOF, give0
as the fourth parameter tohttp_parser_execute()
. Callbacks and errors can still be encountered during an EOF, so one must still be prepared to receive them.Scalar valued message information such as
status_code
,method
, and the HTTP version are stored in the parser structure. This data is only temporally stored inhttp_parser
and gets reset on each new message. If this information is needed later, copy it out of the structure during theheaders_complete
callback.The parser decodes the transfer-encoding for both requests and responses transparently. That is, a chunked encoding is decoded before being sent to the on_body callback.
The Special Problem of Upgrade¶
http_parser
supports upgrading the connection to a different protocol. An increasingly common example of this is the WebSocket protocol which sends a request likeGET /demo HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: example.com Origin: http://example.com WebSocket-Protocol: samplefollowed by non-HTTP data.
(See RFC6455 for more information the WebSocket protocol.)
To support this, the parser will treat this as a normal HTTP message without a body, issuing both on_headers_complete and on_message_complete callbacks. However http_parser_execute() will stop parsing at the end of the headers and return.
The user is expected to check if
parser->upgrade
has been set to 1 afterhttp_parser_execute()
returns. Non-HTTP data begins at the buffer supplied offset by the return value ofhttp_parser_execute()
.Callbacks¶ During the
http_parser_execute()
call, the callbacks set inhttp_parser_settings
will be executed. The parser maintains state and never looks behind, so buffering the data is not necessary. If you need to save certain data for later usage, you can do that from the callbacks.There are two types of callbacks:
- notification
typedef int (*http_cb) (http_parser*);
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
- data
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
Callbacks: (requests only) on_url,
(common) on_header_field, on_header_value, on_body;Callbacks must return 0 on success. Returning a non-zero value indicates error to the parser, making it exit immediately.
For cases where it is necessary to pass local information to/from a callback, the
http_parser
object’sdata
field can be used. An example of such a case is when using threads to handle a socket connection, parse a request, and then give a response over that socket. By instantiation of a thread-local struct containing relevant data (e.g. accepted socket, allocated memory for callbacks to write into, etc), a parser’s callbacks are able to communicate data between the scope of the thread and the scope of the callback in a threadsafe manner. This allowshttp_parser
to be used in multi-threaded contexts.Example:
typedef struct { socket_t sock; void* buffer; int buf_len; } custom_data_t; int my_url_callback(http_parser* parser, const char *at, size_t length) { /* access to thread local custom_data_t struct. Use this access save parsed data for later use into thread local buffer, or communicate over socket */ parser->data; ... return 0; } ... void http_parser_thread(socket_t sock) { int nparsed = 0; /* allocate memory for user data */ custom_data_t *my_data = malloc(sizeof(custom_data_t)); /* some information for use by callbacks. * achieves thread -> callback information flow */ my_data->sock = sock; /* instantiate a thread-local parser */ http_parser *parser = malloc(sizeof(http_parser)); http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ /* this custom data reference is accessible through the reference to the parser supplied to callback functions */ parser->data = my_data; http_parser_settings settings; /* set up callbacks */ settings.on_url = my_url_callback; /* execute parser */ nparsed = http_parser_execute(parser, &settings, buf, recved); ... /* parsed information copied from callback. can now perform action on data copied into thread-local memory from callbacks. achieves callback -> thread information flow */ my_data->buffer; ... }In case you parse HTTP message in chunks (i.e.
read()
request line from socket, parse, read half headers, parse, etc) your data callbacks may be called more than once.http_parser
guarantees that data pointer is only valid for the lifetime of callback. You can alsoread()
into a heap allocated buffer to avoid copying memory around if this fits your application.Reading headers may be a tricky task if you read/parse headers partially. Basically, you need to remember whether last header callback was field or value and apply the following logic:
(on_header_field and on_header_value shortened to on_h_*) ------------------------ ------------ -------------------------------------------- | State (prev. callback) | Callback | Description/action | ------------------------ ------------ -------------------------------------------- | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | | | | into it | ------------------------ ------------ -------------------------------------------- | value | on_h_field | New header started. | | | | Copy current name,value buffers to headers | | | | list and allocate new buffer for new name | ------------------------ ------------ -------------------------------------------- | field | on_h_field | Previous name continues. Reallocate name | | | | buffer and append callback data to it | ------------------------ ------------ -------------------------------------------- | field | on_h_value | Value for current header started. Allocate | | | | new buffer and copy callback data to it | ------------------------ ------------ -------------------------------------------- | value | on_h_value | Value continues. Reallocate value buffer | | | | and append callback data to it | ------------------------ ------------ --------------------------------------------Parsing URLs¶ A simplistic zero-copy URL parser is provided as
http_parser_parse_url()
. Users of this library may wish to use it to parse URLs constructed from consecutiveon_url
callbacks.See examples of reading in headers:
- partial example in C
- from http-parser tests in C
- from Node library in Javascript
References¶
- Source Code (submodule, may be patched).
Used by¶
- Sming (main) ,Component
b64: Base64 Encoding/Decoding Routines¶
Overview:¶ libb64 is a library of ANSI C routines for fast encoding/decoding data into and from a base64-encoded format. C++ wrappers are included, as well as the source code for standalone encoding and decoding executables.
base64 consists of ASCII text, and is therefore a useful encoding for storing binary data in a text file, such as xml, or sending binary data over text-only email.
References:¶
- Wikipedia article:
- http://en.wikipedia.org/wiki/Base64
- base64, another implementation of a commandline en/decoder:
- http://www.fourmilab.ch/webtools/base64/
Why?¶ I did this because I need an implementation of base64 encoding and decoding, without any licensing problems. Most OS implementations are released under either the GNU/GPL, or a BSD-variant, which is not what I require.
Also, the chance to actually use the co-routine implementation in code is rare, and its use here is fitting. I couldn’t pass up the chance. For more information on this technique, see “Coroutines in C”, by Simon Tatham, which can be found online here: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
So then, under which license do I release this code? On to the next section…
License:¶ This work is released under into the Public Domain. It basically boils down to this: I put this work in the public domain, and you can take it and do whatever you want with it.
An example of this “license” is the Creative Commons Public Domain License, a copy of which can be found in the LICENSE file, and also online at http://creativecommons.org/licenses/publicdomain/
Commandline Use:¶ There is a new executable available, it is simply called base64. It can encode and decode files, as instructed by the user.
To encode a file: $ ./base64 -e filea fileb fileb will now be the base64-encoded version of filea.
To decode a file: $ ./base64 -d fileb filec filec will now be identical to filea.
Programming:¶ Some C++ wrappers are provided as well, so you don’t have to get your hands dirty. Encoding from standard input to standard output is as simple as
#include <b64/encode.h> #include <iostream> int main() { base64::encoder E; E.encode(std::cin, std::cout); return 0; }Both standalone executables and a static library is provided in the package,
Example code:¶ The ‘examples’ directory contains some simple example C code, that demonstrates how to use the C interface of the library.
Implementation:¶ It is DAMN fast, if I may say so myself. The C code uses a little trick which has been used to implement coroutines, of which one can say that this implementation is an example.
(To see how the libb64 codebase compares with some other BASE64 implementations available, see the BENCHMARKS file)
The trick involves the fact that a switch-statement may legally cross into sub-blocks. A very thorough and enlightening essay on co-routines in C, using this method, can be found in the above mentioned “Coroutines in C”, by Simon Tatham: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
For example, an RLE decompressing routine, adapted from the article: 1 static int STATE = 0; 2 static int len, c; 3 switch (STATE) 4 { 5 while (1) 6 { 7 c = getchar(); 8 if (c == EOF) return EOF; 9 if (c == 0xFF) { 10 len = getchar(); 11 c = getchar(); 12 while (len–) 13 { 14 STATE = 0; 15 return c; 16 case 0: 17 } 18 } else 19 STATE = 1; 20 return c; 21 case 1: 22 } 23 } 24 }
As can be seen from this example, a coroutine depends on a state variable, which it sets directly before exiting (lines 14 and 119). The next time the routine is entered, the switch moves control to the specific point directly after the previous exit (lines 16 and 21).hands
(As an aside, in the mentioned article the combination of the top-level switch, the various setting of the state, the return of a value, and the labelling of the exit point is wrapped in #define macros, making the structure of the routine even clearer.)
The obvious problem with any such routine is the static keyword. Any static variables in a function spell doom for multithreaded applications. Also, in situations where this coroutine is used by more than one other coroutines, the consistency is disturbed.
What is needed is a structure for storing these variabled, which is passed to the routine seperately. This obviously breaks the modularity of the function, since now the caller has to worry about and care for the internal state of the routine (the callee). This allows for a fast, multithreading-enabled implementation, which may (obviously) be wrapped in a C++ object for ease of use.
The base64 encoding and decoding functionality in this package is implemented in exactly this way, providing both a high-speed high-maintanence C interface, and a wrapped C++ which is low-maintanence and only slightly less performant.
References¶ Used by¶
- Sming (main) ,Component
libyuarel¶
![]()
Very simple and well tested C library for parsing URLs with zero-copy and no mallocs. The library does not do any validation on the URL, neither before nor after it is parsed. The different parts are parsed by searching for special characters like
:
and/
. For a URL should be able to be parsed by yuarel, it has to be constructed in one of the following formats:Absolute URL: scheme “:” [ “//” ] [ username “:” password “@” ] host [ “:” port ] [ “/” ] [ path ] [ “?” query ] [ “#” fragment ]
Relative URL: path [ “?” query ] [ “#” fragment ]
Parts within
[
and]
are optional. A minimal URL could look like this:
a:b
or/
Due to the fact that the library isn’t copying any strings and instead points to the parts in the URL string, the first
/
in the path will be replaced with a null terminator. Therefore, the first slash will be missing in the path.To build¶ $ make && make check && sudo make installThe structs¶ The struct that holds the parsed URL looks like this:
struct yuarel { char *scheme; /* scheme, without ":" and "//" */ char *username; /* username, default: NULL */ char *password; /* password, default: NULL */ char *host; /* hostname or IP address */ int port; /* port, default: 0 */ char *path; /* path, without leading "/", default: NULL */ char *query; /* query, default: NULL */ char *fragment; /* fragment, default: NULL */ };The struct that holds a parsed query string parameter looks like this:
struct yuarel_param { char *key; char *val; };Library functions¶ Parse a URL to a struct¶ int yuarel_parse(struct yuarel *url, char *url_str)
struct yuarel *url
: a pointer to the struct where to store the parsed values.char *url_str
: a pointer to the url to be parsed (null terminated).Note that the url string will be modified by the function.
Returns 0 on success, otherwise -1.
Split a path into several strings¶ int yuarel_split_path(char *path, char **parts, int max_parts)No data is copied, the slashed are used as null terminators and then pointers to each path part will be stored in
parts
.
char *path
: the path to split. The string will be modified.char **parts
: a pointer to an array of(char *)
where to store the result.int max_parts
: max number of parts to parse.Note that the path string will be modified by the function.
Returns the number of parsed items. -1 on error.
Parse a query string¶ int yuarel_parse_query(char *query, char delimiter, struct yuarel_param *params, int max_params)
char *query
: the query string to parse. The string will be modified.char delimiter
: the character that separates the key/value pairs from eachother.struct yuarel_param *params
: an array of(struct yuarel_param)
where to store the result.int max_values
: max number of parameters to parse.The query string should be a null terminated string of parameters separated by a delimiter. Each parameter are checked for the equal sign character. If it appears in the parameter, it will be used as a null terminator and the part that comes after it will be the value of the parameter.
No data are copied, the equal sign and delimiters are used as null terminators and then pointers to each parameter key and value will be stored in the yuarel_param struct.
Note that the query string will be modified by the function.
Returns the number of parsed items. -1 on error.
How to use it:¶ Compile with
-lyuarel
.#include <stdlib.h> #include <stdio.h> #include <yuarel.h> int main(void) { int p; struct yuarel url; char *parts[3]; char url_string[] = "http://localhost:8989/path/to/test?query=yes#frag=1"; if (-1 == yuarel_parse(&url, url_string)) { fprintf(stderr, "Could not parse url!\n"); return 1; } printf("scheme:\t%s\n", url.scheme); printf("host:\t%s\n", url.host); printf("port:\t%d\n", url.port); printf("path:\t%s\n", url.path); printf("query:\t%s\n", url.query); printf("fragment:\t%s\n", url.fragment); if (3 != yuarel_split_path(url.path, parts, 3)) { fprintf(stderr, "Could not split path!\n"); return 1; } printf("path parts: %s, %s, %s\n", parts[0], parts[1], parts[2]); printf("Query string parameters:\n"); p = yuarel_parse_query(url.query, '&', params, 3); while (p-- > 0) { printf("\t%s: %s\n", params[p].key, params[p].val); } }References¶
- Source Code (submodule, may be patched).
Used by¶
- Sming (main) ,Component
malloc_count¶
This Component is a modified version of the original code, intended to provide basic heap monitoring for the Sming Host Emulator.
The following is the original README.
Introduction¶
malloc_count
provides a set of source code tools to measure the amount of allocated memory of a program at run-time. The code library provides facilities to
- measure the current and peak heap memory allocation, and
- write a memory profile for plotting, see the figure on the right.
- Furthermore, separate
stack_count
function can measure stack usage.The code tool works by intercepting the standard
malloc()
,free()
, etc functions. Thus no changes are necessary to the inspected source code.See http://panthema.net/2013/malloc_count for the current verison.
Intercepting Heap Allocation Functions¶ The source code of
malloc_count.[ch]
intercepts the standard heap allocation functionsmalloc()
,free()
,realloc()
andcalloc()
and adds simple counting statistics to each call. Thus the program must be relinked formalloc_count
to work. Each call tomalloc()
and others is passed on to lower levels, and the regularmalloc()
is used for heap allocation.Of course,
malloc_count
can also be used with C++ programs and maybe even script languages like Python and Perl, because thenew
operator and most script interpreters allocations all are based onmalloc
.The tools are usable under Linux and probably also with Cygwin and MinGW, as they too support the standard Linux dynamic link loading mechanisms.
Memory Profile and stack_count
¶The
malloc_count
source is accompanied by two further memory analysis tools:stack_count
and a C++ header calledmemprofile.h
.In
stack_count.[ch]
two simple functions are provided that can measure the maximum stack usage between two points in a program.Maybe the most useful application of
malloc_count
is to create a memory/heap profile of a program (while it is running). This profile can also be created using the well-known valgrind tool “massif”, however, massif is really slow. The overhead ofmalloc_count
is much smaller, and usingmemprofile.h
a statistic file can be produced, which is directly usable with Gnuplot.The source code archive contains two example applications: one which queries
malloc_count
for current heap usage, and a second which creates the memory profile in the figure on the right. See the STX B+ Tree library for another, more complex example of a memory profile.Downloads¶ See http://panthema.net/2013/malloc_count for the current verison.
The source code is published under the MIT License (MIT), which is also found in the header of all source files.
Short Usage Guide¶ Compile
malloc_count.c
and link it with your program. The source filemalloc_count.o
should be located towards the end of the.o
file sequence. You must also add “-ldl
” to the list of libraries.Run your program and observe that when terminating, it outputs a line like
malloc_count ### exiting, total: 12,582,912, peak: 4,194,304, current: 0If desired, increase verbosity
- by setting
log_operations = 1
at the top ofmalloc_count.c
and adaptinglog_operations_threshold
to output only large allocations, or- by including
malloc_count.h
in your program and using the user-functions define therein to output memory usage at specific checkpoints. See the directorytest-malloc_count/
in the source code for an example.Tip: Set the locale environment variable
LC_NUMERIC=en_GB
or similar to get comma-separation of thousands in the printed numbers.The directory
test-memprofile/
contains a simple program, which fills astd::vector
andstd::set
with integers. The memory usage of these containers is profiled using the facilities ofmemprofile.h
, which are described verbosely in the source.Thread Safety¶ The current statistic methods in
malloc_count.c
are not thread-safe. However, the general mechanism (as described below) is per-se thread-safe. The only non-safe parts are adding and subtracting from the counters ininc_count()
anddec_count()
.The
malloc_count.c
code contains a#define THREAD_SAFE_GCC_INTRINSICS
, which enables use of gcc’s intrinsics for atomic counting operations. If you use gcc, enable this option to make themalloc_count
tool thread-safe.The functions in
memprofile.h
are not thread-safe.stack_count
can also be used on local thread stacks.Technicalities of Intercepting libc
Function Calls¶The method used in
malloc_count
to hook the standard heap allocation calls is to provide a source file exporting the symbols “malloc
”, “free
”, etc. These override the libc symbols and thus the functions inmalloc_count
are used instead.However,
malloc_count
does not implement a heap allocator. It loads the symbols “malloc
”, “free
”, etc. directly using the dynamic link loader “dl
” from the chain of shared libraries. Calls to the overriding “malloc
” functions are forwarded to the usual libc allocator.To keep track of the size of each allocated memory area,
malloc_count
uses a trick: it prepends each allocation pointer with two additional bookkeeping variables: the allocation size and a sentinel value. Thus when allocating n bytes, in truth n + c bytes are requested from the libcmalloc()
to save the size (c is by default 16, but can be adapted to fix alignment problems). The sentinel only serves as a check that your program has not overwritten the size information.Closing Credits¶ The idea for this augmenting interception method is not my own, it was borrowed from Jeremy Kerr http://ozlabs.org/~jk/code/.
Written 2013-01-21, 2013-03-16, and 2014-09-10 by Timo Bingmann tb@panthema.net
References¶ Used by¶
- Heap ,Component
- SmingTest Library
- Basic SSL Sample
- RingTone Player Sample
mqtt-protocol-c¶
Zero-copy, interruptible MQTT protocol
parser
andserialiser
written in C. Based initially on Deoxxa’s code and extended to support full client and server parsing and serialization.Overview¶ mqtt-protocol-c is designed for use in resource-constrained environments. To that end, it avoids making any memory allocations or assumptions about the underlying system. It handles only the binary parsing/serialising part of the MQTT protocol, leaving all the logic and networking up to the user.
Examples¶ Take a look at
test_serialiser
andtest_parser
in the bin/test.c file.Copyright¶
- 2018 - present Slavey Karadzhov slav@attachix.com
- 2014 - Deoxxa Development
References¶
- Source Code (submodule, may be patched).
Used by¶
- Sming (main) ,Component
rBoot¶
Introduction¶ rBoot is a second-stage bootloader that allows booting application images from several pre-configured flash memory addresses, called “slots”. Sming supports up to three slots.
Sming uses rBoot exclusively because of its flexibility, reliability and ease of use.
Attention
Make sure that your slots do not extend beyond a 1MB boundary and do not overlap with each other, the file system (if enabled) or the RFcal/system parameters area! Sming currently has no means of detecting a misconfigured memory layout.
Slot 0¶ This is the default slot which is always used.
Slot 1¶
RBOOT_ROM1_ADDR
¶default: disabled
The start address of slot 1. If you don’t need it, leave unconfigured (empty).
If your application includes any kind of Over-the-Air (OTA) firmware update functionality, you will need a second memory slot to store the received update image while the update routines execute from the first slot.
Upon successful completion of the update, the second slot is activated, such that on next reset rBoot boots into the uploaded application. While now running from slot 1, the next update will be stored to slot 0 again, i.e. the roles of slot 0 and slot 1 are flipped with every update.
For devices with more than 1MB of flash memory, it is advisable to choose an address with the same offset within its 1MB block as
RBOOT_ROM0_ADDR
, e.g. 0x102000 for the default slot 0 address (0x2000). This way, the same application image can be used for both slots. See Single vs. Dual ROMs for further details.Slot 2 (GPIO slot)¶ rBoot supports booting into a third slot upon explicit user request, e.g. by pressing a button during reset/power up. This is especially useful for implementing some sort of recovery mechanism.
To enable slot 2, set these values:
RBOOT_GPIO_ENABLED
¶Disabled by default. Set to 1 to enable slot 2.
RBOOT_ROM2_ADDR
¶Address for slot 2
Note that this will only configure rBoot. Sming will not create an application image for slot 2. You can, however, use a second Sming project to build a recovery application image as follows:
- Create a new Sming project for your recovery application. This will be a simple single-slot project. Set
RBOOT_ROM0_ADDR
of the recovery project to the value ofRBOOT_ROM2_ADDR
of the main project.- Build and flash the recovery project as usual by typing
make flash
. This will install the recovery ROM (into slot 2 of the main project) and a temporary bootloader, which will be overwritten in the next step.- Go back to your main project. Build and flash it with
make flash
. This will install the main application (into slot 0) and the final bootloader. You are now all set for booting into the recovery image if the need arises.Automatically derived settings¶ The
RBOOT_BIG_FLASH
andRBOOT_TWO_ROMS
settings are now read-only as their values are derived automatically.In earlier versions of Sming these had to be set manually.
Big Flash Mode¶ The ESP8266 can map only 1MB of flash memory into its internal address space at a time. As you might expect, the first megabyte is mapped by default. This is fine if your image(s) reside(s) in this range. Otherwise, rBoot has to inject a piece of code into the application startup routine to set up the flash controller with the correct mapping.
RBOOT_BIG_FLASH
¶READONLY Set when
RBOOT_ROM0_ADDR
orRBOOT_ROM1_ADDR
>= 0x100000.See also Big flash support.
Single vs. Dual ROMs¶ Since every 1MB range of flash memory is mapped to an identical internal address range, the same ROM image can be used for slots 0 and 1 if (and only if!) both slots have the same address offsets within their 1MB blocks, i.e.
(RBOOT_ROM0_ADDR & 0xFFFFF) == (RBOOT_ROM1_ADDR & 0xFFFFF)
.Consequently, for such configurations, the Sming build system generates only one ROM image.
In all other cases, two distinct application images must be linked with different addresses for the ‘irom0_0_seg’ memory region. The Sming build system takes care of all the details, including linker script generation.
RBOOT_TWO_ROMS
¶READONLY Determines if rBoot needs to generate distinct firmware images.
Further Configuration Settings¶
RBOOT_SILENT
¶Default: 0 (verbose)
At system restart rBoot outputs debug information to the serial port. Set to 1 to disable.
RBOOT_LD_TEMPLATE
¶Path to the linker script template. The actual script is output to the application build directory (e.g.
rom0.ld
), replacing the irom0_0_seg entry according to the configured build settings.
RBOOT_ROM_0
¶Base name for firmware image #0. Default is
rom0
.
RBOOT_ROM_1
¶Base name for firmware image #1. Default is
rom1
.
ESPTOOL2
¶READONLY Defines the path to the esptool2 tool which rBoot uses to manipulate ROM images. Use
$(ESPTOOL2)
if you need it within your own projects.API Documentation¶ API Documentation¶ rboot-api.h¶ Functions
- rboot_config
rboot_get_config
(void)¶Read rBoot configuration from flash.
- Note
- Returns rboot_config (defined in rboot.h) allowing you to modify any values in it, including the ROM layout.
- Return Value
rboot_config
: Copy of the rBoot configuration
- bool
rboot_set_config
(rboot_config *conf)¶Write rBoot configuration to flash memory.
- Note
- Saves the rboot_config structure back to configuration sector (BOOT_CONFIG_SECTOR) of the flash, while maintaining the contents of the rest of the sector. You can use the rest of this sector for your app settings, as long as you protect this structure when you do so.
- Parameters
conf
: pointer to a rboot_config structure containing configuration to save- Return Value
bool
: True on success
- uint8_t
rboot_get_current_rom
(void)¶Get index of current ROM.
- Note
- Get the currently selected boot ROM (this will be the currently running ROM, as long as you haven’t changed it since boot or rBoot booted the rom in temporary boot mode, see rboot_get_last_boot_rom).
- Return Value
uint8_t
: Index of the current ROM
- bool
rboot_set_current_rom
(uint8_t rom)¶Set the index of current ROM.
- Note
- Set the current boot ROM, which will be used when next restarted.
- Note
- This function re-writes the whole configuration to flash memory (not just the current ROM index)
- Parameters
rom
: The index of the ROM to use on next boot- Return Value
bool
: True on success
- rboot_write_status
rboot_write_init
(uint32_t start_addr)¶Initialise flash write process.
- Note
- Call once before starting to pass data to write to flash memory with rboot_write_flash function. start_addr is the address on the SPI flash to write from. Returns a status structure which must be passed back on each write. The contents of the structure should not be modified by the calling code.
- Parameters
start_addr
: Address on the SPI flash to begin write to
- bool
rboot_write_end
(rboot_write_status *status)¶Complete flash write process.
- Note
- Call at the completion of flash writing. This ensures any outstanding bytes are written (if data so far hasn’t been a multiple of 4 bytes there will be a few bytes unwritten, until you call this function).
- Parameters
status
: Pointer to rboot_write_status structure defining the write status
- bool
rboot_write_flash
(rboot_write_status *status, uint8_t *data, uint16_t len)¶Write data to flash memory.
- Note
- Call repeatedly to write data to the flash, starting at the address specified on the prior call to rboot_write_init. Current write position is tracked automatically. This method is likely to be called each time a packet of OTA data is received over the network.
- Note
- Call rboot_write_init before calling this function to get the rboot_write_status structure
- Parameters
status
: Pointer to rboot_write_status structure defining the write statusdata
: Pointer to a block of uint8_t data elements to be written to flashlen
: Quantity of uint8_t data elements to write to flash
- struct
rboot_write_status
¶- #include <rboot-api.h>
Structure defining flash write status.
- Note
- The user application should not modify the contents of this structure.
- See
- rboot_write_flash
rboot.h¶ Defines
CHKSUM_INIT
¶
SECTOR_SIZE
¶
BOOT_CONFIG_SECTOR
¶
BOOT_CONFIG_MAGIC
¶
BOOT_CONFIG_VERSION
¶
MODE_STANDARD
¶
MODE_GPIO_ROM
¶
MODE_TEMP_ROM
¶
MODE_GPIO_ERASES_SDKCONFIG
¶
MODE_GPIO_SKIP
¶
RBOOT_RTC_MAGIC
¶
RBOOT_RTC_READ
¶
RBOOT_RTC_WRITE
¶
RBOOT_RTC_ADDR
¶
BOOT_GPIO_NUM
¶
MAX_ROMS
¶
- struct
rboot_config
¶- #include <rboot.h>
Structure containing rBoot configuration.
- Note
- ROM addresses must be multiples of 0x1000 (flash sector aligned). Without BOOT_BIG_FLASH only the first 8Mbit (1MB) of the chip will be memory mapped so ROM slots containing .irom0.text sections must remain below 0x100000. Slots beyond this will only be accessible via spi read calls, so use these for stored resources, not code. With BOOT_BIG_FLASH the flash will be mapped in chunks of 8MBit (1MB), so ROMs can be anywhere, but must not straddle two 8MBit (1MB) blocks.
Public Members
- uint8_t
magic
¶Our magic, identifies rBoot configuration - should be BOOT_CONFIG_MAGIC.
- uint8_t
version
¶Version of configuration structure - should be BOOT_CONFIG_VERSION.
- uint8_t
mode
¶Boot loader mode (MODE_STANDARD | MODE_GPIO_ROM | MODE_GPIO_SKIP)
- uint8_t
current_rom
¶Currently selected ROM (will be used for next standard boot)
- uint8_t
gpio_rom
¶ROM to use for GPIO boot (hardware switch) with mode set to MODE_GPIO_ROM.
- uint8_t
count
¶Quantity of ROMs available to boot.
- uint8_t
unused
[2]¶Padding (not used)
- uint32_t
roms
[MAX_ROMS
]¶Flash addresses of each ROM.
ESP8266 Cache_Read_Enable¶ 12th June 2015 Richard
Since I haven’t seen this documented anywhere, here is my attempt to explain the Cache_Read_Enable function. Valid values and what they do (at a register level) are from decompiling the code. The outcome of those values is based on my own experimentation so my descriptions and explanations may be silly but they currently fit the observed results.
void Cache_Read_Enable(uint8 odd_even, uint8 mb_count, unt8 no_idea);
- Valid values for odd_even
- 0 – clears bits 24 & 25 of control register 0x3FF0000C 1 – clears bit 24, sets bit 25 other – clears bit 25, sets bit 24
- Function of odd_even
- 0 – allows access to even numbered mb 1 – allow access to odd numbered mb other – appears to do the same as 1, there must be a difference but I haven’t worked out what it is
- Valid values for mb_count
- 0-7 – set bits 16, 17 & 18 of control register 0x3FF0000C
- Function of mb_count
- Which odd or even bank to map (according to odd_even option)
- e.g. mb_count = 0, odd_even = 0 -> map first 8Mbit of flash e.g. mb_count = 0, odd_even = 1 -> map second 8Mbit of flash e.g. mb_count = 1, odd_even = 0 -> map third 8Mbit of flash e.g. mb_count = 1, odd_even = 1 -> map fourth 8Mbit of flash
- Valid values for no_idea
- 0 – sets bit 3 of 0x3FF00024 1 – sets bit 26 of 0x3FF0000C and sets bits 3 & 4 of 0x3FF00024
- Function of no_idea
- The clue is in the name, I can’t work out what this does from my experiments, but the SDK always sets this to 1.
Source: https://richard.burtons.org/2015/06/12/esp8266-cache_read_enable/
13/11/2019 @author mikee47 UPDATE¶ Ref. RTOS SDK source
bootloader_support/bootloader_utility.c
, functionbootloader_utility_load_image()
:extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v); ... Cache_Read_Enable(map, 0, SOC_CACHE_SIZE);Where SOC_CACHE_SIZE is defined as:
#ifdef CONFIG_SOC_FULL_ICACHE #define SOC_CACHE_SIZE 1 // 32KB #else #define SOC_CACHE_SIZE 0 // 16KB #endifReferences¶ Used by¶
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Environment Variables¶ Submodule: rboot¶ rBoot - An open source boot loader for the ESP8266¶ by Richard A Burton, richardaburton@gmail.com http://richard.burtons.org/
rBoot is designed to be a flexible open source boot loader, a replacement for the binary blob supplied with the SDK. It has the following advantages over the Espressif loader:
- Open source (written in C).
- Supports up to 256 roms.
- Roms can be variable size.
- Able to test multiple roms to find a valid backup (without resetting).
- Flash layout can be changed on the fly (with care and appropriately linked rom images).
- GPIO support for rom selection.
- Wastes no stack space (SDK boot loader uses 144 bytes).
- Documented config structure to allow easy editing from user code.
- Can validate .irom0.text section with checksum.
- Temporary next-boot rom selection.
Limitations¶ The ESP8266 can only map 8Mbits (1MB) of flash to memory, but which 8Mbits to map is selectable. This allows individual roms to be up to 1MB in size, so long as they do not straddle an 8Mbit boundary on the flash. This means you could have four 1MB roms or 8 512KB roms on a 32Mbit flash (such as on the ESP-12), or a combination. Note, however, that you could not have, for example, a 512KB rom followed immediately by a 1MB rom because the 2nd rom would then straddle an 8MBit boundary. By default support for using more than the first 8Mbit of the flash is disabled, because it requires several steps to get it working. See below for instructions.
Building¶ A Makefile is included, which should work with the gcc xtensa cross compiler. There are two source files, the first is compiled and included as data in the second. When run this code is copied to memory and executed (there is a good reason for this, see my blog for an explanation). The make file will handle this for you, but you’ll need my esptool2 (see github).
To use the Makefile set
SDK_BASE
to point to the root of the Espressif SDK and either setXTENSA_BINDIR
to the gcc xtensa bin directory or include it in yourPATH
. These can be set as environment variables or by editing the Makefile.Two small assembler stub functions allow the bootloader to launch the user code without reserving any space on the stack (while the SDK boot loader uses 144 bytes). This compiles fine with GCC, but if you use another compiler and it will not compile/work for you then uncomment the
#define BOOT_NO_ASM
inrboot.h
to use a C version of these functions (this uses 32 bytes).Tested with SDK v2.2 and GCC v4.8.5.
Installation¶ Simply write rboot.bin to the first sector of the flash. Remember to set your flash size correctly with your chosen flash tool (e.g. for esptool.py use the
-fs
option). When run rBoot will create it’s own config at the start of sector two for a simple two rom system. You can can then write your two roms to flash addresses0x2000
and (half chip size +0x2000
). E.g. for 8Mbit flash:esptool.py write_flash -fs 8m 0x0000 rboot.bin 0x2000 user1.bin 0x82000 user2.bin
Note: your device may need other options specified. E.g. The nodemcu devkit v1.0 (commonly, but incorrectly, sold as v2) also needs the
-fm dio
option.For more interesting rom layouts you’ll need to write an rBoot config sector manually, see next step.
The two testload bin files can be flashed in place of normal user roms for testing rBoot. You do not need these for normal use.
rBoot Config¶ typedef struct { uint8_t magic; // our magic uint8_t version; // config struct version uint8_t mode; // boot loader mode uint8_t current_rom; // currently selected rom uint8_t gpio_rom; // rom to use for gpio boot uint8_t count; // number of roms in use uint8_t unused[2]; // padding uint32_t roms[MAX_ROMS]; // flash addresses of the roms #ifdef BOOT_CONFIG_CHKSUM uint8_t chksum; // boot config chksum #endif } rboot_config;Write a config structure as above to address
0x1000
on the flash. If you want more than 4 roms (default) just increase MAX_ROMS when you compile rBoot. Think about how you intend to layout your flash before you start! Rom addresses must be sector aligned i.e start on a multiple of 4096.
magic
should have value0xe1
(defined asBOOT_CONFIG_MAGIC
).version
is used in case the config structure changes after deployment. It is defined as0x01
(BOOT_CONFIG_VERSION
). I don’t intend to increase this, but you should if you choose to reflash the bootloader after deployment and the config structure has changed.mode
can be0x00
(MODE_STANDARD
) or0x01
(MODE_GPIO_ROM
). See below for an explanation ofMODE_GPIO_ROM
. There is also an optional extra mode flag0x04
(MODE_GPIO_ERASES_SDKCONFIG
), see below for details.current_rom
is the rom to boot, numbered0
tocount-1
.gpio_rom
is the rom to boot when the GPIO is triggered at boot.count
is the number of roms available (may be less thanMAX_ROMS
, but not more).unused[2]
is padding so theuint32_t
rom addresses are 4 bytes aligned.roms
is the array of flash address for the roms. The default generated config will contain two entries:0x00002000
and0x00082000
.chksum
(if enabled, not by deafult) should be the xor of0xef
followed by each of the bytes of the config structure up to (but obviously not including) the chksum byte itself.Default config¶ A default config sector will be created on boot if one does not exists, or if an existing config is corrupted, and the default rom will be set to rom 0. If you want to have a very customised config for which the default would not be suitable, you can override the implementation in the
rboot.h
header file. See the comments and example code inrboot.h
for more information.GPIO boot mode¶
RBOOT_GPIO_ENABLED
¶If rBoot is compiled with
BOOT_GPIO_ENABLED
set inrboot.h
(orRBOOT_GPIO_ENABLED
set in the Makefile), then GPIO boot functionality will be included in the rBoot binary. The feature can then be enabled by setting the rboot_configmode
field toMODE_GPIO_ROM
. You must also setgpio_rom
in the config to indicate which rom to boot when the GPIO is activated at boot.If the GPIO input pin reads high at boot then rBoot will start the currently selected normal or temp rom (as appropriate). However if the GPIO is pulled low then the rom indicated in config option
gpio_rom
is started instead.The default GPIO is 16, but this can be overriden in the Makefile (
RBOOT_GPIO_NUMBER
) orrboot.h
(BOOT_GPIO_NUM
). If GPIOs other than 16 are used, the internal pullup resistor is enabled before the pin is read and disabled immediately afterwards. For pins that default on reset to configuration other than GPIO input, the pin mode is changed to input when reading but changed back before rboot continues.After a GPIO boot the
current_rom
field will be updated in the config, so the GPIO booted rom should change this again if required.GPIO boot skip mode¶
RBOOT_GPIO_SKIP_ENABLED
¶If rBoot is compiled with
BOOT_GPIO_SKIP_ENABLED
set inrboot.h
(orRBOOT_GPIO_SKIP_ENABLED
set in the Makefile), then a GPIO can be used to skip to the next rom at boot. The feature must then be enabled by setting the rboot_config ‘mode’ field toMODE_GPIO_SKIP
. This means you do not need to have a dedicated GPIO boot rom. If you have a rom that is technically good (valid checksum, etc.) but has operational problems, e.g. wifi doesn’t work or it crashes on boot, rBoot will not be able to detect that and switch rom automatically. In this scenario rebooting the device while pulling the GPIO low will force rBoot to skip this rom and try the next one instead. In a simple two rom setup this simply toggles booting of the other rom.
RBOOT_GPIO_SKIP_ENABLED
andRBOOT_GPIO_ENABLED
cannot be used at the same time.BOOT_GPIO_NUM
is used to select the GPIO pin, as withRBOOT_GPIO_ENABLED
.Erasing SDK configuration on GPIO boot (rom or skip mode)¶ If you set the
MODE_GPIO_ERASES_SDKCONFIG
flag in the configuration like this:conf.mode = MODE_GPIO_ROM|MODE_GPIO_ERASES_SDKCONFIG
; then a GPIO boot will also the erase the Espressif SDK persistent settings store in the final 16KB of flash. This includes removing calibration constants, saved SSIDs, etc.Note that
MODE_GPIO_ERASES_SDKCONFIG
is a flag, so it has to be set as well asMODE_GPIO_ROM
to take effect.Linking user code¶ Each rom will need to be linked with an appropriate linker file, specifying where it will reside on the flash. If you are only flashing one rom to multiple places on the flash it must be linked multiple times to produce the set of rom images. This is the same as with the SDK loader.
Because there are endless possibilities for layout with this loader I don’t supply sample linker files. Instead I’ll tell you how to make them.
For each rom slot on the flash take a copy of the
eagle.app.v6.ld
linker script from the sdk. You then need to modify just one line in it for each rom:irom0_0_seg : org = 0x40240000, len = 0x3C000
Change the org address to be
0x40200000
(base memory mapped location of the flash) + flash address +0x10
(offset of data after the header). The logical place for your first rom is the third sector, address0x2000
.0x40200000 + 0x2000 + 0x10 = 0x40202010
If you use the default generated config the loader will expect to find the second rom at flash address half-chip-size +0x2000
(e.g.0x82000
on an 8MBit flash) so theirom0_0_seg
should be:0x40200000 + 0x82000 + 0x10 = 0x40282010
Due to the limitation of mapped flash (max 8MBit) if you use a larger chip and do not have big flash support enabled the second rom in the default config will still be placed at0x082000
, not truly half-chip-size +0x2000
. Ideally you should also adjust the len to help detect over sized sections at link time, but more important is the overall size of the rom which you need to ensure fits in the space you have allocated for it in your flash layout plan.Then simply compile and link as you would normally for OTA updates with the SDK boot loader, except using the linker scripts you’ve just prepared rather than the ones supplied with the SDK. Remember when building roms to create them as ‘new’ type roms (for use with SDK boot loader v1.2+). Or if using my esptool2 use the
-boot2
option. Note: the test loads included with rBoot are built with-boot0
because they do not contain a.irom0.text
section (and so the value ofirom0_0_seg
in the linker file is irrelevant to them) but ‘normal’ user apps always do.irom checksum¶ The SDK boot loader checksum only covers sections loaded into ram (data and some code). Most of the SDK and user code remains on the flash and that is not included in the checksum. This means you could attempt to boot a corrupt rom and, because it looks ok to the boot loader, there will be no attempt to switch to a backup rom. rBoot improves on this by allowing the
.irom0.text
section to be included in the checksum. To enable this uncomment#define BOOT_IROM_CHKSUM
inrboot.h
and build your roms with esptool2 using the-iromchksum
option.Big flash support¶ This only needs to be enabled if you wish to be able to memory map more than the first 8MBit of the flash. Note you can still only map 8Mbit at a time. Use this if you want to have multiple 1MB roms, or more smaller roms than will fit in 8Mbits. If you have a large flash but only need, for example, two 512KB roms you do not need to enable this mode.
Support in rBoot is enabled by uncommenting the
#define BOOT_BIG_FLASH
inrboot.h
.Thinking about your linker files is either simpler or more complicated, depending on your usage of the flash. If you intend to use multiple 1MB roms you will only need one linker file and you only need to link once for OTA updates. Although when you perform an OTA update the rom will be written to a different position on the flash, each 8Mbit of flash is mapped (separately) to
0x40200000
. So when any given rom is run the code will appear at the same place in memory regardless of where it is on the flash. Your base address for the linker would be0x40202010
. (Actually all but the first rom could base at0x40200010
(because they don’t need to leave space for rBoot and config) but then you’re just making it more complicated again!)If you wanted eight 512KB roms you would need two linker files - one for the first half of any given 8Mbits of flash and another for the second half. Just remember you are really laying out within a single 8MBit area, which can then be replicated multiple times on the flash.
Now the clever bit - rBoot needs to hijack the memory mapping code to select which 8Mbits gets mapped. There is no API for this, but we can override the SDK function. First we need to slightly modify the SDK library
libmain.a
, like so:xtensa-lx106-elf-objcopy -W Cache_Read_Enable_New libmain.a libmain2.aThis produces a version of libmain with a ‘weakened’
Cache_Read_Enable_New
function, which we can then override with our own. Modify your Makefile to link against the librarymain2
instead ofmain
.Next add
rboot-bigflash.c
(from theappcode
directory) &rboot.h
to your project - this adds the replacementCache_Read_Enable_New
to your code.Getting gcc to apply the override correctly can be slightly tricky (I’m not sure why, it shouldn’t be). One option is to add
-u Cache_Read_Enable_New
to yourLD_FLAGS
and change the order of objects on the LD command so yourobjects/.a
file is before the libraries. Another way that seems easier was to#include rboot-bigflash.c
into the main .c file, rather than compiling it to a separate object file. I can’t make any sense of that, but I suggest you uncomment the message in theCache_Read_Enable_New
function when you first build with it, to make sure you are getting your version into the rom.Now when rBoot starts your rom, the SDK code linked in it that normally performs the memory mapping will delegate part of that task to rBoot code (linked in your rom, not in rBoot itself) to choose which part of the flash to map.
Temporary boot option and rBoot<–>app communication¶
RBOOT_RTC_ENABLED
¶To enable communication between rBoot and your app you should enable the
BOOT_RTC_ENABLED
option inrboot.h
. rBoot will then use the RTC data area to pass a structure with boot information which can be read by the app. This will allow the app to determine the boot mode (normal, temporary or GPIO) and the booted rom (even if it is a tempoary boot). Your app can also update this structure to communicate with rBoot when the device is next rebooted, e.g. to instruct it to temporarily boot a different rom to the one saved in the config. See the api documentation and/or the rBoot sample project for more details. Note: the message “don’t use rtc mem data”, commonly seen on startup, comes from the sdk and is not related to this rBoot feature.Integration into other frameworks¶ If you wish to integrate rBoot into a development framework (e.g. Sming) you can set the define
RBOOT_INTEGRATION
and at compile time the filerboot-integration.h
will be included into the source. This should allow you to set some platform specific options without having to modify the source of rBoot which makes it easier to integrate and maintain.SPIFFS for Sming¶
This Component provides additional functionality to support SPIFFS running on both Esp8266 and Host architectures.
DISABLE_SPIFFS
¶
- 0 (default)
- Enable filesystem generation
- 1
- Disable filesystem generation
The value is also #defined for application use.
Note this doesn’t actually disable SPIFFS support in the application!
SPIFF_SIZE
¶Size of the SPIFFS area in Flash memory.
SPIFF_FILES
¶default:
files
The SPIFFS image is built using files from this directory.
SPIFF_BIN
¶Path to the generated SPIFFS filesystem image.
SPIFF_FILEDESC_COUNT
¶Default: 7
Number of file descriptors allocated. This sets the maximum number of files which may be opened at once.
References¶ Used by¶
- Sming (main) ,Component
Environment Variables¶ Submodule: spiffs¶ SPIFFS (SPI Flash File System)¶ V0.3.7
![]()
Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976 at gmail.com)
For legal stuff, see LICENSE. Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won’t be held responsible.
Love to hear feedback though!
INTRODUCTION¶ Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
Spiffs is designed with following characteristics in mind:
- Small (embedded) targets, sparse RAM without heap
- Only big areas of data (blocks) can be erased
- An erase will reset all bits in block to ones
- Writing pulls one to zeroes
- Zeroes can only be pulled to ones by erase
- Wear leveling
BUILDING¶
mkdir build; make
Otherwise, configure the
builddir
variable towards the top ofmakefile
as something opposed to the defaultbuild
. Sanity check on the host viamake test
and refer to.travis.yml
for the official in-depth testing procedure. See the wiki for integrating spiffs into projects and spiffsimg from nodemcu is a good example on the subject.FEATURES¶ What spiffs does:
- Specifically designed for low ram usage
- Uses statically sized ram buffers, independent of number of files
- Posix-like api: open, close, read, write, seek, stat, etc
- It can run on any NOR flash, not only SPI flash - theoretically also on embedded flash of a microprocessor
- Multiple spiffs configurations can run on same target - and even on same SPI flash device
- Implements static wear leveling
- Built in file system consistency checks
- Highly configurable
What spiffs does not:
- Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path tmp/myfile.txt will create a file called tmp/myfile.txt instead of a myfile.txt under directory tmp.
- It is not a realtime stack. One write operation might last much longer than another.
- Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128Mbyte is probably a bad idea. This is a side effect of the design goal to use as little ram as possible.
- Presently, it does not detect or handle bad blocks.
- One configuration, one binary. There’s no generic spiffs binary that handles all types of configurations.
NOTICE¶ 0.4.0 is under construction. This is a full rewrite and will change the underlying structure. Hence, it will not be compatible with earlier versions of the filesystem. The API is the same, with minor modifications. Some config flags will be removed (as they are mandatory in 0.4.0) and some features might fall away until 0.4.1. If you have any worries or questions, it can be discussed in issue #179
MORE INFO¶ See the wiki for configuring, integrating, using, and optimizing spiffs.
For design, see docs/TECH_SPEC.
For a generic spi flash driver, see this.
HISTORY¶ 0.3.7¶
- fixed prevent seeking to negative offsets #158
- fixed file descriptor offsets not updated for multiple fds on same file #157
- fixed cache page not closed for removed files #156
- fixed a lseek bug when seeking exactly to end of a fully indexed first level LUT #148
- fixed wear leveling issue #145
- fixed attempt to write out of bounds in flash #130,
- set file offset when seeking over end #121 (thanks @sensslen)
- fixed seeking in virgin files #120 (thanks @sensslen)
- Optional file metadata #128 (thanks @cesanta)
- AFL testing framework #100 #143 (thanks @pjsg)
- Testframe updates
New API functions:
SPIFFS_update_meta, SPIFFS_fupdate_meta
- updates metadata for a fileNew config defines:
SPIFFS_OBJ_META_LEN
- enable possibility to add extra metadata to files0.3.6¶
- Fix range bug in index memory mapping #98
- Add index memory mapping #97
- Optimize SPIFFS_read for large files #96
- Add temporal cache for opening files #95
- More robust gc #93 (thanks @dismirlian)
- Fixed a double write of same data in certain cache situations
- Fixed an open bug in READ_ONLY builds
- File not visible in SPIFFS_readdir #90 (thanks @benpicco-tmp)
- Cache load code cleanup #92 (thanks @niclash)
- Fixed lock/unlock asymmetry #88 #87 (thanks @JackJefferson, @dpruessner)
- Testframe updates
New API functions:
SPIFFS_ix_map
- map index meta data to memory for a fileSPIFFS_ix_unmap
- unmaps index meta data for a fileSPIFFS_ix_remap
- changes file offset for index metadata mapSPIFFS_bytes_to_ix_map_entries
- utility, get length of needed vector for given amount of bytesSPIFFS_ix_map_entries_to_bytes
- utility, get number of bytes a vector can represent given lengthNew config defines:
SPIFFS_IX_MAP
- enable possibility to map index meta data to memory for reading fasterSPIFFS_TEMPORAL_FD_CACHE
- enable temporal cache for opening files fasterSPIFFS_TEMPORAL_CACHE_HIT_SCORE
- for tuning the temporal cache0.3.5¶
- Fixed a bug in fs check
- API returns actual error codes #84) (thanks @Nails)
- Fix compiler warnings for non-gcc #83 #81 (thanks @Nails)
- Unable to recover from full fs #82 (thanks @rojer)
- Define SPIFFSO* flags #80
- Problem with long filenames #79 (thanks @psjg)
- Duplicate file name bug fix #74 (thanks @igrr)
- SPIFFS_eof and SPIFFS_tell return wrong value #72 (thanks @ArtemPisarenko)
- Bunch of testframe updates #77 #78 #86 (thanks @dpreussner, @psjg a.o)
0.3.4¶
- Added user callback file func.
- Fixed a stat bug with obj id.
- SPIFFS_probe_fs added
- Add possibility to compile a read-only version of spiffs
- Make magic dependent on fs length, if needed (see #59 & #66) (thanks @hreintke)
- Exposed SPIFFS_open_by_page_function
- Zero-size file cannot be seek #57 (thanks @lishen2)
- Add tell and eof functions #54 (thanks @raburton)
- Make api string params const #53 (thanks @raburton)
- Preserve user_data during mount() #51 (thanks @rojer)
New API functions:
SPIFFS_set_file_callback_func
- register a callback informing about file eventsSPIFFS_probe_fs
- probe a spi flash trying to figure out size of fsSPIFFS_open_by_page
- open a file by page indexSPIFFS_eof
- checks if end of file is reachedSPIFFS_tell
- returns current file offsetNew config defines:
SPIFFS_READ_ONLY
SPIFFS_USE_MAGIC_LENGTH
0.3.3¶ Might not be compatible with 0.3.2 structures. See issue #40
- Possibility to add integer offset to file handles
- Truncate function presumes too few free pages #49
- Bug in truncate function #48 (thanks @PawelDefee)
- Update spiffs_gc.c - remove unnecessary parameter (thanks @PawelDefee)
- Update INTEGRATION docs (thanks @PawelDefee)
- Fix pointer truncation in 64-bit platforms (thanks @igrr)
- Zero-sized files cannot be read #44 (thanks @rojer)
- (More) correct calculation of max_id in obj_lu_find #42 #41 (thanks @lishen2)
- Check correct error code in obj_lu_find_free #41 (thanks @lishen2)
- Moar comments for SPIFFS_lseek (thanks @igrr)
- Fixed padding in spiffs_page_object_ix #40 (thanks @jmattsson @lishen2)
- Fixed gc_quick test (thanks @jmattsson)
- Add SPIFFS_EXCL flag #36
- SPIFFS_close may fail silently if cache is enabled #37
- User data in callbacks #34
- Ignoring SINGLETON build in cache setup (thanks Luca)
- Compilation error fixed #32 (thanks @chotasanjiv)
- Align cand_scores (thanks @hefloryd)
- Fix build warnings when SPIFFS_CACHE is 0 (thanks @ajaybhargav)
New config defines:
SPIFFS_FILEHDL_OFFSET
0.3.2¶
- Limit cache size if too much cache is given (thanks pgeiem)
- New feature - Controlled erase. #23
- SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
- moved dbg print defines in test framework to params_test.h
- lseek should return the resulting offset (thanks hefloryd)
- fixed type on dbg ifdefs
- silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
- Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
- Cache might writethrough too often #16
- even moar testrunner updates
- Test framework update and some added tests
- Some thoughts for next gen
- Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
- GC might be suboptimal #11
- Fix eternal readdir when objheader at last block, last entry
New API functions:
SPIFFS_gc_quick
- call a nonintrusive gcSPIFFS_gc
- call a full-scale intrusive gc0.3.1¶
- Removed two return warnings, was too triggerhappy on release
0.3.0¶
- Added existing namecheck when creating files
- Lots of static analysis bugs #6
- Added rename func
- Fix SPIFFS_read length when reading beyond file size
- Added reading beyond file length testcase
- Made build a bit more configurable
- Changed name in spiffs from “errno” to “err_code” due to conflicts compiling in mingw
- Improved GC checks, fixed an append bug, more robust truncate for very special case
- GC checks preempts GC, truncate even less picky
- Struct alignment needed for some targets, define in spiffs config #10
- Spiffs filesystem magic, definable in config
New config defines:
SPIFFS_USE_MAGIC
- enable or disable magic check upon mountSPIFFS_ALIGNED_OBJECT_INDEX_TABLES
- alignment for certain targetsNew API functions:
SPIFFS_rename
- rename filesSPIFFS_clearerr
- clears last errnoSPIFFS_info
- returns info on used and total bytes in fsSPIFFS_format
- formats the filesystemSPIFFS_mounted
- checks if filesystem is mountedSSL: Secure Sockets Layer¶
https://en.m.wikipedia.org/wiki/Transport_Layer_Security
Sming supports multiple SSL implementations, currently with adapters for:
If you want to use SSL then take a look at the Basic SSL sample for creating SSL clients, and HttpServer Config Network for SSL servers.
Configuration Variables¶
ENABLE_SSL
¶
- 0 (default): SSL requires lots of RAM and some intensive processing, so to conserve resources it is disabled by default.
- 1: to enable the default SSL adapter. At the moment that is Axtls.
- Axtls: to enable SSL support using the AXTLS 8266 component.
- Bearssl: to enable SSL support using the Bear SSL component.
API Documentation¶ SSL: Upgrading¶ Introduction¶ Sming v4.1 introduced some major changes in the SSL architecture to support multiple adapters.
The default adapter is still based on axTLS, and it can be enabled in your application by providing the
ENABLE_SSL
directive either in your component.mk file or during compilation.Migration¶ The access to the SSL connection from the TcpConnection is simplified and fetching information about SSL certificate and session id is easier than before.
The old code was looking like this:
SSL* ssl = connection.getSsl(); if(ssl) { const char* common_name = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); if(common_name) { debugf("Common Name:\t\t\t%s\n", common_name); } displayCipher(ssl); displaySessionId(ssl); }Now it should be migrated to the following shorter version:
auto ssl = connection.getSsl(); if(ssl != nullptr) { ssl->printTo(Serial); }SSL initialisation in TCP clients or servers is done using an
Ssl::Session::InitDelegate
callback.Old code looking like this:
MqttClient* getMqttClient() { if(mqtt == nullptr) { mqtt = new MqttClient(); mqtt->addSslOptions(SSL_SERVER_VERIFY_LATER); // << this is where we were setting SSL options Url url;Has to be migrated to the following code:
void sslInit(Ssl::Session& session) { session.options.verifyLater = true; } MqttClient* getMqttClient() { if(mqtt == nullptr) { mqtt = new MqttClient(); mqtt->setSslInitHandler(sslInit); // << this is where the sslInit callback is set Url url;It is possible to create an SSL enabled server. The excerpt below demonstrates this and it is part of the HttpServer Config Network sample. Pay attention to the security considerations and limitations using this on a microcontroller with limited RAM:
void startWebServer() { #ifdef ENABLE_SSL server.setSslInitHandler([](Ssl::Session& session) { debug_i("SSL Init handler: setting server keyCert"); session.keyCert.assign(serverKey, serverCert); }); server.listen(443, true); #else server.listen(80); #endif server.paths.set("/", onIndex); server.paths.set("/ipconfig", onIpConfig); server.paths.set("/ajax/get-networks", onAjaxNetworkList); server.paths.set("/ajax/connect", onAjaxConnect); server.paths.setDefault(onFile); }Setting client certificates, ssl options and pinning for a HttpRequest is done using onSslInit callback. If you look at the Basic SSL sample you will see that the old way of setting them was as shown below:
HttpRequest* request = new HttpRequest(F("https://www.grc.com/fingerprints.htm")); request->setSslOptions(SSL_SERVER_VERIFY_LATER); request->pinCertificate(fingerprints);The new one is using the following sequence of commands:
auto request = new HttpRequest(F("https://www.grc.com/fingerprints.htm")); request->onSslInit(grcSslInit);A sample callback is given below. In the callback the developer has access to the current SSL session and HTTP request and can modify them accordingly:
void grcSslInit(Ssl::Session& session, HttpRequest& request) { static const Ssl::Fingerprint::Cert::Sha1 fingerprint PROGMEM = { ... }; session.validators.pin(fingerprint); // We're using validators, so don't attempt to validate full certificate session.options.verifyLater = true; session.fragmentSize = Ssl::eSEFS_16K; }Note also that the
Fingerprints
class has been removed. Instead, we use methods ofsession.validators
to:
- Pin fingerprints;
- Add one or more custom callback validators;
- Implement custom validators by inheriting from
Ssl::Validator
.Cryptographic support¶ Some basic class-based cryptographic support is provided via the Cryptographic Support library, organised within the
Crypto
namespace.This is primarily for use with the SSL interface but does not require SSL to be enabled.
The cryptographic ‘C’ libraries themselves may be used directly by your application, regardless of which SSL adapter is in use, or even if SSL is disabled.
For example the following old code is using axTLS cryptographic functions:
char* loadPsk(int* keylen) { SHA1_CTX sha_ctx; // ... SHA1_Init(&sha_ctx); SHA1_Update(&sha_ctx, (uint8_t*)buffer, strlen(buffer)); SHA1_Final(digest, &sha_ctx);For this code to work you should include the following header:
#include <axtls-8266/crypto/crypto.h>And also make sure that your application component.mk file has the following line:
COMPONENT_DEPENDS += axtls-8266SSL namespace¶ All SSL related classes and types are organized in a separate namespace called
Ssl
. For example you should useSsl::KeyCertPair
instead ofSslKeyCertPair
andSsl::Fingerprints
instead ofSslFingerprints
.Comparison of SSL implementations¶ Memory usage¶ axTLS uses dynamic (heap) allocations which causes issues with large fragment sizes. If you run into memory problems, try setting
ENABLE_CUSTOM_HEAP
.Bear SSL uses fixed buffers and does not suffer from this limitation.
{ todo }
Session¶
- class
Session
¶Handles all SSL activity for a TCP connection.
A session is created for every TCP connection where
useSsl
is specified. It is then passed to any registered session initialisation callbacks for customisation.Public Functions
~Session
()¶
- const SessionId *
getSessionId
() const¶If available, return the current SSL Session ID.
- Return Value
SessionId*
: If connection hasn’t been established, may return Null
- bool
onAccept
(TcpConnection *client, tcp_pcb *tcp)¶Called when a client connection is made via server TCP socket.
- Parameters
client
: The client TCP sockettcp
: The low-level TCP connection to use for reading and writing- Return Value
bool
: true if the connection may proceed, false to abort
- void
setConnection
(Connection *connection)¶Called by TcpConnection to set the established SSL connection.
- Parameters
connection
: The server connection
- Connection *
getConnection
()¶Get the currently active SSL connection object.
- Return Value
Connection*
:
- bool
onConnect
(tcp_pcb *tcp)¶Handle connection event.
- Parameters
tcp
:- Return Value
bool
: true on success, false to abort the connection
- bool
isConnected
() const¶Determine if an SSL connection has been fully established.
- Return Value
bool
: Connection state
- void
close
()¶End the session.
SSL typically sends a closing handshake at this point
- int
read
(InputBuffer &input, uint8_t *&output)¶Read data from SSL connection.
- Parameters
input
: Source encrypted dataoutput
: Points to decrypted content- Return Value
int
: Size of decrypted data returned, or negative on error
- int
write
(const uint8_t *data, size_t length)¶Write data to SSL connection.
- Parameters
data
:length
:- Return Value
int
: Quantity of bytes actually written, or tcp error code
- bool
validateCertificate
()¶Called by SSL adapter when certificate validation is required.
- Note
- SSL Internal method
- Return Value
bool
: true if validation is success, false to abort connection
- void
handshakeComplete
(bool success)¶Called by SSL adapter when handshake has been completed.
- Note
- SSL Internal method
- Parameters
success
: Indicates if handshake was successful
- size_t
printTo
(Print &p) const¶For debugging.
Public Members
- String
hostName
¶Used for SNI https://en.wikipedia.org/wiki/Server_Name_Indication.
- KeyCertPair
keyCert
¶Required for server, optional for client.
- MaxBufferSize
maxBufferSize
= MaxBufferSize::Default¶Controls SSL RAM usage.
- const CipherSuites::Array *
cipherSuites
= &CipherSuites::basic¶Configure supported cipher suites. Default is basic.
- int
cacheSize
= 10¶Set session caching.
Server: Number of cached client sessions. Suggested value: 10.
Client: Number of cached session ids. Suggested value: 1.
- ValidatorList
validators
¶List of certificate validators used by Client.
- struct
Options
¶Configurable options.
- enum
Ssl
::
MaxBufferSize
¶Indicate to SSL how much memory (approximately) to commit for buffers.
A remote SSL server may require data transfers in large (16K) fragments, so restricting buffer sizes may cause connections to such servers to fail.
This must be balanced against other requirements for RAM by the application, therefore this setting can be used to restrict RAM usage.
- Note
- The ordinal value of this enumeration corresponds to SSL fragment size as defined in Maximum Fragment Length Negotiation https://tools.ietf.org/html/rfc6066
Values:
Default
= 0¶Let SSL implementation decide.
B512
¶512 bytes
K1
¶1024 bytes
K2
¶
K4
¶
K8
¶
K16
¶Cipher Suites¶
- enum
Ssl
::
CipherSuite
¶Cipher suite identifier.
The TLS standard specifies codes using two 8-bit values. We combine these into a single 16-bit value in MSB-LSB order.
For example:
TLS_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x2F } = 0x002F
- See
- Refer to
CipherSuite.h
for defined values.Values:
XX
¶
- namespace
CipherSuites
¶Standard cipher suite options The actual suites are implementation-specific.
Standard cipher suites lists
DECLARE_CIPHER_SUITES
(basic)¶Supported by all adapters.
DECLARE_CIPHER_SUITES
(full)¶Adapter-specific.
Typedefs
- using
Ssl::CipherSuites::Array = typedef FSTR::Array<Ssl::CipherSuite>
Certificates¶
- class
Certificate
¶Implemented by SSL adapter to handle certificate operations.
Public Types
Public Functions
- virtual
~Certificate
()¶
- virtual bool
getFingerprint
(Fingerprint::Type type, Fingerprint &fingerprint) const = 0¶Obtain certificate fingerprint.
- Parameters
type
: Which type of fingerprint to returnfingerprint
: On success, returned fingerprint- Return Value
bool
: true on success, false if fingerprint not available
- virtual String
getName
(DN dn, RDN rdn) const = 0¶Retrieve an X.509 distinguished name component.
- Parameters
dn
: The desired Distinguished Namerdn
: The component to return- Return Value
String
: The requested Distinguished Name component
- size_t
printTo
(Print &p) const¶Debugging print support.
- class
ValidatorList
: public Vector<Validator>¶Performs certificate validation.
Validators are created in the application’s session initialisation callback. When the certificate has been received, it is checked against each registered validator in turn until successful. All validators are destroyed during this process.
If there are no validators in the list then the certificate will not be checked and the connection accepted.
Public Types
- template<>
typedef int (*Comparer
)(const Validator &lhs, const Validator &rhs)¶Public Functions
- bool
add
(Validator *validator)¶Add a validator to the list.
- Parameters
validator
: Must be allocated on the heap
- template <class T>
boolpin
(const T &fingerprint)¶Pin a fingerprint.
Creates and adds a fingerprint validator to the list
- bool
add
(ValidatorCallback callback, void *data = nullptr)¶Register a custom validator callback.
- Parameters
callback
:data
: User-provided data (optional)
- bool
validate
(const Certificate *certificate)¶Validate certificate via registered validators.
We only need one match for a successful result, but we free all the validators. This method must be called no more than ONCE.
- Note
- Called by SSL framework.
- Parameters
certificate
: When called with nullptr will free all validators, then fail- Return Value
bool
: true on success, false on failure
- unsigned int
capacity
() const¶
- bool
contains
(const Validator &elem) const¶
- const Validator &
firstElement
() const¶
- int
indexOf
(const Validator &elem) const¶
- bool
isEmpty
() const¶
- const Validator &
lastElement
() const¶
- int
lastIndexOf
(const Validator &elem) const¶
- unsigned int
count
() const¶
- unsigned int
size
() const¶
- void
copyInto
(Validator *array) const¶
- bool
add
(const Validator &obj)¶
- bool
addElement
(const Validator &obj)¶
- bool
addElement
(Validator *objp)¶
- void
clear
()¶
- bool
ensureCapacity
(unsigned int minCapacity)¶
- void
removeAllElements
()¶
- bool
removeElement
(const Validator &obj)¶
- bool
setSize
(unsigned int newSize)¶
- void
trimToSize
()¶
- const Validator &
elementAt
(unsigned int index) const¶
- bool
insertElementAt
(const Validator &obj, unsigned int index)¶
- const void
remove
(unsigned int index)¶
- void
removeElementAt
(unsigned int index)¶
- bool
setElementAt
(const Validator &obj, unsigned int index)¶
- const Validator &
get
(unsigned int index) const¶
- const Validator &
operator[]
(unsigned int index) const¶
- Validator &
operator[]
(unsigned int index)¶
- void
sort
(Comparer compareFunction)¶
- const Validator &
at
(unsigned int i) const¶Public Members
- Fingerprint::Types
fingerprintTypes
¶Contains a list of registered fingerprint types.
Allows implementations to avoid calculating fingerprint values which are not required, as this is computationally expensive.
- class
Validator
¶Base validator class.
Validation is performed by invoking each validator in turn until a successful result is obtained.
Custom validators may either override this class, or use a callback.
Subclassed by Ssl::CallbackValidator, Ssl::FingerprintValidator< FP >
- union
Fingerprint
¶- #include <Fingerprints.h>
Various types of fingerprint.
Applications should use the appropriate type to define a fingerprint, for example:
static const Fingerprint::Cert::Sha1 fingerprint PROGMEM = { ... };Public Types
- enum
Type
¶SSL Certificate fingerprint type.
Values:
CertSha1
¶SHA1 Fingerprint of entire certificate.
CertSha256
¶SHA256 Fingerprint of entire certificate.
PkiSha256
¶SHA256 Fingerprint of Public Key Information.
- union
Cert
¶- #include <Fingerprints.h>
Fingerprints for the entire Certificate.
- struct
Sha1
¶- #include <Fingerprints.h>
Fingerprint based on the SHA1 value of the certificate.
The SHA1 hash of the entire certificate. This changes on each certificate renewal so needs to be updated every time the remote server updates its certificate.
Advantages: Takes less time to verify than SHA256
Disadvantages: Likely to change periodically
Public Static Attributes
- constexpr Type
type
= Type::CertSha1¶
- struct
Sha256
¶- #include <Fingerprints.h>
Fingerprint based on the SHA256 value of the certificate.
Typically displayed in browser certificate information
Public Static Attributes
- constexpr Type
type
= Type::CertSha256¶
- union
Pki
¶- #include <Fingerprints.h>
for the Public Key only
- struct
Sha256
¶- #include <Fingerprints.h>
Fingerprint based on the SHA256 value of the Public Key Subject in the certificate.
For HTTP public key pinning (RFC7469), the SHA-256 hash of the Subject Public Key Info (which usually only changes when the public key changes) is used.
Advantages: Doesn’t change frequently
Disadvantages: Takes more time (in ms) to verify.
Public Static Attributes
- constexpr Type
type
= Type::PkiSha256¶Adapter API¶ These classes provide the interface between a
Ssl::Session
and an appropriate adapter.
- Returned int error codes are 0 for success, or < 0 for error.
- The error codes themselves are implementation-specific.
- Use getErrorString() to obtain the message.
- SSL Alerts are also reported via error codes. Use getAlert
- class
Factory
¶Implemented by SSL adapter.
- class
Context
¶Implemented by SSL adapter to create and manage SSL connections.
Public Functions
- virtual
~Context
()¶
- virtual bool
init
() = 0¶Initializer method that must be called after object creation and before the creation of server or client connections.
- Return Value
bool
: true on success
- virtual Connection *
createClient
(tcp_pcb *tcp) = 0¶Creates client SSL connection. Your SSL client use this call to create a client connection to remote server.
- Return Value
Connection*
:
- virtual Connection *
createServer
(tcp_pcb *tcp) = 0¶Creates server SSL connection. Your SSL servers use this call to allow remote clients to connect to them and use SSL.
- Return Value
Connection*
:
- class
Connection
: public Printable¶Implemented by SSL adapter to handle a connection.
Returned
int
error codes are 0 for success, or < 0 for error.The error codes themselves are implementation-specific. Use
getErrorString()
to obtain the message. SSL Alerts are also reported via error codes and can be obtained using a call togetAlert()
.Public Functions
- virtual
~Connection
()¶
- virtual bool
isHandshakeDone
() const = 0¶Checks if the handshake has finished.
- Return Value
bool
: true on success
- virtual int
read
(InputBuffer &input, uint8_t *&output) = 0¶Reads encrypted information and decrypts it.
- Parameters
input
: Source encrypted dataoutput
: Pointer to decrypted plaintext buffer- Return Value
0
: : handshake is still in progress > 0 : there is decrypted data < 0 : error
- virtual int
write
(const uint8_t *data, size_t length) = 0¶Converts and sends plaintext data.
- Parameters
data
:length
:- Return Value
int
: length of the data that was actually written < 0 on error
- virtual CipherSuite
getCipherSuite
() const = 0¶Gets the cipher suite that was used.
- Return Value
CipherSuite
: IDs as defined by SSL/TLS standard
- virtual SessionId
getSessionId
() const = 0¶Gets the current session id object. Should be called after handshake.
- Return Value
- virtual const Certificate *
getCertificate
() const = 0¶Gets the certificate object. That object MUST be owned by the Connection implementation and should not be freed outside of it.
- Return Value
Certificate*
: Returns NULL if there is no certificate available
- virtual void
freeCertificate
() = 0¶
- size_t
printTo
(Print &p) const¶For debugging.
- int
writeTcpData
(uint8_t *data, size_t length)¶
- virtual Alert
getAlert
(int error) const = 0¶Get alert code from error.
- Parameters
error
:- Return Value
Alert
: Alert::INVALID if not an alertReferences¶
- Source Code
- AXTLS 8266 Component
- Cryptographic Support Component
Used by¶
- Sming (main) ,Component
Environment Variables¶ Terminal¶
Introduction¶ This Component provides make targets to support a serial terminal for communicating with devices.
The default serial terminal is miniterm. If you don’t have it installed already, you can install it via pip using the following command:
make python-requirements(You’ll need python, of course.)
Options¶
COM_PORT
¶Default port for device communications. Default value depends on the development platform being used.
COM_OPTS
¶Additional options to pass to the terminal.
TERMINAL
¶Command line to use when running
make terminal
. Redefine if you want to use a different terminal application.
KILL_TERM
¶Command line to use to kill the running terminal process If the terminal never runs in the background and the warnings annoy you, just clear it.
References¶ Used by¶
- Sming (main) ,Component
ws_parser¶
ws_parser is a streaming parser for the WebSocket protocol (RFC 6455).
This library is loosely inspired by joyent/http_parser and shares many of the same attributes: it has no dependencies, makes no allocations or syscalls, and only requires 16 bytes of memory to maintain its parse state.
References¶
- Source Code (submodule, may be patched).
Used by¶
- Sming (main) ,Component
References¶
- Source Code
- Sming (Esp32) Component
- Sming (Esp8266) Component
- Sming (Host) Component
- FlashString Component
- HTTP Parser Component
- b64: Base64 Encoding/Decoding Routines Component
- libyuarel Component
- mqtt-protocol-c Component
- SPIFFS for Sming Component
- SSL: Secure Sockets Layer Component
- Terminal Component
- ws_parser Component
Environment Variables¶
Sming Esp32 Architecture¶
Support building Sming for the Esp32 architecture.
Build variables¶
-
IDF_PATH
¶ This contains the base directory for the ESP-IDF toolchain used to build the framework. This variable is required and must be set accordingly.
Requirements¶
In order to be able to compile for the ESP32 architecture you should have ESP-IDF v4.0 installed. A detailed installation manual can be found in the ESP-IDF documentation.
Building¶
Make sure that the IDF_PATH environmental variable is set. Also make sure that the other ESP-IDF environmental variables are set. For example on Linux this can be done using the following command:
source $IDF_PATH/export.sh
Build the framework and application as usual, specifying SMING_ARCH
=Esp32. For example:
cd $SMING_HOME/../samples/Basic_Serial
make SMING_ARCH=Esp32
This builds the application. Once built the application needs to be flashed on a real Esp32 microcontroller to run. Flashing can be done using the following command:
make flash
SDK¶
Sming comes with pre-compiled libraries and configuration files. If needed you can re-configure ESP-IDF using the command below:
make SMING_ARCH=Esp32 sdk-menuconfig
A re-compilation is required after the change of the configuration. This can be done with the following command:
make SMING_ARCH=Esp32 sdk-build
If you want to revert to using the default pre-compiled SDK then issue the following command:
make SMING_ARCH=Esp32 sdk-default
Components¶
Sming (Esp32)¶
This Component builds a library containing architecture-specific code, and defines dependencies for Sming to build for the Esp32.
-
ENABLE_GDB
¶ In order to be able to debug live directly on the ESP8266 microcontroller you should re-compile your application with
ENABLE_GDB=1
directive.- undefined (default)
- Compile normally
- 1
- Compile with debugging support provided by Esp8266 GDBSTUB for Sming. See also the Live Debug sample.
- Source Code
- Esp32 Drivers Component
- Esp32 Core Component Component
- Host ESP HAL Component
- References Component
- References Component
- FAT Filing System Component
- Heap Component
- Esp32 LIBC Component Component
- Esp8266 SPI Flash Support Component
- Sming (main) ,Component
Esp32 Drivers¶
Provides low-level peripheral drivers.
SDK definitions for GPIO.
-
const esp32_gpioMux_t
esp32_gpioMux
[40]¶
-
const int8_t
esp32_adc2gpio
[20]¶
-
ESP32_LOW
¶
-
ESP32_HIGH
¶
-
ESP32_INPUT
¶
-
ESP32_OUTPUT
¶
-
ESP32_PULLUP
¶
-
ESP32_INPUT_PULLUP
¶
-
ESP32_PULLDOWN
¶
-
ESP32_INPUT_PULLDOWN
¶
-
ESP32_OPEN_DRAIN
¶
-
ESP32_OUTPUT_OPEN_DRAIN
¶
-
ESP32_SPECIAL
¶
-
ESP32_FUNCTION_1
¶
-
ESP32_FUNCTION_2
¶
-
ESP32_FUNCTION_3
¶
-
ESP32_FUNCTION_4
¶
-
ESP32_FUNCTION_5
¶
-
ESP32_FUNCTION_6
¶
-
ESP32_ANALOG
¶
-
ESP32_DISABLED
¶
-
ESP32_RISING
¶
-
ESP32_FALLING
¶
-
ESP32_CHANGE
¶
-
ESP32_ONLOW
¶
-
ESP32_ONHIGH
¶
-
ESP32_ONLOW_WE
¶
-
ESP32_ONHIGH_WE
¶
-
digitalPinIsValid
(pin)¶
-
digitalPinCanOutput
(pin)¶
-
digitalPinToRtcPin
(pin)¶
-
digitalPinToAnalogChannel
(pin)¶
-
digitalPinToTouchChannel
(pin)¶
-
digitalPinToDacChannel
(pin)¶
-
enum
gpio_driver
::
GPIO_INT_TYPE
¶ Defines the GPIO interrupt type.
Values:
-
GPIO_PIN_INTR_DISABLE
= 0¶ Interrupt disabled for this pin
-
GPIO_PIN_INTR_POSEDGE
= 1¶ Interrupt occurs on positive edge
-
GPIO_PIN_INTR_NEGEDGE
= 2¶ Interrupt occurs on negative edge
-
GPIO_PIN_INTR_ANYEDGE
= 3¶ Interrupt occurs on both positive and negative edge
-
GPIO_PIN_INTR_LOLEVEL
= 4¶ Interrupt occurs when GPIO low
-
GPIO_PIN_INTR_HILEVEL
= 5¶ Interrupt occurs when GPIO high
-
-
struct
esp32_gpioMux_t
¶ - #include <gpio.h>
Driver for hardware timers.
-
USE_US_TIMER
¶ 0 (default): Use default /256 prescale for Timer2 1: Use /16 prescale
The following functions depend on Timer2: - NOW() return value, the Timer2 tick count - Software timers - System time
Software timers are driven by Timer2, which by default uses a /256 prescale providing a resolution of 3.2us and a range of 1’ 54”.
Enabling this setting increases the resolution to 200ns but reduces the maximum software timer to 7” 9.5s.
-
enum
hw_timer
::
hw_timer_clkdiv_t
¶ Values:
-
TIMER_CLKDIV_1
= 0¶
-
TIMER_CLKDIV_16
= 4¶
-
TIMER_CLKDIV_256
= 8¶
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
-
enum
hw_timer
::
hw_timer_intr_type_t
¶ Values:
-
TIMER_EDGE_INT
= 0¶
-
TIMER_LEVEL_INT
= 1¶
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
-
enum
hw_timer
::
hw_timer_source_type_t
¶ Values:
-
TIMER_FRC1_SOURCE
= 0¶
-
TIMER_NMI_SOURCE
= 1¶
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
-
enum
hw_timer
::
hw_timer_clkdiv_t
Values:
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
-
enum
hw_timer
::
hw_timer_intr_type_t
Values:
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
-
enum
hw_timer
::
hw_timer_source_type_t
Values:
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
-
typedef void (*
hw_timer_callback_t
)(void *arg)¶
-
typedef void (*
hw_timer_callback_t
)(void *arg)
-
constexpr uint32_t
HW_TIMER2_CLKDIV
= TIMER_CLKDIV_256¶
-
constexpr uint32_t
HW_TIMER2_CLK
= HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV¶
-
constexpr uint32_t
HW_TIMER2_CLKDIV
= TIMER_CLKDIV_256
-
constexpr uint32_t
HW_TIMER2_CLK
= HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV
-
void
hw_timer1_attach_interrupt
(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void *arg)¶ Attach an interrupt for the timer.
- Parameters
source_type
:callback
: Callback function invoked via timer interruptarg
: Passed to callback function
-
void
hw_timer1_enable
(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load)¶ Enable the timer.
- Parameters
div
:intr_type
:auto_load
:
-
void
hw_timer1_write
(uint32_t ticks)¶ Set the timer interval.
- Parameters
ticks
:
-
void
hw_timer1_disable
(void)¶ Disable the timer.
-
void
hw_timer1_detach_interrupt
(void)¶ Detach interrupt from the timer.
-
uint32_t
hw_timer1_read
(void)¶ Get timer1 count.
- Return Value
uint32_t
: Current count value, counts from initial value down to 0
-
uint32_t
hw_timer2_read
(void)¶ Read current timer2 value.
- Return Value
uint32_t
:
-
void
hw_timer2_set_alarm
(uint32_t ticks)¶ Set timer2 alarm count value.
- Note
- For internal use ONLY; used by software timers
- Parameters
ticks
:
-
void
hw_timer_init
(void)¶ Initialise hardware timers.
- Note
- Called by startup code
-
MAX_HW_TIMER1_INTERVAL
¶ Maximum timer interval in ticks.
- Note
- The corresponding time interval depends on the prescaler in use:
/1 - 0.1048s /16 - 1.677s /256 - 26.84s
-
MIN_HW_TIMER1_INTERVAL_US
¶ Minimum hardware interval in microseconds.
- Note
- Attempting to use repetitive interrupts below this level can lead to system instabliity and lockups, due to the software overhead in servicing the interrupts.
-
MAX_HW_TIMER1_INTERVAL
Maximum timer interval in ticks.
- Note
- The corresponding time interval depends on the prescaler in use:
/1 - 0.1048s /16 - 1.677s /256 - 26.84s
-
MIN_HW_TIMER1_INTERVAL_US
Minimum hardware interval in microseconds.
- Note
- Attempting to use repetitive interrupts below this level can lead to system instabliity and lockups, due to the software overhead in servicing the interrupts.
I2S was designed for transfer of digital audio data.
The ESP8266 has two I2S modules (one transmitter and one receiver), both with hardware DMA support, which means transfers from RAM to the hardware SPI FIFO can be handled directly in hardware without any CPU involvement.
The Sming driver deals with the complicated of setting up the hardware, using an API similar to that in the Espressif RTOS SDK. In addition, DMA buffers may be accessed directly to avoid double-buffering and the associated RAM and copy overhead.
Playing MIDI files, MP3 files, speech synthesis, etc. is all possible using the ESP8266, though many audio applications require considerable processing power. That means you may need to disable WiFi and set the processor to run at full 160MHz speed.
High-quality multi-channel audio requires an external I2S DAC, which is what the protocol was designed for in the first place. You may find problems with insufficient RAM, but you can always add external SPI RAM.
More realistic uses include generating simple tones, beeps, playing pre-recorded WAV audio, etc. to supplement existing projects. This can all be done in the background without disrupting the system’s main purpose, whatever that may be.
For such applications you can generate single-channel audio via the I2S OUT pin, using Pulse-density modulation.
See the Tone Generator library for a demonstration of this.
Expand GPIO using low-cost shift registers. https://github.com/lhartmann/esp8266_reprap.
Devices such as WS2812-based NeoPixels use a simple, single-wire protocol. I2S is ideal for this as it can be used to generate a precisely-timed bitstream with very low CPU loading.
-
enum
i2s_driver
::
i2s_bits_per_sample_t
¶ I2S bit width per sample.
Values:
-
I2S_BITS_PER_SAMPLE_8BIT
= 8¶ I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16¶ I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24¶ I2S bits per sample: 24-bits.
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
-
enum
i2s_driver
::
i2s_channel_t
¶ I2S channel.
Values:
-
I2S_CHANNEL_MONO
= 1¶ I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2¶ I2S 2 channel (stereo)
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
-
enum
i2s_driver
::
i2s_comm_format_t
¶ I2S communication standard format.
Values:
-
I2S_COMM_FORMAT_I2S
= 0x01¶ I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01¶ I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03¶ I2S format LSB.
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
-
enum
i2s_driver
::
i2s_channel_fmt_t
¶ I2S channel format type.
Values:
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00¶
-
I2S_CHANNEL_FMT_ALL_RIGHT
¶
-
I2S_CHANNEL_FMT_ALL_LEFT
¶
-
I2S_CHANNEL_FMT_ONLY_RIGHT
¶
-
I2S_CHANNEL_FMT_ONLY_LEFT
¶
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
-
enum
i2s_driver
::
i2s_mode_t
¶ I2S Mode, default is I2S_MODE_MASTER.
Values:
-
I2S_MODE_DISABLED
¶
-
I2S_MODE_MASTER
¶
-
I2S_MODE_SLAVE
¶
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
-
enum
i2s_driver
::
i2s_event_type_t
¶ I2S event types.
Values:
-
I2S_EVENT_DMA_ERROR
¶
-
I2S_EVENT_TX_DONE
¶ I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
¶ I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
¶ I2S event max index
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
-
enum
i2s_driver
::
i2s_pin_t
¶ I2S pin enable for i2s_set_pin.
Values:
-
I2S_PIN_BCK_OUT
= 0x01¶ GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02¶ GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04¶ GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10¶ GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20¶ GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40¶ GPIO 12 / D6.
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
-
enum
i2s_driver
::
i2s_bits_per_sample_t
I2S bit width per sample.
Values:
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
-
enum
i2s_driver
::
i2s_channel_t
I2S channel.
Values:
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
-
enum
i2s_driver
::
i2s_comm_format_t
I2S communication standard format.
Values:
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
-
enum
i2s_driver
::
i2s_channel_fmt_t
I2S channel format type.
Values:
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
-
enum
i2s_driver
::
i2s_mode_t
I2S Mode, default is I2S_MODE_MASTER.
Values:
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
-
enum
i2s_driver
::
i2s_event_type_t
I2S event types.
Values:
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
-
enum
i2s_driver
::
i2s_pin_t
I2S pin enable for i2s_set_pin.
Values:
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
-
typedef void (*
i2s_callback_t
)(void *param, i2s_event_type_t event)¶ Callback function type.
- Note
- Function is called in interrupt context, so place in IRAM and keep it brief.
-
typedef unsigned
TickType_t
¶ Defines the wait interval (presently milliseconds)
-
typedef uint8_t
i2s_pin_set_t
¶
-
typedef void (*
i2s_callback_t
)(void *param, i2s_event_type_t event) Callback function type.
- Note
- Function is called in interrupt context, so place in IRAM and keep it brief.
-
typedef unsigned
TickType_t
Defines the wait interval (presently milliseconds)
-
typedef uint8_t
i2s_pin_set_t
-
bool
i2s_driver_install
(const i2s_config_t *config)¶ Install and start I2S driver.
- Note
- This function must be called before any I2S driver read/write operations.
- Parameters
config
: I2S configuration
- Return Value
true
: on success, false if already installed or invalid config
-
void
i2s_driver_uninstall
()¶ Uninstall I2S driver.
-
bool
i2s_start
()¶ Start I2S driver.
- Note
- It is not necessary to call this function after i2s_driver_install() as it is started automatically, unless
config.auto_start
was set to false. - Return Value
bool
: true on success, false if driver not initialised
-
bool
i2s_stop
()¶ Stop I2S driver.
- Note
- Disables I2S TX/RX, until i2s_start() is called
- Return Value
bool
: true on success, false if driver not initialised
-
bool
i2s_set_sample_rates
(uint32_t rate)¶ - Parameters
rate
: Sample rate in Hz (ex 44100, 48000) for TX/RX
-
bool
i2s_set_dividers
(uint8_t bck_div, uint8_t mclk_div)¶ Direct control over output rate
-
float
i2s_get_real_rate
()¶ - Return Value
float
: The actual Sample Rate on output
-
bool
i2s_dma_read
(i2s_buffer_info_t *info, size_t max_bytes)¶ Fetch a DMA buffer containing received data (zero-copy)
- Note
- On success,
info->buffer
specifies where to read the data from, andinfo->size
how many bytes are actually available (always > 0). - Note
- Returns at most one DMA buffer
- Parameters
info
: Pointer to structure to receive buffer informationmax_bytes
: Number of bytes to read
- Return Value
bool
: true on success, false if no data available or info is null
-
bool
i2s_dma_write
(i2s_buffer_info_t *info, size_t max_bytes)¶ Fetch a DMA buffer for direct writing (zero-copy)
- Note
- On success,
info->buffer
specifies where to write the data, andinfo->size
how many bytes should be written - may be less than max_bytes, but always > 0. - Note
- Returns at most one DMA buffer
- Parameters
info
: Pointer to structure to receive buffer informationmax_bytes
: Number of bytes required in buffer
- Return Value
bool
: true on success, false if buffer unavailable or info is null
-
size_t
i2s_write
(const void *src, size_t size, TickType_t ticks_to_wait)¶ writes a buffer of frames into the DMA memory, returns the amount of frames written.
- Note
- Data is copied into DMA buffers
- Parameters
src
: Data to writesize
: Size in bytesticks_to_wait
: Wait timeout in ticks
- Return Value
size_t
: Data actually written, may be less than size
-
size_t
i2s_read
(void *dest, size_t size, TickType_t ticks_to_wait)¶ Reads a block of received data.
- Parameters
dest
: Buffer to store datasize
: Max. bytes to readticks_to_wait
: Wait timeout in ticks
- Return Value
size_t
: Number of bytes read
-
bool
i2s_zero_dma_buffer
()¶ Zero the contents of the TX DMA buffer.
- Note
- Pushes zero-byte samples into the TX DMA buffer, until it is full
-
void
i2s_set_pins
(i2s_pin_set_t pins, bool enable)¶ Configure I2S pins.
You can alternatively use arduino functions.
- Note
- Call this after initialising driver to specify which pins are required
- Parameters
pins
: Mask of i2s_pin_t valuesenable
: true to enable for I2S use, false to revert to GPIO
Example: i2s_set_pins(_BV(I2S_BCK_OUT), true)
-
bool
i2s_enable_loopback
(bool enable)¶
-
bool
i2s_stat_tx
(i2s_buffer_stat_t *stat)¶ Obtain state information for TX buffers.
- Parameters
stat
:
- Return Value
bool
: true on success
-
bool
i2s_stat_rx
(i2s_buffer_stat_t *stat)¶ Obtain state information for RX buffers.
- Parameters
stat
:
- Return Value
bool
: true on success
-
union
i2s_sample_t
¶ - #include <i2s.h>
I2S sample.
An I2S frame can contain various types of data:
8-bit, 16-bit or 24-bit mono samples 8-bit or 16-bit stereo samples
Public Members
-
uint32_t
u32
¶
-
int16_t
left
¶
-
int16_t
right
¶
-
struct i2s_sample_t::[anonymous] [anonymous]¶
-
struct i2s_sample_t::[anonymous] [anonymous]¶
-
uint32_t
-
struct
i2s_module_config_t
¶ - #include <i2s.h>
I2S module configuration (TX or RX)
Public Members
-
i2s_mode_t
mode
¶ I2S work mode (combination of i2s_mode_t)
-
i2s_bits_per_sample_t
bits_per_sample
¶ I2S bits per sample.
-
i2s_channel_fmt_t
channel_format
¶ I2S channel format.
-
i2s_comm_format_t
communication_format
¶ I2S communication format.
-
uint16_t
dma_buf_len
¶ I2S DMA Buffer Length (in samples)
-
uint8_t
dma_buf_count
¶ I2S DMA Buffer Count.
-
uint8_t
callback_threshold
¶ TX: callback when available buffers > threshold RX: Callback when slc_queue_len > threshold
-
i2s_mode_t
-
struct
i2s_config_t
¶ - #include <i2s.h>
I2S configuration parameters.
Public Members
-
i2s_module_config_t
tx
¶ TX module configuration.
-
i2s_module_config_t
rx
¶ RX module configuration.
-
unsigned
sample_rate
¶ I2S sample rate.
-
bool
tx_desc_auto_clear
¶ I2S auto clear tx descriptor if there is underflow condition (Mutes output)
-
bool
auto_start
¶ Start immediately on successful initialisation.
-
i2s_callback_t
callback
¶ Callback handler.
-
void *
param
¶ Callback parameter.
-
uint8_t
bits_mod
¶ Evaluate what this does (4 bits)
-
i2s_module_config_t
-
struct
i2s_buffer_info_t
¶ - #include <i2s.h>
Defines a buffer with available content.
Public Members
-
void *
buffer
¶
-
i2s_sample_t *
samples
¶
-
union i2s_buffer_info_t::[anonymous] [anonymous]¶
-
size_t
size
¶ Available space (TX) or data (RX) in bytes.
-
uint16_t
buf
¶
-
uint16_t
pos
¶
-
union i2s_buffer_info_t::[anonymous] [anonymous]¶
-
void *
-
struct
i2s_buffer_stat_t
¶ - #include <i2s.h>
Contains I2S buffer status information.
- Note
- Size excludes buffer in use by DMA
-
void
os_timer_arm_ticks
(os_timer_t *ptimer, uint32_t ticks, bool repeat_flag)¶ Set a software timer using the Timer2 tick value.
This function has been added to Sming for more efficient and flexible use of software timers. It can be used alongside the SDK
os_timer_arm_new()
function.- Parameters
ptimer
: Timer structureticks
: Tick count duration for the timerrepeat_flag
: true if timer will automatically repeat
The driver interface is defined in the ESP8266 SDK.
-
ENABLE_CUSTOM_PWM
¶ - undefined
- use the Espressif PWM driver
- 1 (default)
- Use the New PWM driver, a drop-in replacement for the version provided in the Espressif SDK.
-
void
pwm_init
(uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32 (*pin_info_list)[3])¶ Initialize PWM function, including GPIO selection, period and duty cycle.
Example:
uint32 io_info[][3] = { {PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC, PWM_0_OUT_IO_NUM}, {PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC, PWM_1_OUT_IO_NUM}, {PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC, PWM_2_OUT_IO_NUM} }; pwm_init(light_param.pwm_period, light_param.pwm_duty, 3, io_info);
- Note
- This API can be called only once.
- Parameters
period
: PWM periodduty
: duty cycle of each outputpwm_channel_num
: PWM channel numberpin_info_list
: Array containing an entry for each channel giving
-
void
pwm_start
(void)¶ Starts PWM.
This function needs to be called after PWM configuration is changed.
-
void
pwm_set_duty
(uint32 duty, uint8 channel)¶ Sets duty cycle of a PWM output.
Set the time that high-level signal will last. The range of duty depends on PWM period. Its maximum value of which can be Period * 1000 / 45.
- Parameters
duty
: The time that high-level single will last, duty cycle will be (duty*45)/(period*1000)channel
: PWM channel, which depends on how many PWM channels are used
For example, for 1-KHz PWM, the duty range is 0 ~ 22222.
-
uint32
pwm_get_duty
(uint8 channel)¶ Get duty cycle of PWM output.
Duty cycle will be (duty*45) / (period*1000).
- Parameters
channel
: PWM channel, which depends on how many PWM channels are used
- Return Value
uint32
: Duty cycle of PWM output
-
void
pwm_set_period
(uint32 period)¶ Set PWM period.
- Parameters
period
: PWM period in us. For example, 1-KHz PWM period = 1000us.
-
uint32
pwm_get_period
(void)¶ Get PWM period.
- Return Value
uint32
: Return PWM period in us.
-
uint32
get_pwm_version
(void)¶ Get version information of PWM.
- Return Value
uint32
: PWM version
Custom asynchronous driver.
-
enum
uart_driver
::
smg_uart_mode_
¶ values for
mode
argument of uart_initValues:
-
UART_FULL
¶ Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
¶ Receive only.
-
UART_TX_ONLY
¶ Transmit only.
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
-
enum
uart_driver
::
smg_uart_option_bits_t
¶ bit values for
options
argument of uart_init- Note
- use _BV(opt) to specify values
Values:
-
UART_OPT_TXWAIT
¶ If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
¶ ISR invokes user callback function with no pre-processing.
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
enum
uart_driver
::
smg_uart_notify_code_t
¶ Indicates notification, parameters refer to uart_notify_info_t structure.
Values:
-
UART_NOTIFY_AFTER_OPEN
¶ Called when uart has been initialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
¶ Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
¶ Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
¶ Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
¶ Called to ensure all buffered data is output.
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been iniitialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
-
enum
uart_driver
::
smg_uart_mode_
values for
mode
argument of uart_initValues:
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
-
enum
uart_driver
::
smg_uart_option_bits_t
bit values for
options
argument of uart_init- Note
- use _BV(opt) to specify values
Values:
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
enum
uart_driver
::
smg_uart_notify_code_t
Indicates notification, parameters refer to uart_notify_info_t structure.
Values:
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been initialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been iniitialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
-
typedef enum smg_uart_mode_
smg_uart_mode_t
¶
-
typedef uint8_t
uart_options_t
¶
-
typedef void (*
smg_uart_callback_t
)(smg_uart_t *uart, uint32_t status)¶ callback invoked directly from ISR
Errors can be detected via uart_get_status().
- Note
- Values can be: UIFE: TX FIFO Empty UIFF: RX FIFO Full UITO: RX FIFO Timeout UIBD: Break Detected
- Parameters
arg
: the UART objectstatus
: UART USIS STATUS flag bits indicating cause of interrupt
-
typedef void (*
smg_uart_notify_callback_t
)(smg_uart_t *uart, smg_uart_notify_code_t code)¶ Port notification callback function type.
- Parameters
info
:
- Return Value
bool
: true if callback handled operation, false to default to normal operation
-
typedef enum smg_uart_mode_
smg_uart_mode_t
-
typedef uint8_t
uart_options_t
-
typedef struct smg_uart_
smg_uart_t
-
typedef void (*
smg_uart_callback_t
)(smg_uart_t *uart, uint32_t status) callback invoked directly from ISR
Errors can be detected via uart_get_status().
- Note
- Values can be: UIFE: TX FIFO Empty UIFF: RX FIFO Full UITO: RX FIFO Timeout UIBD: Break Detected
- Parameters
arg
: the UART objectstatus
: UART USIS STATUS flag bits indicating cause of interrupt
-
typedef void (*
smg_uart_notify_callback_t
)(smg_uart_t *uart, smg_uart_notify_code_t code) Port notification callback function type.
- Parameters
info
:
- Return Value
bool
: true if callback handled operation, false to default to normal operation
-
bool
smg_uart_set_notify
(unsigned uart_nr, smg_uart_notify_callback_t callback)¶ Set the notification callback function.
- Parameters
uart_nr
: Which uart to register notifications forcallback
:
- Return Value
bool
: true on success
-
smg_uart_t *
smg_uart_init
(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, size_t rx_size, size_t tx_size = 0)¶
-
smg_uart_t *
smg_uart_init_ex
(const smg_uart_config &cfg)¶
-
void
smg_uart_uninit
(smg_uart_t *uart)¶
-
int
smg_uart_get_nr
(smg_uart_t *uart)¶
-
smg_uart_t *
smg_uart_get_uart
(uint8_t uart_nr)¶ Get the uart structure for the given number.
- Parameters
uart_nr
:
- Return Value
uart_t*
: Returns nullptr if uart isn’t initialised
-
void
smg_uart_set_callback
(smg_uart_t *uart, smg_uart_callback_t callback, void *param)¶ Set callback handler for serial port.
- Parameters
uart
:callback
: specify nullptr to disable callbacksparam
: user parameter passed to callback
-
void *
smg_uart_get_callback_param
(smg_uart_t *uart)¶ Get the callback parameter specified by uart_set_callback()
- Parameters
uart
:
- Return Value
void*
: the callback parameter
-
static void
smg_uart_set_options
(smg_uart_t *uart, uart_options_t options)¶ Set option flags.
- Parameters
uart
:options
: The option(s) to set
-
uint8_t
smg_uart_get_status
(smg_uart_t *uart)¶ Get error flags and clear them.
- Note
- To detect errors during a transaction, call at the start to clear the flags, then check the value at the end. Only these values are cleared/returned: UIBD: Break Detected UIOF: RX FIFO OverFlow UIFR: Frame Error UIPE: Parity Error
- Parameters
uart
:
- Return Value
Status
: error bits:
-
static uart_options_t
smg_uart_get_options
(smg_uart_t *uart)¶
-
void
smg_uart_swap
(smg_uart_t *uart, int tx_pin)¶
-
void
smg_uart_set_tx
(smg_uart_t *uart, int tx_pin)¶
-
void
smg_uart_set_pins
(smg_uart_t *uart, int tx, int rx)¶
-
bool
smg_uart_tx_enabled
(smg_uart_t *uart)¶
-
bool
smg_uart_rx_enabled
(smg_uart_t *uart)¶
-
uint32_t
smg_uart_set_baudrate_reg
(int uart_nr, uint32_t baud_rate)¶ set UART baud rate, given the UART number
- Parameters
uart_nr
:baud_rate
: requested baud rate
- Return Value
uint32_t
: actual baudrate used, 0 on failure
-
uint32_t
smg_uart_set_baudrate
(smg_uart_t *uart, uint32_t baud_rate)¶ set UART baud rate
- Parameters
uart
:baud_rate
: requested baud rate
- Return Value
uint32_t
: actual baudrate used, 0 on failure
-
uint32_t
smg_uart_get_baudrate
(smg_uart_t *uart)¶ get the actual baud rate in use
- Parameters
uart
:
- Return Value
uint32_t
: the baud rate, 0 on failure
-
size_t
smg_uart_resize_rx_buffer
(smg_uart_t *uart, size_t new_size)¶
-
size_t
smg_uart_rx_buffer_size
(smg_uart_t *uart)¶
-
size_t
smg_uart_resize_tx_buffer
(smg_uart_t *uart, size_t new_size)¶
-
size_t
smg_uart_tx_buffer_size
(smg_uart_t *uart)¶
-
size_t
smg_uart_write
(smg_uart_t *uart, const void *buffer, size_t size)¶ write a block of data
- Parameters
uart
:buffer
:size
:
- Return Value
size_t
: number of bytes buffered for transmission
-
static size_t
smg_uart_write_char
(smg_uart_t *uart, char c)¶ queue a single character for output
- Parameters
uart
:c
:
- Return Value
size_t
: 1 if character was written, 0 on failure
-
size_t
smg_uart_read
(smg_uart_t *uart, void *buffer, size_t size)¶ read a block of data
- Parameters
uart
:buffer
: where to write the datasize
: requested quantity of bytes to read
- Return Value
size_t
: number of bytes read
-
static int
smg_uart_read_char
(smg_uart_t *uart)¶ read a received character
- Parameters
uart
:
- Return Value
the
: character, -1 on failure
-
int
smg_uart_peek_char
(smg_uart_t *uart)¶ see what the next character in the rx buffer is
- Note
- if buffer isn’t allocated data may be in the hardware FIFO, which must be read out using uart_read()
- Parameters
uart
:
- Return Value
int
: returns -1 if buffer is empty or not allocated
-
int
smg_uart_peek_last_char
(smg_uart_t *uart)¶ fetch last character read out of FIFO
- Note
- this is only useful if an rx buffer has been allocated of sufficient size to contain a message. This function then indicates the terminating character.
- Parameters
uart
:
- Return Value
int
: the character, or -1 if rx buffer is empty or unallocated
-
int
smg_uart_rx_find
(smg_uart_t *uart, char c)¶
-
size_t
smg_uart_rx_available
(smg_uart_t *uart)¶ determine available data which can be read
- Note
- this obtains a count of data both in the memory buffer and hardware FIFO
- Parameters
uart
:
- Return Value
size_t
:
-
size_t
smg_uart_tx_free
(smg_uart_t *uart)¶ return free space in transmit buffer
-
void
smg_uart_wait_tx_empty
(smg_uart_t *uart)¶
-
void
smg_uart_set_break
(smg_uart_t *uart, bool state)¶ Set or clear a break condition on the TX line.
- Parameters
uart
:state
:
-
void
smg_uart_flush
(smg_uart_t *uart, smg_uart_mode_t mode = UART_FULL)¶ discard any buffered data and reset hardware FIFOs
- Note
- this function does not wait for any transmissions to complete
- Parameters
uart
:mode
: Whether to flush TX, RX or both (the default)
-
void
smg_uart_set_debug
(int uart_nr)¶
-
int
smg_uart_get_debug
()¶
-
void
smg_uart_start_isr
(smg_uart_t *uart)¶ enable interrupts for a UART
- Parameters
uart
:
-
void
smg_uart_stop_isr
(smg_uart_t *uart)¶ disable interrupts for a UART
- Parameters
uart
:
-
void
smg_uart_detach
(int uart_nr)¶ detach a UART interrupt service routine
- Parameters
uart_nr
:
-
void
smg_uart_detach_all
()¶ detach all UART interrupt service routines
- Note
- call at startup to put all UARTs into a known state
-
uint8_t
smg_uart_disable_interrupts
()¶ disable interrupts and return current interrupt state
- Return Value
state
: non-zero if any UART interrupts were active
-
void
smg_uart_restore_interrupts
()¶ re-enable interrupts after calling uart_disable_interrupts()
-
UART0
¶
-
UART1
¶
-
UART2
¶ Virtualised UART0.
-
UART_NO
¶ No UART specified.
-
UART_PHYSICAL_COUNT
¶ Number of physical UARTs on the system.
-
UART_COUNT
¶ Number of UARTs on the system, virtual or otherwise.
-
UART_NB_BIT_MASK
¶
-
UART_NB_BIT_5
¶
-
UART_NB_BIT_6
¶
-
UART_NB_BIT_7
¶
-
UART_NB_BIT_8
¶
-
UART_PARITY_MASK
¶
-
UART_PARITY_NONE
¶
-
UART_PARITY_EVEN
¶
-
UART_PARITY_ODD
¶
-
UART_NB_STOP_BIT_MASK
¶
-
UART_NB_STOP_BIT_0
¶
-
UART_NB_STOP_BIT_1
¶
-
UART_NB_STOP_BIT_15
¶
-
UART_NB_STOP_BIT_2
¶
-
UART_5N1
¶
-
UART_6N1
¶
-
UART_7N1
¶
-
UART_8N1
¶
-
UART_5N2
¶
-
UART_6N2
¶
-
UART_7N2
¶
-
UART_8N2
¶
-
UART_5E1
¶
-
UART_6E1
¶
-
UART_7E1
¶
-
UART_8E1
¶
-
UART_5E2
¶
-
UART_6E2
¶
-
UART_7E2
¶
-
UART_8E2
¶
-
UART_5O1
¶
-
UART_6O1
¶
-
UART_7O1
¶
-
UART_8O1
¶
-
UART_5O2
¶
-
UART_6O2
¶
-
UART_7O2
¶
-
UART_8O2
¶
-
UART_RX_FIFO_SIZE
¶
-
UART_TX_FIFO_SIZE
¶
-
UART0
-
UART1
-
UART2
Virtualised UART0.
-
UART_NO
No UART specified.
-
UART_PHYSICAL_COUNT
Number of physical UARTs on the system.
-
UART_COUNT
Number of UARTs on the system, virtual or otherwise.
-
UART_NB_BIT_MASK
-
UART_NB_BIT_5
-
UART_NB_BIT_6
-
UART_NB_BIT_7
-
UART_NB_BIT_8
-
UART_PARITY_MASK
-
UART_PARITY_NONE
-
UART_PARITY_EVEN
-
UART_PARITY_ODD
-
UART_NB_STOP_BIT_MASK
-
UART_NB_STOP_BIT_0
-
UART_NB_STOP_BIT_1
-
UART_NB_STOP_BIT_15
-
UART_NB_STOP_BIT_2
-
UART_5N1
-
UART_6N1
-
UART_7N1
-
UART_8N1
-
UART_5N2
-
UART_6N2
-
UART_7N2
-
UART_8N2
-
UART_5E1
-
UART_6E1
-
UART_7E1
-
UART_8E1
-
UART_5E2
-
UART_6E2
-
UART_7E2
-
UART_8E2
-
UART_5O1
-
UART_6O1
-
UART_7O1
-
UART_8O1
-
UART_5O2
-
UART_6O2
-
UART_7O2
-
UART_8O2
-
UART_RX_FIFO_SIZE
-
UART_TX_FIFO_SIZE
-
struct
smg_uart_
¶ - #include <uart.h>
Public Members
-
uint8_t
uart_nr
¶
-
uint32_t
baud_rate
¶
-
smg_uart_mode_t
mode
¶
-
uint8_t
options
¶
-
uint8_t
rx_pin
¶
-
uint8_t
tx_pin
¶
-
uint8_t
rx_headroom
¶ Callback when rx_buffer free space <= headroom.
-
uint16_t
status
¶ All status flags reported to callback since last uart_get_status() call.
-
struct SerialBuffer *
rx_buffer
¶ Optional receive buffer.
-
struct SerialBuffer *
tx_buffer
¶ Optional transmit buffer.
-
smg_uart_callback_t
callback
¶ Optional User callback routine.
-
void *
param
¶ User-supplied callback parameter.
-
uart_port_t
uart_nr
-
uint8_t
-
struct
smg_uart_config
¶ - #include <uart.h>
Public Members
-
uint8_t
uart_nr
¶
-
uint8_t
tx_pin
¶ Specify 2 for alternate pin, otherwise defaults to pin 1.
-
smg_uart_mode_t
mode
¶ Whether to enable receive, transmit or both.
-
uart_options_t
options
¶
-
uint32_t
baudrate
¶ Requested baudrate; actual baudrate may differ.
-
uint32_t
config
¶ UART CONF0 register bits.
-
size_t
rx_size
¶
-
size_t
tx_size
¶
-
uint8_t
rx_pin
¶
-
uint8_t
- Source Code
- Esp32 Core Component Component
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Esp32 Core Component¶
Contains startup code, crash handling and additional Esp32-specific support code. Sming may be built using a pre-installed SDK, or by using the current version 3 SDK as a submodule.
Attention
At time of writing, SDK 3 does not appear to support use of devices with 256K or 512K memory, such as the ESP-01. For now, please use the default SDK 1.5.4 or SDK 2.0.0.
-
SDK_BASE
¶ Points to the location of the Espressif Non-OS SDK. To use the Espressif version 3 SDK, you need only set this variable to point at the Sming repository (
SMING_HOME
). The actual location will be subsituted by the build system and the SDK pulled in via GIT.So for Windows you need to do:
set SDK_BASE=%SMING_HOME%
For Linux (bash):
export SDK_BASE="$SMING_HOME"
If you change this value then your application and Sming must both be recompiled:
make components-clean clean make
-
SDK_INTERNAL
¶ READONLY When compiled using the current (version 3+) Espressif SDK this value is set to 1.
-
SDK_LIBDIR
¶ READONLY Path to the directory containing SDK archive libraries
-
SDK_INCDIR
¶ READONLY Path to the directory containing SDK header files
- Source Code
- References Component
- Esp32 Drivers ,Component
- Host ESP HAL ,Component
- Esp8266 WiFi ,Component
- Sming (Esp32) ,Component
- Esp8266 SPI Flash Support ,Component
Host ESP HAL¶
Provides implementations for various low-level functions similar to the Esp8266.
- Task queues
- Timer queues
- System functions
- Source Code
- Esp32 Core Component Component
- Sming (Esp32) ,Component
- Sming (Host) ,Component
References¶
Used by¶
- Esp32 Core Component ,Component
- Sming (Esp32) ,Component
Environment Variables¶
References¶
Used by¶
- Sming (Esp32) ,Component
Environment Variables¶
Esp8266 WiFi¶
All related libraries for WiFi support. Definitions are provided in the Espressif Non-OS SDK.
- Source Code
- Esp32 Core Component Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
FAT Filing System¶
Required by the SDCard library.
http://elm-chan.org/fsw/ff/00index_e.html
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
Heap¶
This Component implements heap-related housekeeping functions. Heap usage is tracked using malloc_count. This also provides some validation (using sentinels to detect if memory blocks are overwritten).
-
ENABLE_MALLOC_COUNT
¶ We require malloc_count to keep track of heap usage for system_get_free_heap_size(). It does this by hooking the memory allocation routines (malloc, free, etc.). If you wish to disable this behaviour, set ENABLE_MALLOC_COUNT=0. If using tools such as Valgrind, this will provide a cleaner trace.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Esp32 LIBC Component¶
This Component accommodates the differences in runtime libraries for the various supported toolchains.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Esp8266 SPI Flash Support¶
Provides functions for access to flash memory.
-
uint32_t
flashmem_get_address
(const void *memptr)¶ Obtain the flash memory address for a memory pointer.
- Note
- If memptr is not in valid flash memory it will return an offset which exceeds the internal flash memory size.
- Note
- The flash location is dependent on where rBoot has mapped the firmware.
- Parameters
memptr
:
- Return Value
uint32_t
: Offset from start of flash memory
-
uint32_t
flashmem_write
(const void *from, uint32_t toaddr, uint32_t size)¶ Write a block of data to flash.
- Note
- None of the parameters need to be aligned
- Parameters
from
: Buffer to obtain data fromtoaddr
: Flash location to start writingsize
: Number of bytes to write
- Return Value
uint32_t
: Number of bytes written
-
uint32_t
flashmem_read
(void *to, uint32_t fromaddr, uint32_t size)¶ Read a block of data from flash.
- Note
- none of the parameters need to be aligned
- Parameters
to
: Buffer to store datafromaddr
: Flash location to start readingsize
: Number of bytes to read
- Return Value
uint32_t
: Number of bytes written
-
bool
flashmem_erase_sector
(uint32_t sector_id)¶ Erase a single flash sector.
- Parameters
sector_id
: the sector to erase
- Return Value
true
: on success
-
SPIFlashInfo
flashmem_get_info
()¶ Get flash memory information block.
- Return Value
SPIFlashInfo
: Information block
-
uint8_t
flashmem_get_size_type
()¶ Returns a number indicating the size of flash memory chip.
- Return Value
uint8_t
: See SpiFlashInfo.size field for possible values
-
uint32_t
flashmem_get_size_bytes
()¶ get the total flash memory size
- Return Value
uint32_t
: Size in bytes
-
uint16_t
flashmem_get_size_sectors
()¶ Get the total number of flash sectors.
- Return Value
uint16_t
: Sector count
-
uint32_t
flashmem_find_sector
(uint32_t address, uint32_t *pstart, uint32_t *pend)¶ Helper function: find the flash sector in which an address resides.
- Note
- Optional parameters may be null
- Parameters
address
:pstart
: OUT/OPTIONAL: Start of sector containing the given addresspend
: OUT/OPTIONAL: Last address in sector
- Return Value
uint32_t
: Sector number for the given address
-
uint32_t
flashmem_get_sector_of_address
(uint32_t addr)¶ Get sector number containing the given address.
- Parameters
addr
:
- Return Value
uint32_t
: sector number
-
uint32_t
flashmem_write_internal
(const void *from, uint32_t toaddr, uint32_t size)¶ write to flash memory
- Note
- All parameters MUST be aligned to 4-byte word boundaries, including the RAM pointer
- Parameters
from
: Buffer to read data from - MUST be word-alignedtoaddr
: Flash address (offset) to write to - MUST be word-alignedsize
: Number of bytes to write - MUST be word-aligned
- Return Value
uint32_t
: Number of bytes actually written
-
uint32_t
flashmem_read_internal
(void *to, uint32_t fromaddr, uint32_t size)¶ Read from flash memory.
- Note
- All parameters MUST be aligned to 4-byte word boundaries, including the RAM pointer
- Parameters
to
: Buffer to store data - MUST be word-alignedfromaddr
: Flash address (offset) to read from - MUST be word-alignedsize
: Number of bytes to read - MUST be word-aligned
- Return Value
uint32_t
: Number of bytes actually read
-
uint32_t
flashmem_get_first_free_block_address
()¶
-
INTERNAL_FLASH_WRITE_UNIT_SIZE
¶ Flash memory access must be aligned and in multiples of 4-byte words.
-
INTERNAL_FLASH_READ_UNIT_SIZE
¶
-
FLASH_TOTAL_SEC_COUNT
¶
-
SYS_PARAM_SEC_COUNT
¶ Number of flash sectors reserved for system parameters at start.
-
FLASH_WORK_SEC_COUNT
¶
-
INTERNAL_FLASH_SECTOR_SIZE
¶
-
INTERNAL_FLASH_SIZE
¶
-
INTERNAL_FLASH_START_ADDRESS
¶
-
SPI_FLASH_RESULT_OK
¶
-
INTERNAL_FLASH_WRITE_UNIT_SIZE
Flash memory access must be aligned and in multiples of 4-byte words.
-
INTERNAL_FLASH_READ_UNIT_SIZE
-
FLASH_TOTAL_SEC_COUNT
-
SYS_PARAM_SEC_COUNT
Number of flash sectors reserved for system parameters at start.
-
FLASH_WORK_SEC_COUNT
-
INTERNAL_FLASH_SECTOR_SIZE
-
INTERNAL_FLASH_SIZE
-
INTERNAL_FLASH_START_ADDRESS
-
struct
STORE_TYPEDEF_ATTR
¶ - #include <esp_spi_flash.h>
SPI Flash memory information block. Stored at the beginning of flash memory.
Public Types
-
enum
[anonymous]
¶ Values:
-
SIZE_4MBIT
= 0¶
-
SIZE_2MBIT
= 1¶
-
SIZE_8MBIT
= 2¶
-
SIZE_16MBIT
= 3¶
-
SIZE_32MBIT
= 4¶
-
-
enum
[anonymous]
¶ Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
-
enum
[anonymous]
¶ Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
-
enum
[anonymous]
¶ Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
Public Members
-
uint8_t
unknown0
¶
-
uint8_t
unknown1
¶
-
STORE_TYPEDEF_ATTR::[anonymous]
mode
¶
-
STORE_TYPEDEF_ATTR::[anonymous]
speed
¶
-
STORE_TYPEDEF_ATTR::[anonymous]
size
¶
-
STORE_TYPEDEF_ATTR::[anonymous]
mode
-
STORE_TYPEDEF_ATTR::[anonymous]
speed
-
STORE_TYPEDEF_ATTR::[anonymous]
size
-
enum
This is taken from the esp8266 arduino core. For details see:
See Flash memory for some background.
Code is always executed from IRAM, however it must be read in from flash memory on first use which can cause issues within timing-critical code.
This can be avoided by placing the code in IRAM. However, IRAM is a very limited resource and should generally be reserved for interrupt service routines.
An alternative solution is to arrange for critical code to be pre-loaded into IRAM before it starts execution.
Note
This cannot be used for interrupt service routines.
By their nature, interrupts are essentially random events and therefore code must be available in IRAM at any time.
The steps required are:
- Mark the function containing code using
IRAM_PRECACHE_ATTR()
- Place a call to
IRAM_PRECACHE_START()
before the first line of critical code - Place a call to
IRAM_PRECACHE_END()
after the last line of critical code
You must always declare a tag to avoid the risk of section name conflicts.
You can find an example of how precaching is used here:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_spi_utils.cpp
-
void
iram_precache
(void *addr, uint32_t bytes)¶ Pre-load flash data into the flash instruction cache.
- Note
- All pages containing the requested region will be read to pull them into cache RAM.
- Parameters
addr
: First location to cache, specify NULL to use current location.bytes
: Number of bytes to cache
-
IRAM_PRECACHE_ATTR
¶ Tools for pre-loading code into the flash cache.
- It can be useful for code that accesses/uses SPI0 which is connected to the flash chip.
- Non interrupt handler code that is infrequently called but might otherwise require being in valuable IRAM - such as bit-banging I/O code or some code run at bootup can avoid being permanently in IRAM. Mark functions containing critical code using this attribute
-
IRAM_PRECACHE_START
(tag)¶ Place this macro before the first line of the critical code.
- Note
- Do not omit the tag, and be careful with naming to avoid conflicts
- Parameters
tag
: Used to create the precached section name, must be globally unique
-
IRAM_PRECACHE_END
(tag)¶ Place this macro after the last line of critical code.
- Parameters
tag
: Must be the same tag used in IRAM_PRECACHE_START()
-
IRAM_PRECACHE_ATTR
Tools for pre-loading code into the flash cache.
- It can be useful for code that accesses/uses SPI0 which is connected to the flash chip.
- Non interrupt handler code that is infrequently called but might otherwise require being in valuable IRAM - such as bit-banging I/O code or some code run at bootup can avoid being permanently in IRAM. Mark functions containing critical code using this attribute
-
IRAM_PRECACHE_START
(tag) Place this macro before the first line of the critical code.
- Note
- Do not omit the tag, and be careful with naming to avoid conflicts
- Parameters
tag
: Used to create the precached section name, must be globally unique
-
IRAM_PRECACHE_END
(tag) Place this macro after the last line of critical code.
- Parameters
tag
: Must be the same tag used in IRAM_PRECACHE_START()
- Source Code
- Esp32 Core Component Component
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Sming Esp8266 Architecture¶
Support building Sming for the Esp8266 architecture.
Build variables¶
-
ESP_HOME
¶ This contains the base directory for the toolchain used to build the framework.
Components¶
Sming (Esp8266)¶
This Component builds a library containing architecture-specific code, and defines dependencies for Sming to build for the Esp8266.
Default: OFF. In order to use SDK 3.0.0 or newer please follow the instructions here Esp8266 Core Component.
-
DISABLE_WIFI
¶ If a project does not require WiFi (or networking) bulding with this option enabled reduces code size and memory usage signficantly. It does this using an un-official Esp8266 No WiFi Component.
LWIP (LightWeight IP) is a small independent implementation
of the TCP/IP protocol suite used widely in embedded systems. Sming supports several versions of this,
controlled by the ENABLE_CUSTOM_LWIP
setting.
-
ENABLE_CUSTOM_LWIP
¶ - 0
- Use binary Esp8266 LWIP (Espressif) stack.
- 1 (default)
- Use custom compiled Esp8266 Open LWIP (version 1) stack.
Compared with the Espressif stack, this uses less RAM but
consumes FLASH (program) memory. All espconn_* functions are turned off by default, so if you require these add
the
ENABLE_ESPCONN
=1 directive. The Basic Smart Config example sets this in itscomponent.mk
file. - 2
- Use Esp8266 LWIP Version 2 stack. This does not have support for espconn_* functions.
-
ENABLE_LWIP_DEBUG
¶ By default, some debug information will be printed for critical errors and situations. Set this to 1 to enable printing of all debug information.
-
ENABLE_GDB
¶ In order to be able to debug live directly on the ESP8266 microcontroller you should re-compile your application with
ENABLE_GDB=1
directive.- undefined (default)
- Compile normally
- 1
- Compile with debugging support provided by Esp8266 GDBSTUB for Sming. See also the Live Debug sample.
- Source Code
- Esp8266 Drivers Component
- Esp8266 Core Component Component
- Esp8266 WiFi Component
- Esptool Component
- FAT Filing System Component
- Esp8266 GDBSTUB for Sming Component
- Heap Component
- Esp8266 LIBC Component Component
- Esp8266 SPI Flash Support Component
- rBoot Component
- Sming (main) ,Component
Esp8266 Drivers¶
Provides low-level peripheral drivers.
SDK definitions for GPIO.
-
const esp32_gpioMux_t
esp32_gpioMux
[40]
-
const int8_t
esp32_adc2gpio
[20]
-
ESP32_LOW
¶
-
ESP32_HIGH
¶
-
ESP32_INPUT
¶
-
ESP32_OUTPUT
¶
-
ESP32_PULLUP
¶
-
ESP32_INPUT_PULLUP
¶
-
ESP32_PULLDOWN
¶
-
ESP32_INPUT_PULLDOWN
¶
-
ESP32_OPEN_DRAIN
¶
-
ESP32_OUTPUT_OPEN_DRAIN
¶
-
ESP32_SPECIAL
¶
-
ESP32_FUNCTION_1
¶
-
ESP32_FUNCTION_2
¶
-
ESP32_FUNCTION_3
¶
-
ESP32_FUNCTION_4
¶
-
ESP32_FUNCTION_5
¶
-
ESP32_FUNCTION_6
¶
-
ESP32_ANALOG
¶
-
ESP32_DISABLED
¶
-
ESP32_RISING
¶
-
ESP32_FALLING
¶
-
ESP32_CHANGE
¶
-
ESP32_ONLOW
¶
-
ESP32_ONHIGH
¶
-
ESP32_ONLOW_WE
¶
-
ESP32_ONHIGH_WE
¶
-
digitalPinIsValid
(pin)¶
-
digitalPinCanOutput
(pin)¶
-
digitalPinToRtcPin
(pin)¶
-
digitalPinToAnalogChannel
(pin)¶
-
digitalPinToTouchChannel
(pin)¶
-
digitalPinToDacChannel
(pin)¶
-
enum
gpio_driver
::
GPIO_INT_TYPE
Defines the GPIO interrupt type.
Values:
-
GPIO_PIN_INTR_DISABLE
= 0 Interrupt disabled for this pin
-
GPIO_PIN_INTR_POSEDGE
= 1 Interrupt occurs on positive edge
-
GPIO_PIN_INTR_NEGEDGE
= 2 Interrupt occurs on negative edge
-
GPIO_PIN_INTR_ANYEDGE
= 3 Interrupt occurs on both positive and negative edge
-
GPIO_PIN_INTR_LOLEVEL
= 4 Interrupt occurs when GPIO low
-
GPIO_PIN_INTR_HILEVEL
= 5 Interrupt occurs when GPIO high
-
-
struct
esp32_gpioMux_t
- #include <gpio.h>
Public Members
-
uint8_t
reg
GPIO register offset from DR_REG_IO_MUX_BASE
-
int8_t
rtc
RTC GPIO number (-1 if not RTC GPIO pin)
-
int8_t
adc
ADC Channel number (-1 if not ADC pin)
-
int8_t
touch
Touch Channel number (-1 if not Touch pin)
-
uint8_t
Driver for hardware timers.
-
USE_US_TIMER
¶ 0 (default): Use default /256 prescale for Timer2 1: Use /16 prescale
The following functions depend on Timer2: - NOW() return value, the Timer2 tick count - Software timers - System time
Software timers are driven by Timer2, which by default uses a /256 prescale providing a resolution of 3.2us and a range of 1’ 54”.
Enabling this setting increases the resolution to 200ns but reduces the maximum software timer to 7” 9.5s.
-
enum
hw_timer
::
hw_timer_clkdiv_t
Values:
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
-
enum
hw_timer
::
hw_timer_intr_type_t
Values:
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
-
enum
hw_timer
::
hw_timer_source_type_t
Values:
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
-
enum
hw_timer
::
hw_timer_clkdiv_t
Values:
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
TIMER_CLKDIV_1
= 0
-
TIMER_CLKDIV_16
= 4
-
TIMER_CLKDIV_256
= 8
-
-
enum
hw_timer
::
hw_timer_intr_type_t
Values:
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
TIMER_EDGE_INT
= 0
-
TIMER_LEVEL_INT
= 1
-
-
enum
hw_timer
::
hw_timer_source_type_t
Values:
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
TIMER_FRC1_SOURCE
= 0
-
TIMER_NMI_SOURCE
= 1
-
-
typedef void (*
hw_timer_callback_t
)(void *arg)
-
typedef void (*
hw_timer_callback_t
)(void *arg)
-
constexpr uint32_t
HW_TIMER2_CLKDIV
= TIMER_CLKDIV_256
-
constexpr uint32_t
HW_TIMER2_CLK
= HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV
-
constexpr uint32_t
HW_TIMER2_CLKDIV
= TIMER_CLKDIV_256
-
constexpr uint32_t
HW_TIMER2_CLK
= HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV
-
void
hw_timer1_attach_interrupt
(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void *arg) Attach an interrupt for the timer.
- Parameters
source_type
:callback
: Callback function invoked via timer interruptarg
: Passed to callback function
-
void
hw_timer1_enable
(hw_timer_clkdiv_t div, hw_timer_intr_type_t intr_type, bool auto_load) Enable the timer.
- Parameters
div
:intr_type
:auto_load
:
-
void
hw_timer1_write
(uint32_t ticks) Set the timer interval.
- Parameters
ticks
:
-
void
hw_timer1_disable
(void) Disable the timer.
-
void
hw_timer1_detach_interrupt
(void) Detach interrupt from the timer.
-
uint32_t
hw_timer1_read
(void) Get timer1 count.
- Return Value
uint32_t
: Current count value, counts from initial value down to 0
-
uint32_t
hw_timer2_read
(void) Read current timer2 value.
- Return Value
uint32_t
:
-
void
hw_timer2_set_alarm
(uint32_t ticks) Set timer2 alarm count value.
- Note
- For internal use ONLY; used by software timers
- Parameters
ticks
:
-
void
hw_timer_init
(void) Initialise hardware timers.
- Note
- Called by startup code
-
MAX_HW_TIMER1_INTERVAL
¶ Maximum timer interval in ticks.
- Note
- The corresponding time interval depends on the prescaler in use:
/1 - 0.1048s /16 - 1.677s /256 - 26.84s
-
MIN_HW_TIMER1_INTERVAL_US
¶ Minimum hardware interval in microseconds.
- Note
- Attempting to use repetitive interrupts below this level can lead to system instabliity and lockups, due to the software overhead in servicing the interrupts.
-
MAX_HW_TIMER1_INTERVAL
Maximum timer interval in ticks.
- Note
- The corresponding time interval depends on the prescaler in use:
/1 - 0.1048s /16 - 1.677s /256 - 26.84s
-
MIN_HW_TIMER1_INTERVAL_US
Minimum hardware interval in microseconds.
- Note
- Attempting to use repetitive interrupts below this level can lead to system instabliity and lockups, due to the software overhead in servicing the interrupts.
I2S was designed for transfer of digital audio data.
The ESP8266 has two I2S modules (one transmitter and one receiver), both with hardware DMA support, which means transfers from RAM to the hardware SPI FIFO can be handled directly in hardware without any CPU involvement.
The Sming driver deals with the complicated of setting up the hardware, using an API similar to that in the Espressif RTOS SDK. In addition, DMA buffers may be accessed directly to avoid double-buffering and the associated RAM and copy overhead.
Playing MIDI files, MP3 files, speech synthesis, etc. is all possible using the ESP8266, though many audio applications require considerable processing power. That means you may need to disable WiFi and set the processor to run at full 160MHz speed.
High-quality multi-channel audio requires an external I2S DAC, which is what the protocol was designed for in the first place. You may find problems with insufficient RAM, but you can always add external SPI RAM.
More realistic uses include generating simple tones, beeps, playing pre-recorded WAV audio, etc. to supplement existing projects. This can all be done in the background without disrupting the system’s main purpose, whatever that may be.
For such applications you can generate single-channel audio via the I2S OUT pin, using Pulse-density modulation.
See the Tone Generator library for a demonstration of this.
Expand GPIO using low-cost shift registers. https://github.com/lhartmann/esp8266_reprap.
Devices such as WS2812-based NeoPixels use a simple, single-wire protocol. I2S is ideal for this as it can be used to generate a precisely-timed bitstream with very low CPU loading.
-
enum
i2s_driver
::
i2s_bits_per_sample_t
I2S bit width per sample.
Values:
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
-
enum
i2s_driver
::
i2s_channel_t
I2S channel.
Values:
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
-
enum
i2s_driver
::
i2s_comm_format_t
I2S communication standard format.
Values:
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
-
enum
i2s_driver
::
i2s_channel_fmt_t
I2S channel format type.
Values:
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
-
enum
i2s_driver
::
i2s_mode_t
I2S Mode, default is I2S_MODE_MASTER.
Values:
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
-
enum
i2s_driver
::
i2s_event_type_t
I2S event types.
Values:
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
-
enum
i2s_driver
::
i2s_pin_t
I2S pin enable for i2s_set_pin.
Values:
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
-
enum
i2s_driver
::
i2s_bits_per_sample_t
I2S bit width per sample.
Values:
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
I2S_BITS_PER_SAMPLE_8BIT
= 8 I2S bits per sample: 8-bits.
-
I2S_BITS_PER_SAMPLE_16BIT
= 16 I2S bits per sample: 16-bits.
-
I2S_BITS_PER_SAMPLE_24BIT
= 24 I2S bits per sample: 24-bits.
-
-
enum
i2s_driver
::
i2s_channel_t
I2S channel.
Values:
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
I2S_CHANNEL_MONO
= 1 I2S 1 channel (mono)
-
I2S_CHANNEL_STEREO
= 2 I2S 2 channel (stereo)
-
-
enum
i2s_driver
::
i2s_comm_format_t
I2S communication standard format.
Values:
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
I2S_COMM_FORMAT_I2S
= 0x01 I2S communication format I2S.
-
I2S_COMM_FORMAT_I2S_MSB
= 0x01 I2S format MSB.
-
I2S_COMM_FORMAT_I2S_LSB
= 0x03 I2S format LSB.
-
-
enum
i2s_driver
::
i2s_channel_fmt_t
I2S channel format type.
Values:
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
I2S_CHANNEL_FMT_RIGHT_LEFT
= 0x00
-
I2S_CHANNEL_FMT_ALL_RIGHT
-
I2S_CHANNEL_FMT_ALL_LEFT
-
I2S_CHANNEL_FMT_ONLY_RIGHT
-
I2S_CHANNEL_FMT_ONLY_LEFT
-
-
enum
i2s_driver
::
i2s_mode_t
I2S Mode, default is I2S_MODE_MASTER.
Values:
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
I2S_MODE_DISABLED
-
I2S_MODE_MASTER
-
I2S_MODE_SLAVE
-
-
enum
i2s_driver
::
i2s_event_type_t
I2S event types.
Values:
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
I2S_EVENT_DMA_ERROR
-
I2S_EVENT_TX_DONE
I2S DMA finish sent 1 buffer
-
I2S_EVENT_RX_DONE
I2S DMA finish received 1 buffer
-
I2S_EVENT_MAX
I2S event max index
-
-
enum
i2s_driver
::
i2s_pin_t
I2S pin enable for i2s_set_pin.
Values:
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
I2S_PIN_BCK_OUT
= 0x01 GPIO 15 / TXD2 / D8.
-
I2S_PIN_WS_OUT
= 0x02 GPIO 2 / TXD1 / D4.
-
I2S_PIN_DATA_OUT
= 0x04 GPIO 3 / RXD0 / D9.
-
I2S_PIN_BC_IN
= 0x10 GPIO 13 / RXD2 / D7.
-
I2S_PIN_WS_IN
= 0x20 GPIO 14 / D5.
-
I2S_PIN_DATA_IN
= 0x40 GPIO 12 / D6.
-
-
typedef void (*
i2s_callback_t
)(void *param, i2s_event_type_t event) Callback function type.
- Note
- Function is called in interrupt context, so place in IRAM and keep it brief.
-
typedef unsigned
TickType_t
Defines the wait interval (presently milliseconds)
-
typedef uint8_t
i2s_pin_set_t
-
typedef void (*
i2s_callback_t
)(void *param, i2s_event_type_t event) Callback function type.
- Note
- Function is called in interrupt context, so place in IRAM and keep it brief.
-
typedef unsigned
TickType_t
Defines the wait interval (presently milliseconds)
-
typedef uint8_t
i2s_pin_set_t
-
bool
i2s_driver_install
(const i2s_config_t *config) Install and start I2S driver.
- Note
- This function must be called before any I2S driver read/write operations.
- Parameters
config
: I2S configuration
- Return Value
true
: on success, false if already installed or invalid config
-
void
i2s_driver_uninstall
() Uninstall I2S driver.
-
bool
i2s_start
() Start I2S driver.
- Note
- It is not necessary to call this function after i2s_driver_install() as it is started automatically, unless
config.auto_start
was set to false. - Return Value
bool
: true on success, false if driver not initialised
-
bool
i2s_stop
() Stop I2S driver.
- Note
- Disables I2S TX/RX, until i2s_start() is called
- Return Value
bool
: true on success, false if driver not initialised
-
bool
i2s_set_sample_rates
(uint32_t rate) - Parameters
rate
: Sample rate in Hz (ex 44100, 48000) for TX/RX
-
bool
i2s_set_dividers
(uint8_t bck_div, uint8_t mclk_div) Direct control over output rate
-
float
i2s_get_real_rate
() - Return Value
float
: The actual Sample Rate on output
-
bool
i2s_dma_read
(i2s_buffer_info_t *info, size_t max_bytes) Fetch a DMA buffer containing received data (zero-copy)
- Note
- On success,
info->buffer
specifies where to read the data from, andinfo->size
how many bytes are actually available (always > 0). - Note
- Returns at most one DMA buffer
- Parameters
info
: Pointer to structure to receive buffer informationmax_bytes
: Number of bytes to read
- Return Value
bool
: true on success, false if no data available or info is null
-
bool
i2s_dma_write
(i2s_buffer_info_t *info, size_t max_bytes) Fetch a DMA buffer for direct writing (zero-copy)
- Note
- On success,
info->buffer
specifies where to write the data, andinfo->size
how many bytes should be written - may be less than max_bytes, but always > 0. - Note
- Returns at most one DMA buffer
- Parameters
info
: Pointer to structure to receive buffer informationmax_bytes
: Number of bytes required in buffer
- Return Value
bool
: true on success, false if buffer unavailable or info is null
-
size_t
i2s_write
(const void *src, size_t size, TickType_t ticks_to_wait) writes a buffer of frames into the DMA memory, returns the amount of frames written.
- Note
- Data is copied into DMA buffers
- Parameters
src
: Data to writesize
: Size in bytesticks_to_wait
: Wait timeout in ticks
- Return Value
size_t
: Data actually written, may be less than size
-
size_t
i2s_read
(void *dest, size_t size, TickType_t ticks_to_wait) Reads a block of received data.
- Parameters
dest
: Buffer to store datasize
: Max. bytes to readticks_to_wait
: Wait timeout in ticks
- Return Value
size_t
: Number of bytes read
-
bool
i2s_zero_dma_buffer
() Zero the contents of the TX DMA buffer.
- Note
- Pushes zero-byte samples into the TX DMA buffer, until it is full
-
void
i2s_set_pins
(i2s_pin_set_t pins, bool enable) Configure I2S pins.
You can alternatively use arduino functions.
- Note
- Call this after initialising driver to specify which pins are required
- Parameters
pins
: Mask of i2s_pin_t valuesenable
: true to enable for I2S use, false to revert to GPIO
Example: i2s_set_pins(_BV(I2S_BCK_OUT), true)
-
bool
i2s_enable_loopback
(bool enable)
-
bool
i2s_stat_tx
(i2s_buffer_stat_t *stat) Obtain state information for TX buffers.
- Parameters
stat
:
- Return Value
bool
: true on success
-
bool
i2s_stat_rx
(i2s_buffer_stat_t *stat) Obtain state information for RX buffers.
- Parameters
stat
:
- Return Value
bool
: true on success
-
union
i2s_sample_t
- #include <i2s.h>
I2S sample.
An I2S frame can contain various types of data:
8-bit, 16-bit or 24-bit mono samples 8-bit or 16-bit stereo samples
Public Members
-
uint32_t
u32
-
int16_t
left
-
int16_t
right
-
struct i2s_sample_t::[anonymous] [anonymous]
-
struct i2s_sample_t::[anonymous] [anonymous]
-
uint32_t
-
struct
i2s_module_config_t
- #include <i2s.h>
I2S module configuration (TX or RX)
Public Members
-
i2s_mode_t
mode
I2S work mode (combination of i2s_mode_t)
-
i2s_bits_per_sample_t
bits_per_sample
I2S bits per sample.
-
i2s_channel_fmt_t
channel_format
I2S channel format.
-
i2s_comm_format_t
communication_format
I2S communication format.
-
uint16_t
dma_buf_len
I2S DMA Buffer Length (in samples)
-
uint8_t
dma_buf_count
I2S DMA Buffer Count.
-
uint8_t
callback_threshold
TX: callback when available buffers > threshold RX: Callback when slc_queue_len > threshold
-
i2s_mode_t
-
struct
i2s_config_t
- #include <i2s.h>
I2S configuration parameters.
Public Members
-
i2s_module_config_t
tx
TX module configuration.
-
i2s_module_config_t
rx
RX module configuration.
-
unsigned
sample_rate
I2S sample rate.
-
bool
tx_desc_auto_clear
I2S auto clear tx descriptor if there is underflow condition (Mutes output)
-
bool
auto_start
Start immediately on successful initialisation.
-
i2s_callback_t
callback
Callback handler.
-
void *
param
Callback parameter.
-
uint8_t
bits_mod
Evaluate what this does (4 bits)
-
i2s_module_config_t
-
struct
i2s_buffer_info_t
- #include <i2s.h>
Defines a buffer with available content.
Public Members
-
void *
buffer
-
i2s_sample_t *
samples
-
union i2s_buffer_info_t::[anonymous] [anonymous]
-
size_t
size
Available space (TX) or data (RX) in bytes.
-
uint16_t
buf
-
uint16_t
pos
-
union i2s_buffer_info_t::[anonymous] [anonymous]
-
void *
-
struct
i2s_buffer_stat_t
- #include <i2s.h>
Contains I2S buffer status information.
- Note
- Size excludes buffer in use by DMA
Public Members
-
uint16_t
size
-
uint16_t
used
-
void
os_timer_arm_ticks
(os_timer_t *ptimer, uint32_t ticks, bool repeat_flag) Set a software timer using the Timer2 tick value.
This function has been added to Sming for more efficient and flexible use of software timers. It can be used alongside the SDK
os_timer_arm_new()
function.- Parameters
ptimer
: Timer structureticks
: Tick count duration for the timerrepeat_flag
: true if timer will automatically repeat
The driver interface is defined in the ESP8266 SDK.
-
ENABLE_CUSTOM_PWM
¶ - undefined
- use the Espressif PWM driver
- 1 (default)
- Use the New PWM driver, a drop-in replacement for the version provided in the Espressif SDK.
-
void
pwm_init
(uint32 period, uint32 *duty, uint32 pwm_channel_num, uint32 (*pin_info_list)[3]) Initialize PWM function, including GPIO selection, period and duty cycle.
Example:
uint32 io_info[][3] = { {PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC, PWM_0_OUT_IO_NUM}, {PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC, PWM_1_OUT_IO_NUM}, {PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC, PWM_2_OUT_IO_NUM} }; pwm_init(light_param.pwm_period, light_param.pwm_duty, 3, io_info);
- Note
- This API can be called only once.
- Parameters
period
: PWM periodduty
: duty cycle of each outputpwm_channel_num
: PWM channel numberpin_info_list
: Array containing an entry for each channel giving
-
void
pwm_start
(void) Starts PWM.
This function needs to be called after PWM configuration is changed.
-
void
pwm_set_duty
(uint32 duty, uint8 channel) Sets duty cycle of a PWM output.
Set the time that high-level signal will last. The range of duty depends on PWM period. Its maximum value of which can be Period * 1000 / 45.
- Parameters
duty
: The time that high-level single will last, duty cycle will be (duty*45)/(period*1000)channel
: PWM channel, which depends on how many PWM channels are used
For example, for 1-KHz PWM, the duty range is 0 ~ 22222.
-
uint32
pwm_get_duty
(uint8 channel) Get duty cycle of PWM output.
Duty cycle will be (duty*45) / (period*1000).
- Parameters
channel
: PWM channel, which depends on how many PWM channels are used
- Return Value
uint32
: Duty cycle of PWM output
-
void
pwm_set_period
(uint32 period) Set PWM period.
- Parameters
period
: PWM period in us. For example, 1-KHz PWM period = 1000us.
-
uint32
pwm_get_period
(void) Get PWM period.
- Return Value
uint32
: Return PWM period in us.
-
uint32
get_pwm_version
(void) Get version information of PWM.
- Return Value
uint32
: PWM version
Custom asynchronous driver.
-
enum
uart_driver
::
smg_uart_mode_
values for
mode
argument of uart_initValues:
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
-
enum
uart_driver
::
smg_uart_option_bits_t
bit values for
options
argument of uart_init- Note
- use _BV(opt) to specify values
Values:
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
enum
uart_driver
::
smg_uart_notify_code_t
Indicates notification, parameters refer to uart_notify_info_t structure.
Values:
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been initialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been iniitialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
-
enum
uart_driver
::
smg_uart_mode_
values for
mode
argument of uart_initValues:
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
UART_FULL
Both receive and transmit - will revert to TX only if RX not supported.
-
UART_RX_ONLY
Receive only.
-
UART_TX_ONLY
Transmit only.
-
-
enum
uart_driver
::
smg_uart_option_bits_t
bit values for
options
argument of uart_init- Note
- use _BV(opt) to specify values
Values:
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
UART_OPT_TXWAIT
If buffers are full then uart_write() will wait for free space.
-
UART_OPT_CALLBACK_RAW
ISR invokes user callback function with no pre-processing.
-
enum
uart_driver
::
smg_uart_notify_code_t
Indicates notification, parameters refer to uart_notify_info_t structure.
Values:
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been initialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
UART_NOTIFY_AFTER_OPEN
Called when uart has been iniitialised successfully.
-
UART_NOTIFY_BEFORE_CLOSE
Called immediately before uart is closed and destroyed.
-
UART_NOTIFY_AFTER_WRITE
Called after data has been written into tx buffer.
-
UART_NOTIFY_BEFORE_READ
Called before data is read from rx buffer.
-
UART_NOTIFY_WAIT_TX
Called to ensure all buffered data is output.
-
-
typedef enum smg_uart_mode_
smg_uart_mode_t
-
typedef uint8_t
uart_options_t
-
typedef struct smg_uart_
smg_uart_t
-
typedef void (*
smg_uart_callback_t
)(smg_uart_t *uart, uint32_t status) callback invoked directly from ISR
Errors can be detected via uart_get_status().
- Note
- Values can be: UIFE: TX FIFO Empty UIFF: RX FIFO Full UITO: RX FIFO Timeout UIBD: Break Detected
- Parameters
arg
: the UART objectstatus
: UART USIS STATUS flag bits indicating cause of interrupt
-
typedef void (*
smg_uart_notify_callback_t
)(smg_uart_t *uart, smg_uart_notify_code_t code) Port notification callback function type.
- Parameters
info
:
- Return Value
bool
: true if callback handled operation, false to default to normal operation
-
typedef enum smg_uart_mode_
smg_uart_mode_t
-
typedef uint8_t
uart_options_t
-
typedef struct smg_uart_
smg_uart_t
-
typedef void (*
smg_uart_callback_t
)(smg_uart_t *uart, uint32_t status) callback invoked directly from ISR
Errors can be detected via uart_get_status().
- Note
- Values can be: UIFE: TX FIFO Empty UIFF: RX FIFO Full UITO: RX FIFO Timeout UIBD: Break Detected
- Parameters
arg
: the UART objectstatus
: UART USIS STATUS flag bits indicating cause of interrupt
-
typedef void (*
smg_uart_notify_callback_t
)(smg_uart_t *uart, smg_uart_notify_code_t code) Port notification callback function type.
- Parameters
info
:
- Return Value
bool
: true if callback handled operation, false to default to normal operation
-
bool
smg_uart_set_notify
(unsigned uart_nr, smg_uart_notify_callback_t callback) Set the notification callback function.
- Parameters
uart_nr
: Which uart to register notifications forcallback
:
- Return Value
bool
: true on success
-
smg_uart_t *
smg_uart_init
(uint8_t uart_nr, uint32_t baudrate, uint32_t config, smg_uart_mode_t mode, uint8_t tx_pin, size_t rx_size, size_t tx_size = 0)
-
smg_uart_t *
smg_uart_init_ex
(const smg_uart_config &cfg)
-
void
smg_uart_uninit
(smg_uart_t *uart)
-
int
smg_uart_get_nr
(smg_uart_t *uart)
-
smg_uart_t *
smg_uart_get_uart
(uint8_t uart_nr) Get the uart structure for the given number.
- Parameters
uart_nr
:
- Return Value
uart_t*
: Returns nullptr if uart isn’t initialised
-
void
smg_uart_set_callback
(smg_uart_t *uart, smg_uart_callback_t callback, void *param) Set callback handler for serial port.
- Parameters
uart
:callback
: specify nullptr to disable callbacksparam
: user parameter passed to callback
-
void *
smg_uart_get_callback_param
(smg_uart_t *uart) Get the callback parameter specified by uart_set_callback()
- Parameters
uart
:
- Return Value
void*
: the callback parameter
-
static void
smg_uart_set_options
(smg_uart_t *uart, uart_options_t options) Set option flags.
- Parameters
uart
:options
: The option(s) to set
-
uint8_t
smg_uart_get_status
(smg_uart_t *uart) Get error flags and clear them.
- Note
- To detect errors during a transaction, call at the start to clear the flags, then check the value at the end. Only these values are cleared/returned: UIBD: Break Detected UIOF: RX FIFO OverFlow UIFR: Frame Error UIPE: Parity Error
- Parameters
uart
:
- Return Value
Status
: error bits:
-
static uart_options_t
smg_uart_get_options
(smg_uart_t *uart)
-
void
smg_uart_swap
(smg_uart_t *uart, int tx_pin)
-
void
smg_uart_set_tx
(smg_uart_t *uart, int tx_pin)
-
void
smg_uart_set_pins
(smg_uart_t *uart, int tx, int rx)
-
bool
smg_uart_tx_enabled
(smg_uart_t *uart)
-
bool
smg_uart_rx_enabled
(smg_uart_t *uart)
-
uint32_t
smg_uart_set_baudrate_reg
(int uart_nr, uint32_t baud_rate) set UART baud rate, given the UART number
- Parameters
uart_nr
:baud_rate
: requested baud rate
- Return Value
uint32_t
: actual baudrate used, 0 on failure
-
uint32_t
smg_uart_set_baudrate
(smg_uart_t *uart, uint32_t baud_rate) set UART baud rate
- Parameters
uart
:baud_rate
: requested baud rate
- Return Value
uint32_t
: actual baudrate used, 0 on failure
-
uint32_t
smg_uart_get_baudrate
(smg_uart_t *uart) get the actual baud rate in use
- Parameters
uart
:
- Return Value
uint32_t
: the baud rate, 0 on failure
-
size_t
smg_uart_resize_rx_buffer
(smg_uart_t *uart, size_t new_size)
-
size_t
smg_uart_rx_buffer_size
(smg_uart_t *uart)
-
size_t
smg_uart_resize_tx_buffer
(smg_uart_t *uart, size_t new_size)
-
size_t
smg_uart_tx_buffer_size
(smg_uart_t *uart)
-
size_t
smg_uart_write
(smg_uart_t *uart, const void *buffer, size_t size) write a block of data
- Parameters
uart
:buffer
:size
:
- Return Value
size_t
: number of bytes buffered for transmission
-
static size_t
smg_uart_write_char
(smg_uart_t *uart, char c) queue a single character for output
- Parameters
uart
:c
:
- Return Value
size_t
: 1 if character was written, 0 on failure
-
size_t
smg_uart_read
(smg_uart_t *uart, void *buffer, size_t size) read a block of data
- Parameters
uart
:buffer
: where to write the datasize
: requested quantity of bytes to read
- Return Value
size_t
: number of bytes read
-
static int
smg_uart_read_char
(smg_uart_t *uart) read a received character
- Parameters
uart
:
- Return Value
the
: character, -1 on failure
-
int
smg_uart_peek_char
(smg_uart_t *uart) see what the next character in the rx buffer is
- Note
- if buffer isn’t allocated data may be in the hardware FIFO, which must be read out using uart_read()
- Parameters
uart
:
- Return Value
int
: returns -1 if buffer is empty or not allocated
-
int
smg_uart_peek_last_char
(smg_uart_t *uart) fetch last character read out of FIFO
- Note
- this is only useful if an rx buffer has been allocated of sufficient size to contain a message. This function then indicates the terminating character.
- Parameters
uart
:
- Return Value
int
: the character, or -1 if rx buffer is empty or unallocated
-
int
smg_uart_rx_find
(smg_uart_t *uart, char c)
-
size_t
smg_uart_rx_available
(smg_uart_t *uart) determine available data which can be read
- Note
- this obtains a count of data both in the memory buffer and hardware FIFO
- Parameters
uart
:
- Return Value
size_t
:
-
size_t
smg_uart_tx_free
(smg_uart_t *uart) return free space in transmit buffer
-
void
smg_uart_wait_tx_empty
(smg_uart_t *uart)
-
void
smg_uart_set_break
(smg_uart_t *uart, bool state) Set or clear a break condition on the TX line.
- Parameters
uart
:state
:
-
void
smg_uart_flush
(smg_uart_t *uart, smg_uart_mode_t mode = UART_FULL) discard any buffered data and reset hardware FIFOs
- Note
- this function does not wait for any transmissions to complete
- Parameters
uart
:mode
: Whether to flush TX, RX or both (the default)
-
void
smg_uart_set_debug
(int uart_nr)
-
int
smg_uart_get_debug
()
-
void
smg_uart_start_isr
(smg_uart_t *uart) enable interrupts for a UART
- Parameters
uart
:
-
void
smg_uart_stop_isr
(smg_uart_t *uart) disable interrupts for a UART
- Parameters
uart
:
-
void
smg_uart_detach
(int uart_nr) detach a UART interrupt service routine
- Parameters
uart_nr
:
-
void
smg_uart_detach_all
() detach all UART interrupt service routines
- Note
- call at startup to put all UARTs into a known state
-
uint8_t
smg_uart_disable_interrupts
() disable interrupts and return current interrupt state
- Return Value
state
: non-zero if any UART interrupts were active
-
void
smg_uart_restore_interrupts
() re-enable interrupts after calling uart_disable_interrupts()
-
UART0
¶
-
UART1
¶
-
UART2
¶ Virtualised UART0.
-
UART_NO
¶ No UART specified.
-
UART_PHYSICAL_COUNT
¶ Number of physical UARTs on the system.
-
UART_COUNT
¶ Number of UARTs on the system, virtual or otherwise.
-
UART_NB_BIT_MASK
¶
-
UART_NB_BIT_5
¶
-
UART_NB_BIT_6
¶
-
UART_NB_BIT_7
¶
-
UART_NB_BIT_8
¶
-
UART_PARITY_MASK
¶
-
UART_PARITY_NONE
¶
-
UART_PARITY_EVEN
¶
-
UART_PARITY_ODD
¶
-
UART_NB_STOP_BIT_MASK
¶
-
UART_NB_STOP_BIT_0
¶
-
UART_NB_STOP_BIT_1
¶
-
UART_NB_STOP_BIT_15
¶
-
UART_NB_STOP_BIT_2
¶
-
UART_5N1
¶
-
UART_6N1
¶
-
UART_7N1
¶
-
UART_8N1
¶
-
UART_5N2
¶
-
UART_6N2
¶
-
UART_7N2
¶
-
UART_8N2
¶
-
UART_5E1
¶
-
UART_6E1
¶
-
UART_7E1
¶
-
UART_8E1
¶
-
UART_5E2
¶
-
UART_6E2
¶
-
UART_7E2
¶
-
UART_8E2
¶
-
UART_5O1
¶
-
UART_6O1
¶
-
UART_7O1
¶
-
UART_8O1
¶
-
UART_5O2
¶
-
UART_6O2
¶
-
UART_7O2
¶
-
UART_8O2
¶
-
UART_RX_FIFO_SIZE
¶
-
UART_TX_FIFO_SIZE
¶
-
UART0
-
UART1
-
UART2
Virtualised UART0.
-
UART_NO
No UART specified.
-
UART_PHYSICAL_COUNT
Number of physical UARTs on the system.
-
UART_COUNT
Number of UARTs on the system, virtual or otherwise.
-
UART_NB_BIT_MASK
-
UART_NB_BIT_5
-
UART_NB_BIT_6
-
UART_NB_BIT_7
-
UART_NB_BIT_8
-
UART_PARITY_MASK
-
UART_PARITY_NONE
-
UART_PARITY_EVEN
-
UART_PARITY_ODD
-
UART_NB_STOP_BIT_MASK
-
UART_NB_STOP_BIT_0
-
UART_NB_STOP_BIT_1
-
UART_NB_STOP_BIT_15
-
UART_NB_STOP_BIT_2
-
UART_5N1
-
UART_6N1
-
UART_7N1
-
UART_8N1
-
UART_5N2
-
UART_6N2
-
UART_7N2
-
UART_8N2
-
UART_5E1
-
UART_6E1
-
UART_7E1
-
UART_8E1
-
UART_5E2
-
UART_6E2
-
UART_7E2
-
UART_8E2
-
UART_5O1
-
UART_6O1
-
UART_7O1
-
UART_8O1
-
UART_5O2
-
UART_6O2
-
UART_7O2
-
UART_8O2
-
UART_RX_FIFO_SIZE
-
UART_TX_FIFO_SIZE
-
struct
smg_uart_
- #include <uart.h>
Public Members
-
uint8_t
uart_nr
-
uint32_t
baud_rate
-
smg_uart_mode_t
mode
-
uint8_t
options
-
uint8_t
rx_pin
-
uint8_t
tx_pin
-
uint8_t
rx_headroom
Callback when rx_buffer free space <= headroom.
-
uint16_t
status
All status flags reported to callback since last uart_get_status() call.
-
struct SerialBuffer *
rx_buffer
Optional receive buffer.
-
struct SerialBuffer *
tx_buffer
Optional transmit buffer.
-
smg_uart_callback_t
callback
Optional User callback routine.
-
void *
param
User-supplied callback parameter.
-
uart_port_t
uart_nr
-
uint8_t
-
struct
smg_uart_config
- #include <uart.h>
Public Members
-
uint8_t
uart_nr
-
uint8_t
tx_pin
Specify 2 for alternate pin, otherwise defaults to pin 1.
-
smg_uart_mode_t
mode
Whether to enable receive, transmit or both.
-
uart_options_t
options
-
uint32_t
baudrate
Requested baudrate; actual baudrate may differ.
-
uint32_t
config
UART CONF0 register bits.
-
size_t
rx_size
-
size_t
tx_size
-
uint8_t
rx_pin
-
uint8_t
- Source Code
- Esp8266 Core Component Component
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
This is a drop-in replacement for the ESP8266 SDK PWM
If you like this project and want to support this and my other works, consider donating on Liberapay
The software PWM provided in the ESP8266 SDK from Espressif has several drawbacks:
- Duty cycle limited to 90% (at 1kHz PWM period)
- usable PWM period at most ~2KHz.
- Incomplete documentation
This replacement allows duty cycles from 0% to 100%, with a stepsize of 200ns. This is 5000 steps for a 1kHz PWM, and 256 steps (8 bit of resolution) at 19kHz.
If all channels are in steady state (either 0% of 100% in any combination), the implementation goes to full idle, e.g. no interrupts.
The code is a drop-in replacement for the SDK, it provides the same functions as the SDK libpwm.a closed binary library. Just add pwm.c to your project.
By default there is one small difference to the SDK. The code uses a unit of 200ns for both period and duty. E.g. for 10% duty cycle at 1kHz you need to specify a period value of 5000 and a duty cycle value of 500, a duty cycle of 5000 or above switches the channel to full on.
To have full compatibility with the SDK, you have to set the SDK_PWM_PERIOD_COMPAT_MODE define to 1. If set, the code will use 1us for PWM period and 40ns for the duty cycle. E.g. 10% duty cycle at 1kHz is set by a period value of 1000 and a duty cycle value of 2500, full duty at 25000 and above.
Example usage:
#define PWM_CHANNELS 5
const uint32_t period = 5000 // * 200ns ^= 1 kHz
// PWM setup
uint32 io_info[PWM_CHANNELS][3] = {
// MUX, FUNC, PIN
{PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12, 12},
{PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15, 15},
{PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13, 13},
{PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14, 14},
{PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5 , 5},
};
// initial duty: all off
uint32 pwm_duty_init[PWM_CHANNELS] = {0, 0, 0, 0, 0};
pwm_init(period, pwm_duty_init, PWM_CHANNELS, io_info);
pwm_start();
// do something like this whenever you want to change duty
pwm_set_duty(500, 1); // GPIO15: 10%
pwm_set_duty(5000, 1); // GPIO15: 100%
pwm_start(); // commit
CAVEATS
- To set 100% duty, the duty must be *equal* to the period
- The code uses the TIMER1 interrupt. If you use e.g. the softtimer, there is a conflict. You can use NM1 for the PWM instead.
Esp8266 LWIP (Espressif)¶
The Espressif SDK provides a default version of LWIP, enabled by using this Component.
See ENABLE_CUSTOM_LWIP
.
- Source Code
- Esp8266 Core Component Component
Esp8266 Open LWIP (version 1)¶
This Component provides the default Sming LWIP stack, which uses less RAM than the Espressif version.
See ENABLE_CUSTOM_LWIP
.
-
ENABLE_LWIPDEBUG
¶ - 0 (default)
- Standard build
- 1
- Enable debugging output
You can increase debugging for certain areas by modifying debug options in
esp-open-lwip/include/lwipopts.h
.
-
ENABLE_ESPCONN
¶ The Espressif SDK defines a network API consisting of functions which start with
espconn_
.- 0 (default)
- Disabled
- 1
- Enable espconn_ functions
- Source Code
- Esp8266 Core Component Component
Esp8266 Core Component¶
Contains startup code, crash handling and additional Esp8266-specific support code. Sming may be built using a pre-installed SDK, or by using the current version 3 SDK as a submodule.
Attention
At time of writing, SDK 3 does not appear to support use of devices with 256K or 512K memory, such as the ESP-01. For now, please use the default SDK 1.5.4 or SDK 2.0.0.
-
SDK_BASE
¶ Points to the location of the Espressif Non-OS SDK. To use the Espressif version 3 SDK, you need only set this variable to point at the Sming repository (
SMING_HOME
). The actual location will be subsituted by the build system and the SDK pulled in via GIT.So for Windows you need to do:
set SDK_BASE=%SMING_HOME%
For Linux (bash):
export SDK_BASE="$SMING_HOME"
If you change this value then your application and Sming must both be recompiled:
make components-clean clean make
-
SDK_INTERNAL
¶ READONLY When compiled using the current (version 3+) Espressif SDK this value is set to 1.
-
SDK_LIBDIR
¶ READONLY Path to the directory containing SDK archive libraries
-
SDK_INCDIR
¶ READONLY Path to the directory containing SDK header files
- Esp8266 Drivers ,Component
- Esp8266 LWIP (Espressif) ,Component
- Esp8266 Open LWIP (version 1) ,Component
- Esp8266 WiFi ,Component
- Esptool ,Component
- Esp8266 GDBSTUB for Sming ,Component
- Esp8266 LWIP Version 2 ,Component
- Sming (Esp8266) ,Component
- Esp8266 SPI Flash Support ,Component
Starting from December 2019,
- We will not add any new features to the ESP8266 NonOS SDK.
- We will only fix critical bugs in the ESP8266 NonOS SDK.
- We will only maintain the master branch of ESP8266 NonOS SDK, which is a continuously bug-fix version based on v3.0. This means:
- All other released branches will not be updated.
- All the future versions will be released from only the master branch mentioned above.
- It is suggested that the ESP8266_RTOS_SDK, instead of ESP8266 NonOS SDK, be used for your projects.
The latest ESP8266_RTOS_SDK allows users to develop applications using an architecture that are compatible with the SDKs of all Espressif chips, including ESP8266 series, ESP32 series, and the upcoming new series of chips. Switching to ESP8266_RTOS_SDK will helps users to:
- Eliminate the necessity to maintain more than one applications (for different chips), thus greatly reducing maintenance costs.
- Easily switch to other Espressif chips in the future for enhanced flexibility, less dependency, and reduced time-to-market.
Thank you for your interest in Espressif products.
自 2019 年 12 月起,我们将:
- 停止为 ESP8266 NonOS 新增任何功能。
- 仅修复 ESP8266 NonOS 的关键 bug。
- 所有更新仅在 master 分支进行,即基于 v3.0.0 的持续 bug 修复版本。这意味着:
- 其他任何 release 分支均不再提供维护;
- 所有更新均将通过上述 master 分支发布。
- 建议客户使用新版 ESP8266_RTOS_SDK。
简单来说,新版 ESP8266_RTOS_SDK 可帮助客户避免对单一 SDK 的依赖,允许客户应用程序同时兼容多款乐鑫芯片,包括 ESP8266 系列、ESP32 系列以及未来发布的新产品。使用 ESP8266_RTOS_SDK 允许客户:
- 避免同时维护针对不同芯片的多套应用程序,从而降低维护成本。
- 未来可轻松切换至其他乐鑫芯片,从而提高灵活性、降低对单一芯片的依赖,并缩短上市时间。
感谢大家对乐鑫的支持与关注。
All documentations @ http://espressif.com/en/support/download/documents?keys=&field_type_tid%5B%5D=14
Please add user_pre_init()
in your project, which will be called before user_init()
. And you MUST call system_partition_table_regist()
in user_pre_init
to register your project partition table.
The following partition address CAN NOT be modified, and you MUST give the correct address. They are retated to the flash map, please refer to ESP8266 SDK Getting Started Guide or ESP8266 SDK 入门指南.
- SYSTEM_PARTITION_BOOTLOADER
- SYSTEM_PARTITION_OTA_1
- SYSTEM_PARTITION_OTA_2
- SYSTEM_PARTITION_SYSTEM_PARAMETER
If you donot use Non-FOTA bin, eagle.irom0.text.bin and irom0.text MUST be downloaded the fixed address, which also can be found in ESP8266 SDK Getting Started Guide or ESP8266 SDK 入门指南, and you can define their partition type after SYSTEM_PARTITION_CUSTOMER_BEGIN
.
Esp8266 No WiFi¶
Based on SDK 3.0.1 disassemblies with reference and thanks to:
- https://github.com/pvvx/esp8266web Further development of
- https://github.com/cnlohr/nosdk8266
The problem we have is to disentangle the wifi functions from the SDK within the
app_main.o
and user_interface.o
modules from libmain.a
.
In particular, the user_start()
code which mixes up
wifi stuff with system code so it cannot be easily separated.
The SDKnoWiFi implements the startup code and some system functions but contains a lot of stuff which is provided by the SDK and in other parts of the Sming framework. We need to provide replacement functions to interoperate correctly with the remaining SDK code.
This is the approach used to create this Component.
Remove user_interface from libmain:
ar d libmain.a user_interface.o
Implement
call_user_start_local
. The actual entry point iscall_user_start
, in vector.o, which is required. (Note: This symbol was -u in the linker script but this is un-necessary and has been removed.)Build and implement missing functions.
Where functions can be passed directly to the ROM code (e.g. system_os_task -> ets_task) these are defined in the no.wifi.ld linker script.
Other code is located in a .c file named according to the module it replaces in libmain.a.
There are various options for integrating this into Sming, but I’ve decided the most useful
way is to have it as a link-time option. We either link esp_wifi
or esp_no_wifi
as required, no rebuild to the framework is necessary. This is controlled by the
DISABLE_WIFI
setting.
This means that if there are any WiFi routines used in the project the link step will fail.
An alternate approach is to separate out the Network/WiFi stuff in the framework into separate Components which are themselves only included. However, some of the network code could be useful in a non-networked application. There may even be an alternate physical network layer implemented (e.g. Ethernet over SPI) so it’s simplest to just leave the framework intact.
You can create a disassembly of the relevant SDK libraries for inspection by running this command from a project directory:
make sdk-disassemble
If you want to disassemble other SDK libraries, do this:
make sdk-disassemble SDK_LIBLIST="crypto net80211"
Further work is required to implement the following (list incomplete):
- Sleep/power saving modes
- Partition tables
- Analogue reading
Esp8266 WiFi¶
All related libraries for WiFi support. Definitions are provided in the Espressif Non-OS SDK.
- Source Code
- Esp8266 Core Component Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Esptool¶
This Component provides Espressif’s tool for reading and writing firmware and other data to hardware.
-
SPI_SPEED
¶ Clock speed for flash memory (20, 26, 40 or 80). Default is 40.
-
SPI_MODE
¶ Flash memory operating mode (quot, dio, dout, qio). Default is qio.
-
SPI_SIZE
¶ Size of flash memory chip (256KB, 512KB, 1MB, 2MB, 4MB). Default is 512K bytes.
-
ESPTOOL
¶ Full path of esptool.py
- Source Code
- Esp8266 Core Component Component
- Sming (Esp8266) ,Component
A Python-based, open source, platform independent, utility to communicate with the ROM bootloader in Espressif ESP8266 & ESP32 chips.
esptool.py was started by Fredrik Ahlberg (@themadinventor) as an unofficial community project. It is now also supported by Espressif. Current primary maintainer is Angus Gratton (@projectgus).
esptool.py is Free Software under a GPLv2 license.
You will need either Python 2.7 or Python 3.4 or newer installed on your system.
The latest stable esptool.py release can be installed from pypi via pip:
$ pip install esptool
With some Python installations this may not work and you’ll receive an error, try python -m pip install esptool
or pip2 install esptool
.
After installing, you will have esptool.py
installed into the default Python executables directory and you should be able to run it with the command esptool.py
.
Manual installation allows you to run the latest development version from this repository.
esptool.py depends on pySerial version 3.0 or newer for serial communication with the target device.
If you choose to install esptool.py system-wide by running python setup.py install
, then this will be taken care of automatically.
If not using setup.py
, then you’ll have to install pySerial manually by running something like pip install pyserial
, easy_install pyserial
or apt-get install python-serial
, depending on your platform. (The official pySerial installation instructions are here).
esptool.py also bundles the pyaes & ecdsa Python modules as “vendored” libraries. These modules are required when using the ESP32-only espsecure.py
and espefuse.py
tools. If you install esptool.py via pip
or setup.py
as shown above, then versions of these libraries will be installed from pypi. If you run esptool.py from the repository directory directly, it will use the “vendored” versions.
Use esptool.py -h
to see a summary of all available commands and command line options.
To see all options for a particular command, append -h
to the command name. ie esptool.py write_flash -h
.
- The serial port is selected using the
-p
option, like-p /dev/ttyUSB0
(Linux and macOS) or-p COM1
(Windows). - A default serial port can be specified by setting the
ESPTOOL_PORT
environment variable. - If no
-p
option orESPTOOL_PORT
value is specified,esptool.py
will enumerate all connected serial ports and try each one until it finds an Espressif device connected (new behaviour in v2.4.0).
Note: Windows and macOS may require drivers to be installed for a particular USB/serial adapter, before a serial port is available. Consult the documentation for your particular device. On macOS, you can also consult System Information’s list of USB devices to identify the manufacturer or device ID when the adapter is plugged in. On Windows, you can use Windows Update or Device Manager to find a driver.
If using Cygwin or WSL on Windows, you have to convert the Windows-style name into an Unix-style path (COM1
-> /dev/ttyS0
, and so on). (This is not necessary if using esp-idf for ESP32 with the supplied Windows MSYS2 environment, this environment uses a native Windows Python which accepts COM ports as-is.)
In Linux, the current user may not have access to serial ports and a “Permission Denied” error will appear. On most Linux distributions, the solution is to add the user to the dialout
group with a command like sudo usermod -a -G dialout <USERNAME>
. Check your Linux distribution’s documentation for more information.
The default esptool.py baud rate is 115200bps. Different rates may be set using -b 921600
(or another baudrate of your choice). A default baud rate can also be specified using the ESPTOOL_BAUD
environment variable. This can speed up write_flash
and read_flash
operations.
The baud rate is limited to 115200 when esptool.py establishes the initial connection, higher speeds are only used for data transfers.
Most hardware configurations will work with -b 230400
, some with -b 460800
, -b 921600
and/or -b 1500000
or higher.
If you have connectivity problems then you can also set baud rates below 115200. You can also choose 74880, which is the usual baud rate used by the ESP8266 to output boot log information.
Binary data can be written to the ESP’s flash chip via the serial write_flash
command:
esptool.py --port COM4 write_flash 0x1000 my_app-0x01000.bin
Multiple flash addresses and file names can be given on the same command line:
esptool.py --port COM4 write_flash 0x00000 my_app.elf-0x00000.bin 0x40000 my_app.elf-0x40000.bin
The --chip
argument is optional when writing to flash, esptool will detect the type of chip when it connects to the serial port.
The --port
argument is documented under Serial Port.
The next arguments to write_flash are one or more pairs of offset (address) and file name. When generating ESP8266 “version 1” images, the file names created by elf2image
include the flash offsets as part of the file name. For other types of images, consult your SDK documentation to determine the files to flash at which offsets.
Numeric values passed to write_flash (and other commands) can be specified either in hex (ie 0x1000), or in decimal (ie 4096).
See the Troubleshooting section if the write_flash command is failing, or the flashed module fails to boot.
You may also need to specify arguments for flash mode and flash size, if you wish to override the defaults. For example:
esptool.py --port /dev/ttyUSB0 write_flash --flash_mode qio --flash_size 32m 0x0 bootloader.bin 0x1000 my_app.bin
Since esptool v2.0, these options are not often needed as the default is to keep the flash mode and size from the .bin
image file, and to detect the flash size. See the Flash Modes section for more details.
By default, the serial transfer data is compressed for better performance. The -u/--no-compress
option disables this behaviour.
The read_flash command allows reading back the contents of flash. The arguments to the command are an address, a size, and a filename to dump the output to. For example, to read a full 2MB of attached flash:
./esptool.py -p PORT -b 460800 read_flash 0 0x200000 flash_contents.bin
(Note that if write_flash
updated the boot image’s flash mode and flash size during flashing then these bytes may be different when read back.)
To erase the entire flash chip (all data replaced with 0xFF bytes):
esptool.py erase_flash
To erase a region of the flash, starting at address 0x20000 with length 0x4000 bytes (16KB):
esptool.py erase_region 0x20000 0x4000
The address and length must both be multiples of the SPI flash erase sector size. This is 0x1000 (4096) bytes for supported flash chips.
esptool.py read_mac
esptool.py flash_id
Example output:
Manufacturer: e0
Device: 4016
Detected flash size: 4MB
Refer to flashrom source code for flash chip manufacturer name and part number.
The elf2image
command converts an ELF file (from compiler/linker output) into the binary executable images which can be flashed and then booted into:
esptool.py --chip esp8266 elf2image my_app.elf
This command does not require a serial connection.
elf2image
also accepts the Flash Modes arguments --flash_freq
and --flash_mode
, which can be used to set the default values in the image header. This is important when generating any image which will be booted directly by the chip. These values can also be overwritten via the write_flash
command, see the write_flash command for details.
The default command output is two binary files: my_app.elf-0x00000.bin
and my_app.elf-0x40000.bin
. You can alter the firmware file name prefix using the --output/-o
option.
elf2image
can also produce a “version 2” image file suitable for use with a software bootloader stub such as rboot or the Espressif bootloader program. You can’t flash a “version 2” image without also flashing a suitable bootloader.
esptool.py --chip esp8266 elf2image --version=2 -o my_app-ota.bin my_app.elf
For esp32, elf2image produces a single output binary “image file”. By default this has the same name as the .elf file, with a .bin extension. ie:
esptool.py --chip esp32 elf2image my_esp32_app.elf
In the above example, the output image file would be called my_esp32_app.bin
.
The image_info
command outputs some information (load addresses, sizes, etc) about a .bin
file created by elf2image
.
esptool.py --chip esp32 image_info my_esp32_app.bin
Note that --chip esp32
is required when reading ESP32 images. Otherwise the default is --chip esp8266
and the image will be interpreted as an invalid ESP8266 image.
The following commands are less commonly used, or only of interest to advanced users. They are documented on the wiki:
The following tools for ESP32, bundled with esptool.py, are documented on the wiki:
The ESP8266 & ESP32 ROM serial bootloader uses a 3.3V UART serial connection. Many development boards make the serial connections for you onboard.
However, if you are wiring the chip yourself to a USB/Serial adapter or similar then the following connections must be made:
ESP32/ESP8266 Pin | Serial Port Pin |
---|---|
TX (aka GPIO1) | RX (receive) |
RX (aka GPIO3) | TX (transmit) |
Ground | Ground |
Note that TX (transmit) on the ESP8266 is connected to RX (receive) on the serial port connection, and vice versa.
Do not connect the chip to 5V TTL serial adapters, and especially not to “standard” RS-232 adapters! 3.3V serial only!
Both ESP8266 and ESP32 have to be reset in a certain way in order to launch the serial bootloader.
On some development boards (including NodeMCU, WeMOS, HUZZAH Feather, Core Board, ESP32-WROVER-KIT), esptool.py can automatically trigger a reset into the serial bootloader - in which case you don’t need to read this section.
For everyone else, three things must happen to enter the serial bootloader - a reset, required pins set correctly, and GPIO0 pulled low:
Both ESP8266 and ESP32 chooses the boot mode each time it resets. A reset event can happen in one of several ways:
- Power applied to chip.
- The nRESET pin was low and is pulled high (on ESP8266 only).
- The CH_PD/EN pin (“enable”) pin was low and is pulled high.
On ESP8266, both the nRESET and CH_PD pins must be pulled high for the chip to start operating.
For more details on selecting the boot mode, see the following Wiki pages:
write_flash
and some other comands accept command line arguments to set bootloader flash mode, flash size and flash clock frequency. The chip needs correct mode, frequency and size settings in order to run correctly - although there is some flexibility. A header at the beginning of a bootable image contains these values.
To override these values, the options --flash_mode
, --flash_size
and/or --flash_freq
must appear after write_flash
on the command line, for example:
esptool.py --port /dev/ttyUSB1 write_flash --flash_mode dio --flash_size 4MB 0x0 bootloader.bin
These options are only consulted when flashing a bootable image to an ESP8266 at offset 0x0, or an ESP32 at offset 0x1000. These are addresses used by the ROM bootloader to load from flash. When flashing at all other offsets, these arguments are not used.
These set Quad Flash I/O or Dual Flash I/O modes. Valid values are keep
, qio
, qout
, dio
, dout
. The default is keep
, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variable ESPTOOL_FM
.
Most boards use qio
mode. Some ESP8266 modules, including the ESP-12E modules on some (not all) NodeMCU boards, are dual I/O and the firmware will only boot when flashed with --flash_mode dio
. Most ESP32 modules are also dual I/O.
In qio
mode, two additional GPIOs (9 and 10) are used for SPI flash communications. If flash mode is set to dio
then these pins are available for other purposes.
For a full explanation of these modes, see the SPI Flash Modes wiki page.
Clock frequency for SPI flash interactions. Valid values are keep
, 40m
, 26m
, 20m
, 80m
(MHz). The default is keep
, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variable ESPTOOL_FF
.
The flash chip connected to most chips works with 40MHz clock speeds, but you can try lower values if the device won’t boot. The highest 80MHz flash clock speed will give best performance, but may cause crashing if the flash or board designis not capable of this speed.
Size of the SPI flash, given in megabytes. Valid values vary by chip type:
Chip | flash_size values |
---|---|
ESP32 | detect , 1MB , 2MB , 4MB , 8MB , 16MB |
ESP8266 | detect , 256KB , 512KB , 1MB , 2MB , 4MB , 2MB-c1 , 4MB-c1 , 8MB , 16MB |
For ESP8266, some additional sizes & layouts for OTA “firmware slots” are available.
The default --flash_size
parameter is detect
, which tries to autodetect size based on SPI flash ID. If detection fails, a warning is printed and a default value of of 4MB
(4 megabytes) is used.
If flash size is not successfully detected, you can find the flash size by using the flash_id
command and then looking up the ID from the output (see Read SPI flash id). Alternatively, read off the silkscreen labelling of the flash chip and search for its datasheet.
The default flash_size
parameter can also be overriden using the environment variable ESPTOOL_FS
.
The ESP8266 SDK stores WiFi configuration at the “end” of flash, and it finds the end using this size. However there is no downside to specifying a smaller flash size than you really have, as long as you don’t need to write an image larger than this size.
ESP-12, ESP-12E and ESP-12F modules (and boards that use them such as NodeMCU, HUZZAH, etc.) usually have at least 4 megabyte / 4MB
(sometimes labelled 32 megabit) flash.
If using OTA, some additional sizes & layouts for OTA “firmware slots” are available. If not using OTA updates then you can ignore these extra sizes:
flash_size arg | Number of OTA slots | OTA Slot Size | Non-OTA Space |
---|---|---|---|
256KB | 1 (no OTA) | 256KB | N/A |
512KB | 1 (no OTA) | 512KB | N/A |
1MB | 2 | 512KB | 0KB |
2MB | 2 | 512KB | 1024KB |
4MB | 2 | 512KB | 3072KB |
2MB-c1 | 2 | 1024KB | 0KB |
4MB-c1 | 2 | 1024KB | 2048KB |
8MB [^] | 2 | 1024KB | 6144KB |
16MB [^] | 2 | 1024KB | 14336KB |
- [^] Support for 8MB & 16MB flash size is not present in all ESP8266 SDKs. If your SDK doesn’t support these flash sizes, use
--flash_size 4MB
.
The ESP32 esp-idf flashes a partition table to the flash at offset 0x8000. All of the partitions in this table must fit inside the configured flash size, otherwise the ESP32 will not work correctly.
See the Advanced Options wiki page for some of the more unusual esptool.py command line options.
It is possible to connect to any networked remote serial port that supports RFC2217 (Telnet) protocol, or a plain TCP socket. See the Remote Serial Ports wiki page for details.
Flashing problems can be fiddly to troubleshoot. Try the suggestions here if you’re having problems:
If you see errors like “Failed to connect” then your chip is probably not entering the bootloader properly:
- Check you are passing the correct serial port on the command line.
- Check you have permissions to access the serial port, and other software (such as modem-manager on Linux) is not trying to interact with it. A common pitfall is leaving a serial terminal accessing this port open in another window and forgetting about it.
- Check the chip is receiving 3.3V from a stable power source (see Insufficient Power for more details.)
- Check that all pins are connected as described in Entering the bootloader. Check the voltages at each pin with a multimeter, “high” pins should be close to 3.3V and “low” pins should be close to 0V.
- If you have connected other devices to GPIO pins mentioned above section, try removing them and see if esptool.py starts working.
- Try using a slower baud rate (
-b 9600
is a very slow value that you can use to verify it’s not a baud rate problem.)
If flashing fails with random errors part way through, retry with a lower baud rate.
Power stability problems may also cause this (see Insufficient Power.)
If esptool.py can flash your module with write_flash
but your program doesn’t run, try the following:
Some devices only support the dio
flash mode. Writing to flash with qio
mode will succeed but the chip can’t read the flash back to run - so nothing happens on boot. Try passing the -fm dio
option to write_flash.
See the SPI Flash Modes wiki page for a full description of the flash modes and how to determine which ones are supported on your device.
The 3.3V power supply for the ESP8266 and ESP32 has to supply large amounts of current (up to 70mA continuous, 200-300mA peak, slightly higher for ESP32). You also need sufficient capacitance on the power circuit to meet large spikes of power demand.
If you’re using a pre-made development board or module then the built-in power regulator & capacitors are usually good enough, provided the input power supply is adequate.
This is not true for some very simple pin breakout modules - `similar to this <https://user-images.githubusercontent.com/205573/30140831-9da417a6-93ba-11e7-95c3-f422744967de.jpg>`_. These breakouts do not integrate enough capacitance to work reliably without additional components.. Surface mount OEM modules like ESP-WROOM02 and ESP-WROOM32 require an external bulk capacitor on the PCB to be reliable, consult the module datasheet.
It is possible to have a power supply that supplies enough current for the serial bootloader stage with esptool.py, but not enough for normal firmware operation. You may see the 3.3V VCC voltage droop down if you measure it with a multimeter, but you can have problems even if this isn’t happening.
Try swapping in a 3.3V supply with a higher current rating, add capacitors to the power line, and/or shorten any 3.3V power wires.
The 3.3V output from FTDI FT232R chips/adapters or Arduino boards do not supply sufficient current to power an ESP8266 or ESP32 (it may seem to work sometimes, but it won’t work reliably). Other USB TTL/serial adapters may also be marginal.
Recent ESP8266 SDKs and the ESP32 esp-idf both use a small firmware bootloader program. The hardware bootloader in ROM loads this firmware bootloader from flash, and then it runs the program. On ESP8266. firmware bootloader image (with a filename like boot_v1.x.bin
) has to be flashed at offset 0. If the firmware bootloader is missing then the ESP8266 will not boot. On ESP32, the bootloader image should be flashed by esp-idf at offset 0x1000.
Refer to SDK or esp-idf documentation for details regarding which binaries need to be flashed at which offsets.
Compared to the ROM bootloader that esptool.py talks to, a running firmware uses more of the chip’s pins to access the SPI flash.
If you set “Quad I/O” mode (-fm qio
, the esptool.py default) then GPIOs 7, 8, 9 & 10 are used for reading the SPI flash and must be otherwise disconnected.
If you set “Dual I/O” mode (-fm dio
) then GPIOs 7 & 8 are used for reading the SPI flash and must be otherwise disconnected.
Try disconnecting anything from those pins (and/or swap to Dual I/O mode if you were previously using Quad I/O mode but want to attach things to GPIOs 9 & 10). Note that if GPIOs 9 & 10 are also connected to input pins on the SPI flash chip, they may still be unsuitable for use as general purpose I/O.
In addition to these pins, GPIOs 6 & 11 are also used to access the SPI flash (in all modes). However flashing will usually fail completely if these pins are connected incorrectly.
Use a serial terminal program to view the boot log. (ESP8266 baud rate is 74880bps, ESP32 is 115200bps). See if the program is crashing during early startup or outputting an error message.
There are many serial terminal programs suitable for debugging & serial interaction. The pyserial module (which is required for esptool.py) includes one such command line terminal program - miniterm.py. For more details see this page or run miniterm -h
.
Note that not every serial program supports the unusual ESP8266 74880bps “boot log” baud rate. Support is especially sparse on Linux. miniterm.py
supports this baud rate on all platforms. ESP32 uses the more common 115200bps.
Running esptool.py --trace
will dump all serial interactions to the standard output (this is a lot of output). This can be helpful when debugging issues with the serial connection, or when providing information for bug reports.
esptool.py can easily be integrated into Python applications or called from other Python scripts.
While it currently does have a poor Python API, something which #208 will address, it allows for passing CLI
arguments to esptool.main()
. This workaround makes integration very straightforward as you can pass exactly the
same arguments as you would on the CLI.
command = ['--baud', '460800', 'read_flash', '0', '0x200000', 'flash_contents.bin']
print('Using command %s' % ' '.join(command))
esptool.main(command)
The repository wiki contains some technical documentation regarding the serial protocol and file format used by the ROM bootloader. This may be useful if you’re developing esptool.py or hacking system internals:
esptool.py was initially created by Fredrik Ahlberg (@themadinventor, @kongo), and is currently maintained by Angus Gratton (@projectgus). It has also received improvements from many members of the ESP8266 community - including @rojer, @jimparis, @jms19, @pfalcon, @tommie, @0ff, @george-hopkins and others.
This document and the attached source code are released under GNU General Public License Version 2. See the accompanying file LICENSE for a copy.
FAT Filing System¶
Required by the SDCard library.
http://elm-chan.org/fsw/ff/00index_e.html
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
Esp8266 GDBSTUB for Sming¶
This is a rewrite of gdbstub based on the esp8266 Arduino project.
To use the GNU Debugger (GDB) with Sming requires your application to
include some code (gdbstub
) which communicates via the serial port.
On the ESP8266 only UART0 may be used for this as UART1 is
transmit-only.
The gdbstub code will only be built if you specify ENABLE_GDB
=1 when compiling your application. At startup, before your init()
function is called, it will claim UART0 so your application will be
unable to use it directly. Therefore, the default port for Serial
is changed to UART2
.
UART2 is a ‘virtual’ serial port to enable serial communications to work correctly when GDB-enabled. Read/write calls and serial callbacks are handled via gdbstub. Baud rate changes affect UART0 directly.
Note that target
refers to the application being debugged, and
host
the development system running the GDB program.
Refer to the official GDB documention for further details.
This is the application which runs on your development system and talks
to gdbstub
.
- Linux: A version of this should be available in
$ESP_HOME/xtensa-lx106-elf/bin/xtensa-lx106-elf-gdb
- Windows: At time of writing, UDK doesn’t provide a GDB application
- Download and run the executable installer at SysProgs
- Copy the
C:\SysGCC\esp8266\opt\xtensa-lx106-elf\bin\xtensa-lx106-elf-gdb.exe
to a suitable location.
- Copy the
- Mac: ?
- Configure gdbstub by editing
gdbstub-cfg.h
as required. You can also configure the options by setting :USER_CFLAGS
in your project’scomponent.mk
file. e.gUSER_CFLAGS=-DGDBSTUB_BREAK_ON_INIT=0
. - Optional: Add
gdb_do_break()
statements to your application. - Run
make clean
, thenmake ENABLE_GDB=1 flash
to build and flash the application with debugging enabled - Run gdb, depending on your configuration immediately after
resetting the board or after it has run into an exception. The
easiest way to do it is to use the provided script:
make gdb
.
To run manually, see the following variables which you can inspect using make list-config
.
-
GDB_CMDLINE
¶ Command line used to run GDB.
-
GDBSTUB_DIR
¶ Location of the GDB stub component, and the
gdbcmds
file.
-
COM_SPEED_GDB
¶ Same as
COM_SPEED_SERIAL
, which is the value compiled into the gdbstub code.
-
GDB_UART_SWAP
¶ If you need to use alternate serial pins, enable this option
GDB_UART_SWAP=1
-
GDB
¶ Path to the GDB executable being used.
c
Continue execution
q
Quit and detach
where
Display current stopped location
bt
Show stack backtrace
disass
Disassemble, disass/m
to mix with source code
print expr
Display a variable or other value
print func()
Call a function, display result, or call func()
to
discard result
tui enable
Provides a windowed interface within the console (only
seems to work in Linux)
x/32xw $sp
Display contents of stack
info reg
Display register values
info break
Display details of currently set breakpoints
delete
Delete all breakpoints
br
Set a breakpoint at the given address or function name
hbr
Set a hardware breakpoint
watch
Set a hardware watchpoint to detect when the value of a
variable changes
These commands require GDBSTUB_ENABLE_HOSTIO
to be enabled:
remote get targetfile hostfile
Read a file from SPIFFS (on the
target)
remote put hostfile targetfile
Write a file to SPIFFS
remote delete targetfile
Delete a file from SPIFFS
Windows:
- Ensure
Use external console for inferior
is checked. - In connection settings, specify COM port like with leading /,
e.g.
/COM4
Problems connecting?
- Switch to the debug perspective before connecting
- Ensure serial baud rate matches your application
- Remove or disable all breakpoints before attaching. Eclipse will attempt to set these on connection, and if any are invalid it will hang and timeout.
- Check connectivity using command-line GDB
Applications may interact with GDB directly using system calls, for example reading input from the GDB command prompt. See the Live Debug sample for a demonstration.
Note that system calls are disabled in the default configuration, so set
GDBSTUB_ENABLE_SYSCALL
=1 to use this feature with your
application.
- Unable to set requested break/watch points
- Cause: Due to hardware limitations, only one hardware breakpount and one hardware watchpoint are available
- Solution: None (hardware limitation)
- System crashes if debugger is paused for too long
- Cause: The WiFi hardware is designed to be serviced by software periodically. It has some buffers so it will behave OK when some data comes in while the processor is busy, but these buffers are not infinite. If the WiFi hardware receives lots of data while the debugger has stopped the CPU, it is bound to crash. This will happen mostly when working with UDP and/or ICMP; TCP-connections in general will not send much more data when the other side doesn’t send any ACKs.
- Solution: In such situations avoid pausing the debugger for extended periods
- Software breakpoints/watchpoints (‘break’ and ‘watch’) don’t work on flash code
- Cause: GDB handles these by replacing code with a debugging instruction, therefore the code must be in RAM.
- Solution: Use hardware breakpoint (‘hbreak’) or use
GDB_IRAM_ATTR
for code which requires testing
- If hardware breakpoint is set, single-stepping won’t work unless code is in RAM.
- Cause: GDB reverts to software breakpoints if no hardware breakpoints are available
- Solution: Delete hardware breakpoint before single-stepping
- Crash occurs when setting breakpoint in HardwareTimer callback routine
- Cause: By default, HardwareTimer uses Non-maskable Interrupts (NMI) which keep running when the debugger is paused
- Solution: Use the timer in non-maskable mode, or enable
GDBSTUB_PAUSE_HARDWARE_TIMER
option
- If gdbstub isn’t initialised then UART2 won’t work, though initialisation will succeed
- Cause: By design, uart callbacks can be registered for UART2 at any time, before or after initialisation
- Solution: Not really an issue, just something to be aware of
- Error reported, “packet reply is too long”
- Cause: Mismatch between GDB version and stub code
- Solution: Set
GDBSTUB_GDB_PATCHED
=1 or use an unpatched version of GDB
- Whilst GDB is attached, input cannot be passed to application
- Cause: GDB buffers keystrokes and replays them only when the target is interrupted (e.g. via ctrl+C), rather than passing them via serial connection.
- Solution: Application may use gdb_syscall interface to
communicate with debugger. See
$(SMING_HOME)/system/gdb_syscall.h
, and Live Debug sample.
- No apparent way to have second ‘console’ (windows terminology) separate from GDB interface
- Cause: Unknown
- Solution: Is this possible with remote targets?
- GDB (in Windows) doesn’t respond at all to Ctrl+C
- Cause: Unknown
- Solution: Press Ctrl+Break to ‘hard kill’ GDB. You’ll probably need to do the next step as well to get it back
- When GDB is running under windows, appears to hang when target reset or restarted
- Cause: Unknown, may not happen on all devboards but presents with NodeMCU
- Solution
- quit GDB
quit
- Start terminal
make terminal
- reset board
- quit terminal
- run GDB again
make gdb
- quit GDB
- Debug messages don’t appear in Eclipse
- Cause: Unknown
- Solution: Use command-line GDB, or a better visual debugger
Defines
-
ENABLE_EXCEPTION_DUMP
¶ When enabled, an exception or crash dumps a stack trace to debug output Default is ON for debug builds, OFF for release builds
Note: Not dependent upon ENABLE_GDB
-
ENABLE_CRASH_DUMP
¶ When enabled, an unexpected reset (i.e. system crash) dumps a stack trace to debug output Default is ON for debug builds, OFF for release builds
Note: Not dependent upon ENABLE_GDB
-
GDBSTUB_ENABLE_DEBUG
¶ When defined, GDB communications are echoed to UART1 for testing GDB stub operation.
0: No debug output 1: Show decoded commands and responses 2: Show packet content 3: Show debug output for internal routines
-
GDBSTUB_GDB_PATCHED
¶ Espressif provide a patched version of GDB which emits only those registered present in the lx106. Set to 0 if an unpatched version of GDB is used.
-
GDBSTUB_USE_OWN_STACK
¶ Enable this to make the exception and debugging handlers switch to a private stack. This will use up 1K of RAM, but may be useful if you’re debugging stack or stack pointer corruption problems. It’s normally disabled because not many situations need it. If for some reason the GDB communication stops when you run into an error in your code, try enabling this.
-
GDBSTUB_STACK_SIZE
¶
-
GDBSTUB_BREAK_ON_EXCEPTION
¶ Enable this to cause the program to pause and wait for gdb to be connected when an exception is encountered.
-
GDBSTUB_BREAK_ON_RESTART
¶ Enable this to cause the program to pause and wait for gdb to be connected when an unexpected system restart occurs.
-
GDBSTUB_CTRLC_BREAK
¶ If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. It does this by monitoring for the ‘x03’ character in the serial receive routine. Any preceding characters are passed through to the application via UART2. If your application uses the serial port for terminal (text) communications you should be OK, but binary transfers are likely to cause problems and this option should probably be disabled. Instead, use GDBSTUB_BREAK_ON_INIT, or call gdb_do_break() in your application.
Specify: 0 to disable Ctrl+C break checking completely 1 to allow Ctrl+C break only when debugger is attached 2 to allow Ctrl+C break at any time. Ensure you have set remote interrupt-on-connect on in GDB command file, so it will send a Ctrl+C sequence when attempting to connect
-
GDBSTUB_ENABLE_UART2
¶ The GDB stub has exclusive access to UART0, so applications cannot use it directly and attempts to open it will fail.
If this option is enabled, the default serial port will be changed to UART2 to allow debug output (from m_printf, debug_*, os_printf, etc.) to show up in your GDB session.
Outside of GDB terminal applications should work as normal, with the following caveats:
If GDBSTUB_BREAK_ON_INIT is defined, then at startup your application will display `$T05#b9` and stop. A similar thing will happen if GDBSTUB_CTRLC_BREAK=2 and you type Ctrl+C. Continue by typing `$D#44` (without the quotes), or exit the terminal and start GDB.
See GDB remote serial protocol for further details.
Disabling this option releases some IRAM. You may be instead able to use UART1 for debug output, adding
Serial.setPort(UART_ID_1);
in your application’sinit()
function.
-
GDBSTUB_ENABLE_SYSCALL
¶ Enable gdb_syscall_* functions for use by application. If undefined, calls will do nothing and return -1.
-
GDBSTUB_ENABLE_HOSTIO
¶ Enable Host I/O capability, where files may be accessed via GDB command prompt using
remote get
,remote put
andremote delete
commands.
-
GDBSTUB_BREAK_ON_INIT
¶ Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by breaking in the init routine; use the gdb ‘c’ command (continue) to start the program.
-
GDBSTUB_CMDENABLE_P
¶ Some commands are not required by GDB, so if neccessary can be disabled to save memory.
-
GDBSTUB_CMDENABLE_X
¶
-
GDBSTUB_UART_READ_TIMEOUT
¶ Specify a timeout (in milliseconds) when stub is reading from serial port. Set to 0 to wait indefinitely.
-
GDBSTUB_FORCE_IRAM
¶ Wherever possible gdbstub code is placed in flash memory. This is fine for most cases, but if debugging whilst flash is disabled or busy (eg during SPI operations or flash write/erase) then you will need to enable this option to move stub code into IRAM.
- Source Code
- Esp8266 Core Component Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Heap¶
-
ENABLE_CUSTOM_HEAP
¶ If your application is experiencing heap fragmentation then you can try the alternative heap.
- undefined (default)
- OFF, use standard heap
- 1
- Use UMM Malloc.
Warning
Do not enable custom heap allocation and -mforce-l32 compiler flag at the same time.
-
UMM_FUNC_IRAM
¶ Default: 1 (enabled)
Custom heap functions are stored in IRAM by default for performance reasons.
If you need the IRAM (about 1.5K bytes) then disable this option:
make ENABLE_CUSTOM_HEAP=1 UMM_FUNC_IRAM=0
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
This is a memory management library specifically designed to work with the ARM7 embedded processor, but it should work on many other 32 bit processors, as well as 16 and 8 bit devices.
You can even use it on a bigger project where a single process might want to manage a large number of smaller objects, and using the system heap might get expensive.
Joerg Wunsch and the avr-libc provided the first malloc()
implementation
that I examined in detail.
http://www.nongnu.org/avr-libc
Doug Lea’s paper on malloc() was another excellent reference and provides a lot of detail on advanced memory management techniques such as binning.
http://g.oswego.edu/dl/html/malloc.html
Bill Dittman provided excellent suggestions, including macros to support
using these functions in critical sections, and for optimizing realloc()
further by checking to see if the previous block was free and could be
used for the new block size. This can help to reduce heap fragmentation
significantly.
Yaniv Ankin suggested that a way to dump the current heap condition might be useful. I combined this with an idea from plarroy to also allow checking a free pointer to make sure it’s valid.
Dimitry Frank contributed many helpful additions to make things more robust including a user specified config file and a method of testing the integrity of the data structures.
Copy the umm_malloc_cfg_example.h
file to umm_malloc_cfg.h
and
make the changes required to support your application.
The following #define
s must be set to something useful for the
library to work at all
UMM_MALLOC_CFG_HEAP_ADDR
must be set to the symbol representing the starting address of the heap. The heap must be aligned on the natural boundary size of the processor.UMM_MALLOC_CFG_HEAP_SIZE
must be set to the size of the heap. The heap size must be a multiple of the natural boundary size of the processor.
The fit algorithm is defined as either:
UMM_BEST_FIT
which scans the entire free list and looks- for either an exact fit or the smallest block that will satisfy the request. This is the default fit method.
UMM_FIRST_FIT
which scans the entire free list and looks- for the first block that satisfies the request.
The following #define
s are disabled by default and should
remain disabled for production use. They are helpful when
testing allocation errors (which are normally due to bugs in
the application code) or for running the test suite when
making changes to the code.
You can define them in your compiler command line or uncomment
the corresponding entries is umm_malloc_cfg.h
:
UMM_INFO
is used to include code that allows dumping the entire heap structure (helpful when there’s a problem).UMM_INTEGRITY_CHECK
is used to include code that performs an integrity check on the heap structure. It’s up to you to call theumm_integrity_check()
function.UMM_POISON_CHECK
is used to include code that adds some bytes around the memory being allocated that are filled with known data. If the data is not intact when the block is checked, then somone has written outside of the memory block they have been allocated. It is up to you to call theumm_poison_check()
function.
The following functions are available for your application:
void *umm_malloc( size_t size );
void *umm_calloc( size_t num, size_t size );
void *umm_realloc( void *ptr, size_t size );
void umm_free( void *ptr );
They have exactly the same semantics as the corresponding standard library functions.
The memory manager assumes the following things:
- The standard POSIX compliant malloc/calloc/realloc/free semantics are used
- All memory used by the manager is allocated at link time, it is aligned on a 32 bit boundary, it is contiguous, and its extent (start and end address) is filled in by the linker.
- All memory used by the manager is initialized to 0 as part of the runtime startup routine. No other initialization is required.
The fastest linked list implementations use doubly linked lists so that its possible to insert and delete blocks in constant time. This memory manager keeps track of both free and used blocks in a doubly linked list.
Most memory managers use a list structure made up of pointers to keep track of used - and sometimes free - blocks of memory. In an embedded system, this can get pretty expensive as each pointer can use up to 32 bits.
In most embedded systems there is no need for managing a large quantity of memory block dynamically, so a full 32 bit pointer based data structure for the free and used block lists is wasteful. A block of memory on the free list would use 16 bytes just for the pointers!
This memory management library sees the heap as an array of blocks, and uses block numbers to keep track of locations. The block numbers are 15 bits - which allows for up to 32767 blocks of memory. The high order bit marks a block as being either free or in use, which will be explained later.
The result is that a block of memory on the free list uses just 8 bytes instead of 16.
In fact, we go even one step futher when we realize that the free block index values are available to store data when the block is allocated.
The overhead of an allocated block is therefore just 4 bytes.
Each memory block holds 8 bytes, and there are up to 32767 blocks available, for about 256K of heap space. If that’s not enough, you can always add more data bytes to the body of the memory block at the expense of free block size overhead.
There are a lot of little features and optimizations in this memory management system that makes it especially suited to small systems, and the best way to appreciate them is to review the data structures and algorithms used, so let’s get started.
We have a general notation for a block that we’ll use to describe the different scenarios that our memory allocation algorithm must deal with:
+----+----+----+----+
c |* n | p | nf | pf |
+----+----+----+----+
Where:
- c is the index of this block
- is the indicator for a free block
- n is the index of the next block in the heap
- p is the index of the previous block in the heap
- nf is the index of the next block in the free list
- pf is the index of the previous block in the free list
The fact that we have forward and backward links in the block descriptors means that malloc() and free() operations can be very fast. It’s easy to either allocate the whole free item to a new block or to allocate part of the free item and leave the rest on the free list without traversing the list from front to back first.
The entire block of memory used by the heap is assumed to be initialized to 0. The very first block in the heap is special - it’t the head of the free block list. It is never assimilated with a free block (more on this later).
Once a block has been allocated to the application, it looks like this:
+----+----+----+----+
c | n | p | ... |
+----+----+----+----+
Where:
- c is the index of this block
- n is the index of the next block in the heap
- p is the index of the previous block in the heap
Note that the free list information is gone because it’s now being used to store actual data for the application. If we had even 500 items in use, that would be 2,000 bytes for free list information. We simply can’t afford to waste that much.
The address of the ...
area is what is returned to the application
for data storage.
The following sections describe the scenarios encountered during the operation of the library. There are two additional notation conventions:
??
inside a pointer block means that the data is irrelevant. We don’t care
about it because we don’t read or modify it in the scenario being
described.
...
between memory blocks indicates zero or more additional blocks are
allocated for use by the upper block.
While we’re talking about “upper” and “lower” blocks, we should make a comment about adresses. In the diagrams, a block higher up in the picture is at a lower address. And the blocks grow downwards their block index increases as does their physical address.
Finally, there’s one very important characteristic of the individual blocks that make up the heap - there can never be two consecutive free memory blocks, but there can be consecutive used memory blocks.
The reason is that we always want to have a short free list of the largest possible block sizes. By always assimilating a newly freed block with adjacent free blocks, we maximize the size of each free memory area.
As part of the system startup code, all of the heap has been cleared.
During the very first malloc operation, we start traversing the free list starting at index 0. The index of the next free block is 0, which means we’re at the end of the list!
At this point, the malloc has a special test that checks if the current block index is 0, which it is. This special case initializes the free list to point at block index 1 and then points block 1 to the last block (lf) on the heap.
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+
1 |*lf | 0 | 0 | 0 |
+----+----+----+----+
...
+----+----+----+----+
lf | 0 | 1 | 0 | 0 |
+----+----+----+----+
The heap is now ready to complete the first malloc operation.
This happens at the very first malloc operation, or any time the free list is traversed and no free block large enough for the request is found.
The current block pointer will be at the end of the free list, and we know we’re at the end of the list because the nf index is 0, like this:
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
pf |*?? | ?? | cf | ?? | pf |*?? | ?? | lf | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
p | cf | ?? | ... | p | cf | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
cf | 0 | p | 0 | pf | c | lf | p | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+
lf | 0 | cf | 0 | pf |
+----+----+----+----+
As we walk the free list looking for a block of size b or larger, we get to cf, which is the last item in the free list. We know this because the next index is 0.
So we’re going to turn cf into the new block of memory, and then create a new block that represents the last free entry (lf) and adjust the prev index of lf to point at the block we just created. We also need to adjust the next index of the new block (c) to point to the last free block.
Note that the next free index of the pf block must point to the new lf because cf is no longer a free block!
This one is pretty easy, just clear the free list bit in the current block and unhook it from the free list.
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
pf |*?? | ?? | cf | ?? | pf |*?? | ?? | nf | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
p | cf | ?? | ... | p | cf | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+ Clear the free
cf |* n | p | nf | pf | cf | n | p | .. | list bit here
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
n | ?? | cf | ... | n | ?? | cf | ... |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | cf | nf | ?? | ?? | ?? | pf |
+----+----+----+----+ +----+----+----+----+
Unhooking from the free list is accomplished by adjusting the next and prev free list index values in the pf and nf blocks.
We’ll allocate the new block at the END of the current free block so we don’t have to change ANY free list pointers.
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
pf |*?? | ?? | cf | ?? | pf |*?? | ?? | cf | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
p | cf | ?? | ... | p | cf | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
cf |* n | p | nf | pf | cf |* c | p | nf | pf |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ This is the new
c | n | cf | .. | block at cf+b
+----+----+----+----+
+----+----+----+----+ +----+----+----+----+
n | ?? | cf | ... | n | ?? | c | ... |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | cf | nf | ?? | ?? | ?? | pf |
+----+----+----+----+ +----+----+----+----+
This one is prety easy too, except we don’t need to mess with the free list indexes at all becasue we’ll allocate the new block at the end of the current free block. We do, however have to adjust the indexes in cf, c, and n.
That covers the initialization and all possible malloc scenarios, so now we need to cover the free operation possibilities…
The operation of free depends on the position of the current block being freed relative to free list items immediately above or below it. The code works like this:
if next block is free
assimilate with next block already on free list
if prev block is free
assimilate with prev block already on free list
else
put current block at head of free list
Step 1 of the free operation checks if the next block is free, and if it is assimilate the next block with this one.
Note that c is the block we are freeing up, cf is the free block that follows it.
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
pf |*?? | ?? | cf | ?? | pf |*?? | ?? | nf | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
p | c | ?? | ... | p | c | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+ This block is
c | cf | p | ... | c | nn | p | ... | disconnected
+----+----+----+----+ +----+----+----+----+ from free list,
+----+----+----+----+ assimilated with
cf |*nn | c | nf | pf | the next, and
+----+----+----+----+ ready for step 2
+----+----+----+----+ +----+----+----+----+
nn | ?? | cf | ?? | ?? | nn | ?? | c | ... |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | cf | nf |*?? | ?? | ?? | pf |
+----+----+----+----+ +----+----+----+----+
Take special note that the newly assimilated block (c) is completely disconnected from the free list, and it does not have its free list bit set. This is important as we move on to step 2 of the procedure…
Step 2 of the free operation checks if the prev block is free, and if it is then assimilate it with this block.
Note that c is the block we are freeing up, pf is the free block that precedes it.
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+ This block has
pf |* c | ?? | nf | ?? | pf |* n | ?? | nf | ?? | assimilated the
+----+----+----+----+ +----+----+----+----+ current block
+----+----+----+----+
c | n | pf | ... |
+----+----+----+----+
+----+----+----+----+ +----+----+----+----+
n | ?? | c | ... | n | ?? | pf | ?? | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | pf | nf |*?? | ?? | ?? | pf |
+----+----+----+----+ +----+----+----+----+
Nothing magic here, except that when we’re done, the current block (c) is gone since it’s been absorbed into the previous free block. Note that the previous step guarantees that the next block (n) is not free.
Step 3 of the free operation only runs if the previous block is not free. it just inserts the current block to the head of the free list.
Remember, 0 is always the first block in the memory heap, and it’s always head of the free list!
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
0 | ?? | ?? | nf | 0 | 0 | ?? | ?? | c | 0 |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
p | c | ?? | ... | p | c | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
c | n | p | .. | c |* n | p | nf | 0 |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
n | ?? | c | ... | n | ?? | c | ... |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | 0 | nf |*?? | ?? | ?? | c |
+----+----+----+----+ +----+----+----+----+
Again, nothing spectacular here, we’re simply adjusting a few pointers to make the most recently freed block the first item in the free list.
That’s because finding the previous free block would mean a reverse traversal of blocks until we found a free one, and it’s just easier to put it at the head of the list. No traversal is needed.
Finally, we can cover realloc, which has the following basic operation.
The first thing we do is assimilate up with the next free block of memory if possible. This step might help if we’re resizing to a bigger block of memory. It also helps if we’re downsizing and creating a new free block with the leftover memory.
First we check to see if the next block is free, and we assimilate it to this block if it is. If the previous block is also free, and if combining it with the current block would satisfy the request, then we assimilate with that block and move the current data down to the new location.
Assimilating with the previous free block and moving the data works like this:
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
pf |*?? | ?? | cf | ?? | pf |*?? | ?? | nf | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
cf |* c | ?? | nf | pf | c | n | ?? | ... | The data gets
+----+----+----+----+ +----+----+----+----+ moved from c to
+----+----+----+----+ the new data area
c | n | cf | ... | in cf, then c is
+----+----+----+----+ adjusted to cf
+----+----+----+----+ +----+----+----+----+
n | ?? | c | ... | n | ?? | c | ?? | ?? |
+----+----+----+----+ +----+----+----+----+
... ...
+----+----+----+----+ +----+----+----+----+
nf |*?? | ?? | ?? | cf | nf |*?? | ?? | ?? | pf |
+----+----+----+----+ +----+----+----+----+
Once we’re done that, there are three scenarios to consider:
- The current block size is exactly the right size, so no more work is needed.
- The current block is bigger than the new required size, so carve off the excess and add it to the free list.
- The current block is still smaller than the required size, so malloc a new block of the correct size and copy the current data into the new block before freeing the current block.
The only one of these scenarios that involves an operation that has not yet been described is the second one, and it’s shown below:
BEFORE AFTER
+----+----+----+----+ +----+----+----+----+
p | c | ?? | ... | p | c | ?? | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ +----+----+----+----+
c | n | p | ... | c | s | p | ... |
+----+----+----+----+ +----+----+----+----+
+----+----+----+----+ This is the
s | n | c | .. | new block at
+----+----+----+----+ c+blocks
+----+----+----+----+ +----+----+----+----+
n | ?? | c | ... | n | ?? | s | ... |
+----+----+----+----+ +----+----+----+----+
Then we call free() with the adress of the data portion of the new block (s) which adds it to the free list.
Esp8266 LIBC Component¶
This Component accommodates the differences in runtime libraries for the various supported toolchains.
See also ESP Quick Toolchain.
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Sming (Host) ,Component
Esp8266 LWIP Version 2¶
This Component implements the current Version 2 LWIP stack. Note that at present espconn_* functions are not supported.
- Source Code
- Esp8266 Core Component Component
This repo offers a link layer for esp82xx-nonos-sdk-2. The original goal is to try and use a recent lwIP version for stability reasons. Currently lwIP-v2 is implemented, other IP stacks could be tried.
- arduino NTPClient
- arduino WiFiAccessPoint
- arduino OTA
- Sming Telnet sample
makefiles are working with linux/osx, and maybe with windows (using ‘make’ included in msys from mingw…)
get lwIP sources
git submodule update --init --recursive
optionnally tune lwIP configuration in glue-lwip/lwipopts.h
build & install
make -f Makefile.<arch> install
Remember the MSS footprint: 4*MSS bytes in RAM per tcp connection. The lowest recommanded value is 536 which is the default here.
Espressif binary libraries rely on their lwip implementation. The idea, as described in this comment is to wrap espressif calls, and rewrite them for a new tcp implementation.
Example with lwip1.4’s ethernet_input() called by espressif binary blobs finally reaching lwip2’s:
-- LWIP2-----------------------------------
#define ethernet_input ethernet_input_LWIP2
- lwip2's ethernet_input_LWIP2_is called
(/ \)
| |
-- glue (new side)-----------^-v-----------
| |
glue_ethernet_input | |
- maps structures glue->new |
- calls ethernet_input_LWIP2(^ v)
- maps structures new->glue |
| |
-- glue (old side)-----------^-v-----------
| |
ethernet_input(): | |
- maps structures old->glue |
- calls glue_ethernet_input (^ v)
- maps structures glue->old |
| |
- espressif blobs -----------^-v-----------
XXXXXXXXXXXXXXXXXXXXXXXXXXXX | | XXXXXXXXXX
wifi calls ethernet_input(/ \) XXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-------------------------------------------
Original cleaning and port of espressif’s patch set from lwIP-v1.4 to lwIP-v2 with references to lwIP-git-sha1
Discussion on how further work could done
First version of this implementation
Second version for arduino only
Esp8266 SPI Flash Support¶
Provides functions for access to flash memory.
-
uint32_t
flashmem_get_address
(const void *memptr) Obtain the flash memory address for a memory pointer.
- Note
- If memptr is not in valid flash memory it will return an offset which exceeds the internal flash memory size.
- Note
- The flash location is dependent on where rBoot has mapped the firmware.
- Parameters
memptr
:
- Return Value
uint32_t
: Offset from start of flash memory
-
uint32_t
flashmem_write
(const void *from, uint32_t toaddr, uint32_t size) Write a block of data to flash.
- Note
- None of the parameters need to be aligned
- Parameters
from
: Buffer to obtain data fromtoaddr
: Flash location to start writingsize
: Number of bytes to write
- Return Value
uint32_t
: Number of bytes written
-
uint32_t
flashmem_read
(void *to, uint32_t fromaddr, uint32_t size) Read a block of data from flash.
- Note
- none of the parameters need to be aligned
- Parameters
to
: Buffer to store datafromaddr
: Flash location to start readingsize
: Number of bytes to read
- Return Value
uint32_t
: Number of bytes written
-
bool
flashmem_erase_sector
(uint32_t sector_id) Erase a single flash sector.
- Parameters
sector_id
: the sector to erase
- Return Value
true
: on success
-
SPIFlashInfo
flashmem_get_info
() Get flash memory information block.
- Return Value
SPIFlashInfo
: Information block
-
uint8_t
flashmem_get_size_type
() Returns a number indicating the size of flash memory chip.
- Return Value
uint8_t
: See SpiFlashInfo.size field for possible values
-
uint32_t
flashmem_get_size_bytes
() get the total flash memory size
- Return Value
uint32_t
: Size in bytes
-
uint16_t
flashmem_get_size_sectors
() Get the total number of flash sectors.
- Return Value
uint16_t
: Sector count
-
uint32_t
flashmem_find_sector
(uint32_t address, uint32_t *pstart, uint32_t *pend) Helper function: find the flash sector in which an address resides.
- Note
- Optional parameters may be null
- Parameters
address
:pstart
: OUT/OPTIONAL: Start of sector containing the given addresspend
: OUT/OPTIONAL: Last address in sector
- Return Value
uint32_t
: Sector number for the given address
-
uint32_t
flashmem_get_sector_of_address
(uint32_t addr) Get sector number containing the given address.
- Parameters
addr
:
- Return Value
uint32_t
: sector number
-
uint32_t
flashmem_write_internal
(const void *from, uint32_t toaddr, uint32_t size) write to flash memory
- Note
- All parameters MUST be aligned to 4-byte word boundaries, including the RAM pointer
- Parameters
from
: Buffer to read data from - MUST be word-alignedtoaddr
: Flash address (offset) to write to - MUST be word-alignedsize
: Number of bytes to write - MUST be word-aligned
- Return Value
uint32_t
: Number of bytes actually written
-
uint32_t
flashmem_read_internal
(void *to, uint32_t fromaddr, uint32_t size) Read from flash memory.
- Note
- All parameters MUST be aligned to 4-byte word boundaries, including the RAM pointer
- Parameters
to
: Buffer to store data - MUST be word-alignedfromaddr
: Flash address (offset) to read from - MUST be word-alignedsize
: Number of bytes to read - MUST be word-aligned
- Return Value
uint32_t
: Number of bytes actually read
-
uint32_t
flashmem_get_first_free_block_address
()
-
INTERNAL_FLASH_WRITE_UNIT_SIZE
¶ Flash memory access must be aligned and in multiples of 4-byte words.
-
INTERNAL_FLASH_READ_UNIT_SIZE
¶
-
FLASH_TOTAL_SEC_COUNT
¶
-
SYS_PARAM_SEC_COUNT
¶ Number of flash sectors reserved for system parameters at start.
-
FLASH_WORK_SEC_COUNT
¶
-
INTERNAL_FLASH_SECTOR_SIZE
¶
-
INTERNAL_FLASH_SIZE
¶
-
INTERNAL_FLASH_START_ADDRESS
¶
-
SPI_FLASH_RESULT_OK
¶
-
INTERNAL_FLASH_WRITE_UNIT_SIZE
Flash memory access must be aligned and in multiples of 4-byte words.
-
INTERNAL_FLASH_READ_UNIT_SIZE
-
FLASH_TOTAL_SEC_COUNT
-
SYS_PARAM_SEC_COUNT
Number of flash sectors reserved for system parameters at start.
-
FLASH_WORK_SEC_COUNT
-
INTERNAL_FLASH_SECTOR_SIZE
-
INTERNAL_FLASH_SIZE
-
INTERNAL_FLASH_START_ADDRESS
-
struct
STORE_TYPEDEF_ATTR
- #include <esp_spi_flash.h>
SPI Flash memory information block. Stored at the beginning of flash memory.
Public Types
-
enum
[anonymous]
Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
-
enum
[anonymous]
Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
-
enum
[anonymous]
Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
-
enum
[anonymous]
Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
-
enum
[anonymous]
Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
-
enum
[anonymous]
Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
Public Members
-
uint8_t
unknown0
-
uint8_t
unknown1
-
STORE_TYPEDEF_ATTR::[anonymous]
mode
-
STORE_TYPEDEF_ATTR::[anonymous]
speed
-
STORE_TYPEDEF_ATTR::[anonymous]
size
-
STORE_TYPEDEF_ATTR::[anonymous]
mode
-
STORE_TYPEDEF_ATTR::[anonymous]
speed
-
STORE_TYPEDEF_ATTR::[anonymous]
size
-
enum
This is taken from the esp8266 arduino core. For details see:
See Flash memory for some background.
Code is always executed from IRAM, however it must be read in from flash memory on first use which can cause issues within timing-critical code.
This can be avoided by placing the code in IRAM. However, IRAM is a very limited resource and should generally be reserved for interrupt service routines.
An alternative solution is to arrange for critical code to be pre-loaded into IRAM before it starts execution.
Note
This cannot be used for interrupt service routines.
By their nature, interrupts are essentially random events and therefore code must be available in IRAM at any time.
The steps required are:
- Mark the function containing code using
IRAM_PRECACHE_ATTR()
- Place a call to
IRAM_PRECACHE_START()
before the first line of critical code - Place a call to
IRAM_PRECACHE_END()
after the last line of critical code
You must always declare a tag to avoid the risk of section name conflicts.
You can find an example of how precaching is used here:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_spi_utils.cpp
-
void
iram_precache
(void *addr, uint32_t bytes) Pre-load flash data into the flash instruction cache.
- Note
- All pages containing the requested region will be read to pull them into cache RAM.
- Parameters
addr
: First location to cache, specify NULL to use current location.bytes
: Number of bytes to cache
-
IRAM_PRECACHE_ATTR
¶ Tools for pre-loading code into the flash cache.
- It can be useful for code that accesses/uses SPI0 which is connected to the flash chip.
- Non interrupt handler code that is infrequently called but might otherwise require being in valuable IRAM - such as bit-banging I/O code or some code run at bootup can avoid being permanently in IRAM. Mark functions containing critical code using this attribute
-
IRAM_PRECACHE_START
(tag)¶ Place this macro before the first line of the critical code.
- Note
- Do not omit the tag, and be careful with naming to avoid conflicts
- Parameters
tag
: Used to create the precached section name, must be globally unique
-
IRAM_PRECACHE_END
(tag)¶ Place this macro after the last line of critical code.
- Parameters
tag
: Must be the same tag used in IRAM_PRECACHE_START()
-
IRAM_PRECACHE_ATTR
Tools for pre-loading code into the flash cache.
- It can be useful for code that accesses/uses SPI0 which is connected to the flash chip.
- Non interrupt handler code that is infrequently called but might otherwise require being in valuable IRAM - such as bit-banging I/O code or some code run at bootup can avoid being permanently in IRAM. Mark functions containing critical code using this attribute
-
IRAM_PRECACHE_START
(tag) Place this macro before the first line of the critical code.
- Note
- Do not omit the tag, and be careful with naming to avoid conflicts
- Parameters
tag
: Used to create the precached section name, must be globally unique
-
IRAM_PRECACHE_END
(tag) Place this macro after the last line of critical code.
- Parameters
tag
: Must be the same tag used in IRAM_PRECACHE_START()
- Source Code
- Esp8266 Core Component Component
- Sming (Esp32) ,Component
- Sming (Esp8266) ,Component
- Host Library ,Component
- Sming (Host) ,Component
Framework¶
Timers and Clocks¶
Hardware timers¶
The ESP8266 has one of these, HardwareTimer
, which can be programmed to trigger
when a pre-programmed interval has elapsed. The callback handler is executed in an
interrupt context so is restricted on what it can do.
The timer is appropriate where accurate and short timing is required.
The API for hardware (and Software timer queues timers) is identical, implemented using a
CallbackTimer
class template for best performance.
-
group
hardware_timer
Hardware callback timer.
Typedefs
-
using
HardwareTimer1
= CallbackTimer<Timer1Api<clkdiv, mode>>¶ Hardware Timer class template with selectable divider and interrupt mode.
-
using
HardwareTimer
= HardwareTimer1<>¶ Default hardware Timer class.
-
typedef HardwareTimer
Hardware_Timer
¶
Enums
-
template <hw_timer_clkdiv_t clkdiv, HardwareTimerMode mode>
classTimer1Api
: public CallbackTimerApi<Timer1Api<clkdiv, mode>>¶ - #include <HardwareTimer.h>
Class template for Timer1 API.
- Note
- Provides low-level interface for timer access
Public Types
-
template<>
usingClock
= Timer1Clock<clkdiv>¶
-
template<>
usingTickType
= uint32_t¶
-
template<>
usingTimeType
= uint32_t¶
Public Functions
-
Timer1Api
()¶
-
~Timer1Api
()¶
-
String
name
() const
-
String
toString
() const
-
operator String
() const
Public Static Functions
-
static constexpr const char *
typeName
()¶
-
static constexpr TickType
minTicks
()¶
-
static constexpr TickType
maxTicks
()¶
-
static TickType
ticks
()¶
-
static void
setCallback
(TimerCallback callback, void *arg)¶
-
static void
setInterval
(TickType interval)¶
-
static TickType
getInterval
()¶
-
static bool
isArmed
()¶
-
static void
arm
(bool repeating)¶
-
static void
disarm
()¶
-
using
Software timer queues¶
Sming has one timer queue which is managed via the Timer
and SimpleTimer
classes.
Like hardware timers, these are callback timers, but the callback handlers execute in the task context so there are no special restrictions on what you can do there.
Because of this, however, these timers are less precise hardware timers, and the accuracy generally depends on how busy the CPU is.
Timers can be ‘one-shot’, for timing single events, or ‘auto-reset’ repetitive timers. A repetitive timer will ensure that time intervals between successive callbacks are consistent.
Timer¶
The Timer
class is the most flexible way to use software timers, supporting extended time intervals
and delegate callback functions so you can use it with class methods, capturing lambdas, etc.
-
group
timer
Extended timer queue class.
Typedefs
-
typedef std::function<void()>
TimerDelegateStdFunction
¶
-
template <class TimerClass>
classOsTimer64Api
: public CallbackTimerApi<OsTimer64Api<TimerClass>>¶ - #include <Timer.h>
Class template implementing an extended OS Timer with 64-bit microsecond times and delegate callback support.
Public Types
-
template<>
usingClock
= OsTimerApi::Clock¶
-
template<>
usingTickType
= uint64_t¶
-
template<>
usingTimeType
= uint64_t¶
Public Functions
-
OsTimer64Api
()¶
-
~OsTimer64Api
()¶
-
bool
isArmed
() const
-
TickType
ticks
() const
-
void
setCallback
(TimerCallback callback, void *arg)¶
-
void
setCallback
(TimerDelegate delegateFunction)¶
-
void
setInterval
(TickType interval)
-
TickType
getInterval
() const¶
-
void
arm
(bool repeating)
-
void
disarm
()
-
String
name
() const
-
String
toString
() const
-
operator String
() const
Public Members
-
TimerCallback
func
= nullptr
-
void *
arg
= nullptr
Public Static Functions
-
static constexpr const char *
typeName
()
-
static constexpr TickType
minTicks
()
-
static constexpr TickType
maxTicks
()
-
template<>
-
template <typename TimerApi>
classDelegateCallbackTimer
: public CallbackTimer<TimerApi>¶ - #include <Timer.h>
Class template adding delegate callback method support to the basic CallbackTimer template.
Public Types
-
template<>
usingMillis
= NanoTime::TimeSource<Clock, NanoTime::Milliseconds, uint32_t>
-
template<>
usingMicros
= NanoTime::TimeSource<Clock, NanoTime::Microseconds, TimeType>
Public Functions
-
template <TimeType microseconds>
DelegateCallbackTimer &initializeUs
(TimerDelegate delegateFunction) Initialise timer in microseconds, with static check.
- Template Parameters
microseconds
: Timer interval in microseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
template <uint32_t milliseconds>
DelegateCallbackTimer &initializeMs
(TimerDelegate delegateFunction) Initialise hardware timer in milliseconds, with static check.
- Template Parameters
milliseconds
: Timer interval in milliseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeMs
(uint32_t milliseconds, TimerDelegate delegateFunction) Initialise millisecond timer.
- Note
- Delegate callback method
- Parameters
milliseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
DelegateCallbackTimer &
initializeUs
(uint32_t microseconds, TimerDelegate delegateFunction) Initialise microsecond timer.
- Note
- Delegate callback method
- Parameters
microseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
void
setCallback
(TimerDelegate delegateFunction) Set timer trigger function using Delegate callback method.
- Note
- Don’t use this for interrupt timers
- Parameters
delegateFunction
: Function to be called on timer trigger
-
template <NanoTime::Unit unit, TimeType time>
CallbackTimer &initialize
(TimerCallback callback, void *arg = nullptr) Initialise timer with an interval (static check) and callback.
- Note
- If interval out of range compilation will fail with error
- Template Parameters
unit
: Time unit for intervaltime
: Timer interval
- Parameters
callback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
template <NanoTime::Unit unit>
CallbackTimer &initialize
(TimeType time, TimerCallback callback, void *arg = nullptr) Initialise timer with an interval and callback.
- Template Parameters
unit
: Time unit for interval
- Parameters
time
: Timer intervalcallback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
template <TimeType microseconds>
CallbackTimer &initializeUs
(TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds (static check) with Timer Callback and optional argument.
-
template <TimeType microseconds>
CallbackTimer &initializeUs
(InterruptCallback callback = nullptr) Initialise timer in microseconds (static check) with optional Interrupt Callback (no argument)
-
CallbackTimer &
initializeUs
(TimeType microseconds, TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(TimeType microseconds, InterruptCallback callback = nullptr) Initialise timer in microseconds with optional Interrupt Callback (no arg)
-
template <uint32_t milliseconds>
CallbackTimer &initializeMs
(TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds (static check) with Timer Callback and optional argument.
-
template <uint32_t milliseconds>
CallbackTimer &initializeMs
(InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds (static check) and optional Interrupt Callback (no arg)
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds with optional Interrupt Callback (no arg)
-
bool
start
(bool repeating = true) Start timer running.
- Parameters
repeating
: True to restart timer when it triggers, false for one-shot (Default: true)
- Return Value
bool
: True if timer started
-
bool
startOnce
() Start one-shot timer.
- Note
- Timer starts and will run for configured period then stop
- Return Value
bool
: True if timer started
-
void
stop
() Stops timer.
-
bool
restart
() Restart timer.
- Note
- Timer is stopped then started with current configuration
- Return Value
bool
: True if timer started
-
bool
isStarted
() const Check if timer is started.
- Return Value
bool
: True if started
-
TickType
getInterval
() const Get timer interval in clock ticks.
-
bool
checkInterval
(TickType ticks) const Check timer interval is valid.
- Parameters
ticks
: Interval to check
- Return Value
bool
: true if interval is within acceptable range for this timer
-
bool
setInterval
(TickType ticks) Set timer interval in timer ticks.
- Parameters
ticks
: Interval in timer ticks
-
template <TimeType ticks>
voidsetInterval
() Set timer interval in timer ticks (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Interval in ticks
-
template <NanoTime::Unit unit, TimeType time>
voidsetInterval
() Set timer interval in specific time unit (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
:time
: Interval to set
-
template <NanoTime::Unit unit>
boolsetInterval
(TimeType time) Set timer interval in timer ticks.
- Template Parameters
unit
:
- Parameters
time
: Interval in given units
-
bool
setIntervalUs
(TimeType microseconds) Set timer interval in microseconds.
-
template <TimeType microseconds>
voidsetIntervalUs
() Set timer interval in microseconds (static check)
-
bool
setIntervalMs
(uint32_t milliseconds) Set timer interval in milliseconds.
-
template <uint32_t milliseconds>
voidsetIntervalMs
() Set timer interval in milliseconds (static check)
-
void
setCallback
(TimerCallback callback, void *arg = nullptr) Set timer trigger callback.
- Parameters
callback
: Function to call when timer triggersarg
: Optional argument passed to callback
-
void
setCallback
(InterruptCallback callback) Set timer trigger callback.
- Note
- Provided for convenience where callback argument not required
- Parameters
callback
: Function to call when timer triggers
Public Static Functions
-
static constexpr Millis
millis
() Get a millisecond time source.
-
static constexpr Micros
micros
() Get a microsecond time source.
-
template <uint64_t us>
static constexpr uint64_tusToTicks
() Convert microsecond count into timer ticks.
-
static TickType
usToTicks
(TimeType time) Convert microsecond count into timer ticks.
-
template <uint64_t ticks>
static constexpr uint64_tticksToUs
() Convert timer ticks into microseconds.
-
static TimeType
ticksToUs
(TickType ticks) Convert timer ticks into microseconds.
-
template <uint64_t ticks>
static constexpr voidcheckInterval
() Check timer interval in ticks is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Timer interval to check
-
template <NanoTime::Unit unit, uint64_t time>
static constexpr voidcheckInterval
() Check timer interval in specific time unit is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
: Time unit for intervaltime
: Interval to check
-
template <uint64_t milliseconds>
static constexpr voidcheckIntervalMs
() Check timer interval in milliseconds is valid (static check)
-
template <uint64_t microseconds>
static constexpr voidcheckIntervalUs
() Check timer interval in microseconds is valid (static check)
-
template<>
-
class
Timer
: public DelegateCallbackTimer<OsTimer64Api<Timer>>¶ - #include <Timer.h>
Callback timer class.
Subclassed by Profiling::MinMaxTimes< Timer >
Public Types
-
template<>
usingMillis
= NanoTime::TimeSource<Clock, NanoTime::Milliseconds, uint32_t>
-
template<>
usingMicros
= NanoTime::TimeSource<Clock, NanoTime::Microseconds, TimeType>
Public Functions
-
DelegateCallbackTimer &
initializeUs
(TimerDelegate delegateFunction) Initialise timer in microseconds, with static check.
- Template Parameters
microseconds
: Timer interval in microseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeUs
(uint32_t microseconds, TimerDelegate delegateFunction) Initialise microsecond timer.
- Note
- Delegate callback method
- Parameters
microseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeUs
(TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(InterruptCallback callback = nullptr) Initialise timer in microseconds (static check) with optional Interrupt Callback (no argument)
-
CallbackTimer &
initializeUs
(TimeType microseconds, TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(TimeType microseconds, InterruptCallback callback = nullptr) Initialise timer in microseconds with optional Interrupt Callback (no arg)
-
DelegateCallbackTimer &
initializeMs
(TimerDelegate delegateFunction) Initialise hardware timer in milliseconds, with static check.
- Template Parameters
milliseconds
: Timer interval in milliseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeMs
(uint32_t milliseconds, TimerDelegate delegateFunction) Initialise millisecond timer.
- Note
- Delegate callback method
- Parameters
milliseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeMs
(TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds (static check) and optional Interrupt Callback (no arg)
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds with optional Interrupt Callback (no arg)
-
void
setCallback
(TimerDelegate delegateFunction) Set timer trigger function using Delegate callback method.
- Note
- Don’t use this for interrupt timers
- Parameters
delegateFunction
: Function to be called on timer trigger
-
void
setCallback
(TimerCallback callback, void *arg = nullptr) Set timer trigger callback.
- Parameters
callback
: Function to call when timer triggersarg
: Optional argument passed to callback
-
void
setCallback
(InterruptCallback callback) Set timer trigger callback.
- Note
- Provided for convenience where callback argument not required
- Parameters
callback
: Function to call when timer triggers
-
CallbackTimer &
initialize
(TimerCallback callback, void *arg = nullptr) Initialise timer with an interval (static check) and callback.
- Note
- If interval out of range compilation will fail with error
- Template Parameters
unit
: Time unit for intervaltime
: Timer interval
- Parameters
callback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
CallbackTimer &
initialize
(TimeType time, TimerCallback callback, void *arg = nullptr) Initialise timer with an interval and callback.
- Template Parameters
unit
: Time unit for interval
- Parameters
time
: Timer intervalcallback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
bool
start
(bool repeating = true) Start timer running.
- Parameters
repeating
: True to restart timer when it triggers, false for one-shot (Default: true)
- Return Value
bool
: True if timer started
-
bool
startOnce
() Start one-shot timer.
- Note
- Timer starts and will run for configured period then stop
- Return Value
bool
: True if timer started
-
void
stop
() Stops timer.
-
bool
restart
() Restart timer.
- Note
- Timer is stopped then started with current configuration
- Return Value
bool
: True if timer started
-
bool
isStarted
() const Check if timer is started.
- Return Value
bool
: True if started
-
TickType
getInterval
() const Get timer interval in clock ticks.
-
bool
checkInterval
(TickType ticks) const Check timer interval is valid.
- Parameters
ticks
: Interval to check
- Return Value
bool
: true if interval is within acceptable range for this timer
-
bool
setInterval
(TickType ticks) Set timer interval in timer ticks.
- Parameters
ticks
: Interval in timer ticks
-
void
setInterval
() Set timer interval in timer ticks (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Interval in ticks
-
void
setInterval
() Set timer interval in specific time unit (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
:time
: Interval to set
-
bool
setInterval
(TimeType time) Set timer interval in timer ticks.
- Template Parameters
unit
:
- Parameters
time
: Interval in given units
-
bool
setIntervalUs
(TimeType microseconds) Set timer interval in microseconds.
-
void
setIntervalUs
() Set timer interval in microseconds (static check)
-
bool
setIntervalMs
(uint32_t milliseconds) Set timer interval in milliseconds.
-
void
setIntervalMs
() Set timer interval in milliseconds (static check)
Public Static Functions
-
static constexpr Millis
millis
() Get a millisecond time source.
-
static constexpr Micros
micros
() Get a microsecond time source.
-
static constexpr uint64_t
usToTicks
() Convert microsecond count into timer ticks.
-
static TickType
usToTicks
(TimeType time) Convert microsecond count into timer ticks.
-
static constexpr uint64_t
ticksToUs
() Convert timer ticks into microseconds.
-
static TimeType
ticksToUs
(TickType ticks) Convert timer ticks into microseconds.
-
static constexpr void
checkInterval
() Check timer interval in ticks is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Timer interval to check
-
static constexpr void
checkInterval
() Check timer interval in specific time unit is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
: Time unit for intervaltime
: Interval to check
-
static constexpr void
checkIntervalMs
() Check timer interval in milliseconds is valid (static check)
-
static constexpr void
checkIntervalUs
() Check timer interval in microseconds is valid (static check)
Protected Types
-
template<>
usingClock
= OsTimerApi::Clock
-
template<>
usingTickType
= uint64_t
-
template<>
usingTimeType
= uint64_t
Protected Functions
-
bool
isArmed
() const
-
TickType
ticks
() const
-
void
arm
(bool repeating)
-
void
disarm
()
-
String
name
() const
-
String
toString
() const
-
operator String
() const
Protected Attributes
-
TimerCallback
func
-
void *
arg
Protected Static Functions
-
static constexpr const char *
typeName
()
-
static constexpr TickType
minTicks
()
-
static constexpr TickType
maxTicks
()
-
template<>
-
class
AutoDeleteTimer
: public DelegateCallbackTimer<OsTimer64Api<AutoDeleteTimer>>¶ - #include <Timer.h>
Auto-delete callback timer class.
Public Types
-
template<>
usingMillis
= NanoTime::TimeSource<Clock, NanoTime::Milliseconds, uint32_t>¶
-
template<>
usingMicros
= NanoTime::TimeSource<Clock, NanoTime::Microseconds, TimeType>¶
Public Functions
-
DelegateCallbackTimer &
initializeUs
(TimerDelegate delegateFunction) Initialise timer in microseconds, with static check.
- Template Parameters
microseconds
: Timer interval in microseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeUs
(uint32_t microseconds, TimerDelegate delegateFunction) Initialise microsecond timer.
- Note
- Delegate callback method
- Parameters
microseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeUs
(TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(InterruptCallback callback = nullptr) Initialise timer in microseconds (static check) with optional Interrupt Callback (no argument)
-
CallbackTimer &
initializeUs
(TimeType microseconds, TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(TimeType microseconds, InterruptCallback callback = nullptr) Initialise timer in microseconds with optional Interrupt Callback (no arg)
-
DelegateCallbackTimer &
initializeMs
(TimerDelegate delegateFunction) Initialise hardware timer in milliseconds, with static check.
- Template Parameters
milliseconds
: Timer interval in milliseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeMs
(uint32_t milliseconds, TimerDelegate delegateFunction) Initialise millisecond timer.
- Note
- Delegate callback method
- Parameters
milliseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeMs
(TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds (static check) and optional Interrupt Callback (no arg)
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds with optional Interrupt Callback (no arg)
-
void
setCallback
(TimerDelegate delegateFunction) Set timer trigger function using Delegate callback method.
- Note
- Don’t use this for interrupt timers
- Parameters
delegateFunction
: Function to be called on timer trigger
-
void
setCallback
(TimerCallback callback, void *arg = nullptr) Set timer trigger callback.
- Parameters
callback
: Function to call when timer triggersarg
: Optional argument passed to callback
-
void
setCallback
(InterruptCallback callback) Set timer trigger callback.
- Note
- Provided for convenience where callback argument not required
- Parameters
callback
: Function to call when timer triggers
-
CallbackTimer &
initialize
(TimerCallback callback, void *arg = nullptr) Initialise timer with an interval (static check) and callback.
- Note
- If interval out of range compilation will fail with error
- Template Parameters
unit
: Time unit for intervaltime
: Timer interval
- Parameters
callback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
CallbackTimer &
initialize
(TimeType time, TimerCallback callback, void *arg = nullptr) Initialise timer with an interval and callback.
- Template Parameters
unit
: Time unit for interval
- Parameters
time
: Timer intervalcallback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
bool
start
(bool repeating = true) Start timer running.
- Parameters
repeating
: True to restart timer when it triggers, false for one-shot (Default: true)
- Return Value
bool
: True if timer started
-
bool
startOnce
() Start one-shot timer.
- Note
- Timer starts and will run for configured period then stop
- Return Value
bool
: True if timer started
-
void
stop
() Stops timer.
-
bool
restart
() Restart timer.
- Note
- Timer is stopped then started with current configuration
- Return Value
bool
: True if timer started
-
bool
isStarted
() const Check if timer is started.
- Return Value
bool
: True if started
-
TickType
getInterval
() const Get timer interval in clock ticks.
-
bool
checkInterval
(TickType ticks) const Check timer interval is valid.
- Parameters
ticks
: Interval to check
- Return Value
bool
: true if interval is within acceptable range for this timer
-
bool
setInterval
(TickType ticks) Set timer interval in timer ticks.
- Parameters
ticks
: Interval in timer ticks
-
void
setInterval
() Set timer interval in timer ticks (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Interval in ticks
-
void
setInterval
() Set timer interval in specific time unit (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
:time
: Interval to set
-
bool
setInterval
(TimeType time) Set timer interval in timer ticks.
- Template Parameters
unit
:
- Parameters
time
: Interval in given units
-
bool
setIntervalUs
(TimeType microseconds) Set timer interval in microseconds.
-
void
setIntervalUs
() Set timer interval in microseconds (static check)
-
bool
setIntervalMs
(uint32_t milliseconds) Set timer interval in milliseconds.
-
void
setIntervalMs
() Set timer interval in milliseconds (static check)
Public Static Functions
-
static constexpr Millis
millis
() Get a millisecond time source.
-
static constexpr Micros
micros
() Get a microsecond time source.
-
static constexpr uint64_t
usToTicks
() Convert microsecond count into timer ticks.
-
static TickType
usToTicks
(TimeType time) Convert microsecond count into timer ticks.
-
static constexpr uint64_t
ticksToUs
() Convert timer ticks into microseconds.
-
static TimeType
ticksToUs
(TickType ticks) Convert timer ticks into microseconds.
-
static constexpr void
checkInterval
() Check timer interval in ticks is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Timer interval to check
-
static constexpr void
checkInterval
() Check timer interval in specific time unit is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
: Time unit for intervaltime
: Interval to check
-
static constexpr void
checkIntervalMs
() Check timer interval in milliseconds is valid (static check)
-
static constexpr void
checkIntervalUs
() Check timer interval in microseconds is valid (static check)
Protected Types
-
template<>
usingClock
= OsTimerApi::Clock¶
-
template<>
usingTickType
= uint64_t¶
-
template<>
usingTimeType
= uint64_t¶
Protected Functions
-
bool
isArmed
() const
-
TickType
ticks
() const
-
void
arm
(bool repeating)
-
void
disarm
()
-
String
name
() const
-
String
toString
() const
-
operator String
() const
Protected Attributes
-
TimerCallback
func
-
void *
arg
Protected Static Functions
-
static constexpr const char *
typeName
()
-
static constexpr TickType
minTicks
()
-
static constexpr TickType
maxTicks
()
-
template<>
-
typedef std::function<void()>
Simple Timer¶
The SimpleTimer
class only supports regular function callbacks, but if you don’t need
the additional functionality that a regular Timer
offers then it will save some RAM.
-
group
simple_timer
Basic timer queue class.
Typedefs
-
using
SimpleTimer
= CallbackTimer<OsTimerApi>¶ Basic callback timer.
- Note
- For delegate callback support and other features see
Timer
class.
-
class
OsTimerApi
: public CallbackTimerApi<OsTimerApi>¶ - #include <SimpleTimer.h>
Implements common system callback timer API.
-
using
Callback Timer API¶
-
template <typename TimerApi>
classCallbackTimer
: protected TimerApi¶ Callback timer class template.
- Note
- Methods return object reference for Method Chaining http://en.wikipedia.org/wiki/Method_chaining This class template provides basic C-style callbacks for best performance
- Template Parameters
TimerApi
: The physical timer implementation
Subclassed by DelegateCallbackTimer< TimerApi >
Public Types
-
template<>
usingMillis
= NanoTime::TimeSource<Clock, NanoTime::Milliseconds, uint32_t>¶
-
template<>
usingMicros
= NanoTime::TimeSource<Clock, NanoTime::Microseconds, TimeType>¶
Public Functions
-
template <NanoTime::Unit unit, TimeType time>
CallbackTimer &initialize
(TimerCallback callback, void *arg = nullptr) Initialise timer with an interval (static check) and callback.
- Note
- If interval out of range compilation will fail with error
- Template Parameters
unit
: Time unit for intervaltime
: Timer interval
- Parameters
callback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
template <NanoTime::Unit unit>
CallbackTimer &initialize
(TimeType time, TimerCallback callback, void *arg = nullptr) Initialise timer with an interval and callback.
- Template Parameters
unit
: Time unit for interval
- Parameters
time
: Timer intervalcallback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
template <TimeType microseconds>
CallbackTimer &initializeUs
(TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds (static check) with Timer Callback and optional argument.
-
template <TimeType microseconds>
CallbackTimer &initializeUs
(InterruptCallback callback = nullptr) Initialise timer in microseconds (static check) with optional Interrupt Callback (no argument)
-
CallbackTimer &
initializeUs
(TimeType microseconds, TimerCallback callback, void *arg = nullptr) Initialise timer in microseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(TimeType microseconds, InterruptCallback callback = nullptr) Initialise timer in microseconds with optional Interrupt Callback (no arg)
-
template <uint32_t milliseconds>
CallbackTimer &initializeMs
(TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds (static check) with Timer Callback and optional argument.
-
template <uint32_t milliseconds>
CallbackTimer &initializeMs
(InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds (static check) and optional Interrupt Callback (no arg)
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, TimerCallback callback, void *arg = nullptr) Initialise hardware timer in milliseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, InterruptCallback callback = nullptr) Initialise hardware timer in milliseconds with optional Interrupt Callback (no arg)
-
bool
start
(bool repeating = true) Start timer running.
- Parameters
repeating
: True to restart timer when it triggers, false for one-shot (Default: true)
- Return Value
bool
: True if timer started
-
bool
startOnce
() Start one-shot timer.
- Note
- Timer starts and will run for configured period then stop
- Return Value
bool
: True if timer started
-
void
stop
() Stops timer.
-
bool
restart
() Restart timer.
- Note
- Timer is stopped then started with current configuration
- Return Value
bool
: True if timer started
-
bool
isStarted
() const Check if timer is started.
- Return Value
bool
: True if started
-
TickType
getInterval
() const Get timer interval in clock ticks.
-
bool
checkInterval
(TickType ticks) const Check timer interval is valid.
- Parameters
ticks
: Interval to check
- Return Value
bool
: true if interval is within acceptable range for this timer
-
bool
setInterval
(TickType ticks) Set timer interval in timer ticks.
- Parameters
ticks
: Interval in timer ticks
-
template <TimeType ticks>
voidsetInterval
() Set timer interval in timer ticks (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Interval in ticks
-
template <NanoTime::Unit unit, TimeType time>
voidsetInterval
() Set timer interval in specific time unit (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
:time
: Interval to set
-
template <NanoTime::Unit unit>
boolsetInterval
(TimeType time) Set timer interval in timer ticks.
- Template Parameters
unit
:
- Parameters
time
: Interval in given units
-
bool
setIntervalUs
(TimeType microseconds) Set timer interval in microseconds.
-
template <TimeType microseconds>
voidsetIntervalUs
() Set timer interval in microseconds (static check)
-
bool
setIntervalMs
(uint32_t milliseconds) Set timer interval in milliseconds.
-
template <uint32_t milliseconds>
voidsetIntervalMs
() Set timer interval in milliseconds (static check)
-
void
setCallback
(TimerCallback callback, void *arg = nullptr) Set timer trigger callback.
- Parameters
callback
: Function to call when timer triggersarg
: Optional argument passed to callback
-
void
setCallback
(InterruptCallback callback) Set timer trigger callback.
- Note
- Provided for convenience where callback argument not required
- Parameters
callback
: Function to call when timer triggers
Public Static Functions
-
static constexpr Millis
millis
() Get a millisecond time source.
-
static constexpr Micros
micros
() Get a microsecond time source.
-
template <uint64_t us>
static constexpr uint64_tusToTicks
() Convert microsecond count into timer ticks.
-
static TickType
usToTicks
(TimeType time) Convert microsecond count into timer ticks.
-
template <uint64_t ticks>
static constexpr uint64_tticksToUs
() Convert timer ticks into microseconds.
-
static TimeType
ticksToUs
(TickType ticks) Convert timer ticks into microseconds.
-
template <uint64_t ticks>
static constexpr voidcheckInterval
() Check timer interval in ticks is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Timer interval to check
-
template <NanoTime::Unit unit, uint64_t time>
static constexpr voidcheckInterval
() Check timer interval in specific time unit is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
: Time unit for intervaltime
: Interval to check
-
template <uint64_t milliseconds>
static constexpr voidcheckIntervalMs
() Check timer interval in milliseconds is valid (static check)
-
template <uint64_t microseconds>
static constexpr voidcheckIntervalUs
() Check timer interval in microseconds is valid (static check)
Polled timers¶
Polled timers can be used to measure elapsed time intervals or to check for timeouts within code loops. Traditionally one might do this as follows:
const unsigned TIMEOUT_MS = 100;
unsigned start = millis();
while(millis() - start < TIMEOUT_MS) {
// do some stuff
}
unsigned elapsed = millis() - start;
Serial.print("Elapsed time: ");
Serial.print(elapsed);
Serial.println("ms");
Note
A common source of bugs when hand-coding such loops can be illustrated by this alternative:
unsigned timeout = millis() + TIMEOUT_MS;
while(millis() < timeout) {
// do some stuff
}
At first glance this looks better than the first approach as we don’t have a subtraction within the loop. However, when millis() exceeds MAXINT - TIMEOUT_MS the timeout calculation will wrap and the loop will never get executed. This takes a little under 25 days, but with microseconds it’ll happen in less than an hour. This may not be the desired behaviour.
It’s generally safer and easier to use a PolledTimer
:
OneShotFastMs timer(TIMEOUT_MS);
while(!timer.expired()) {
// do some stuff
}
auto elapsed = timer.elapsedTime(); // Returns a `NanoTime::Time` object, value with time units
Serial.print("Elapsed time: ");
Serial.println(elapsed.toString()); // Includes units in the elapsed time interval
// Show time rounded to nearest whole seconds
Serial.println(elapsed.as<NanoTime::Seconds>().toString());
If you prefer to use microseconds, use OneShotFastUs
instead or specify the units directly:
OneShotElapseTimer<NanoTime::Microseconds> timer;
Another advantage of polled timers is speed. Every call to millis (or micros) requires a calculation from clock ticks into milliseconds (or microseconds). It’s also a function call.
Polled timers measure time using hardware clock ticks, and query the hardware timer register directly without any function calls or calculations. This makes them a much better choice for tight timing loops.
Here’s the output from the BenchmarkPolledTimer module:
How many loop iterations can we achieve in 100 ms ?
Using millis(), managed 55984 iterations, average loop time = 1786ns (143 CPU cycles)
Using micros(), managed 145441 iterations, average loop time = 688ns (55 CPU cycles)
Using PolledTimer, managed 266653 iterations, average loop time = 375ns (30 CPU cycles)
API Documentation¶
-
group
polled_timer
Polled interval timers.
Unnamed Group
-
using
OneShotElapseTimer
= PolledTimer::OneShot<Timer2Clock, unit>¶
-
using
PeriodicElapseTimer
= PolledTimer::Periodic<Timer2Clock, unit>¶
-
using
OneShotFastMs
= OneShotElapseTimer<NanoTime::Milliseconds>¶
-
using
OneShotFastUs
= OneShotElapseTimer<NanoTime::Microseconds>¶
-
using
ElapseTimer
= OneShotFastUs¶
-
using
OneShotCpuCycleTimer
= PolledTimer::OneShot<CpuCycleClockNormal, units>¶
-
using
PeriodicCpuCycleTimer
= PolledTimer::Periodic<CpuCycleClockNormal, units>¶
-
using
OneShotCpuCycleTimerFast
= PolledTimer::OneShot<CpuCycleClockFast, units>¶
-
using
PeriodicCpuCycleTimerFast
= PolledTimer::Periodic<CpuCycleClockFast, units>¶
-
using
CpuCycleTimer
= OneShotCpuCycleTimer<NanoTime::Nanoseconds>¶
-
using
CpuCycleTimerFast
= OneShotCpuCycleTimerFast<NanoTime::Nanoseconds>¶
-
typedef OneShotFastMs
oneShotFastMs
¶
-
typedef OneShotFastUs
oneShotFastUs
¶
Defines
-
namespace
PolledTimer
¶ Typedefs
-
using
PolledTimer::OneShot = typedef Timer<Clock, unit, false, uint32_t>
-
using
PolledTimer::Periodic = typedef Timer<Clock, unit, true, uint32_t>
-
template <class Clock, NanoTime::Unit unit_, bool IsPeriodic, typename TimeType>
classTimer
: public NanoTime::TimeSource<Clock, unit_, TimeType>¶ - #include <PolledTimer.h>
Template class to implement a polled timer.
If the interval is set to 0, the timer will expire immediately, and remain so:
canWait()
will return false. Callcancel()
to prevent the timer from ever expiring:canExpire()
will return false. Callstart()
to set the timer going with the previously set interval. Callreset()
to set the timer with a new interval.- Note
- Intervals and expiry use ‘tick’ values which are very efficient, whereas ‘time’ values must be computed so are very slow (~100+ cycles for uint32_t, considerably more for uint64_t). The class keeps a note of a ‘start’ time (in ticks) used to determine the
elapsed()
return value. An ‘interval’ value may be given is specified, then theexpired()
method returns true. - Template Parameters
Clock
: Clock sourceunit
: Time unit for tick/time conversionsIsPeriodic
:TimeType
: Variable type to use (uint32_t or uint64_t)
A periodic timer will automatically restart when expired. A one-shot timer will remain expired until reset.
Public Types
-
template<>
usingTickType
= typename Clock::TickType¶
-
template<>
usingMargin
= NanoTime::TimeConst<Clock, NanoTime::Microseconds, POLLED_TIMER_MARGIN_US>¶
-
template<>
usingTicksConst
= TicksConst<Clock, ticks>¶
-
template<>
usingMaxClockTime
= typename Clock::template MaxTime<unit_>¶ Get the time corresponding to the maximum clock tick value.
-
template<>
usingTimeSource
= TimeSource<Clock, unit, TimeType>
-
template<>
usingTicks
= Ticks<Clock, T>
-
template<>
usingMaxTicks
= TicksConst<maxTicks_>
-
template<>
usingMaxTime
= typename MaxTicks::template TimeConst<unit>
Public Functions
-
Timer
(const TimeType &timeInterval = 0)¶ Create a Timer with optional expiry time.
- Parameters
timeInterval
: Relative time until expiry
-
void
start
()¶ Start the timer.
-
template <uint64_t timeInterval>
voidreset
()¶ Start the timer with a new expiry interval.
- Template Parameters
timeInterval
: Time to expire after last call to start()
-
template <uint64_t timeInterval>
constexpr uint32_tcheckTime
()¶ Check the given time interval is valid and return the corresponding tick count.
- Note
- If time interval is invalid fails compilation
- Template Parameters
timeInterval
:
- Return Value
uint32_t
:
-
bool
reset
(const TimeType &timeInterval)¶ Start the timer with a new expiry interval.
- See
- See
resetTicks()
- Parameters
timeInterval
: Time to expire after last call to start()
- Return Value
bool
: true on success, false on failure
-
bool
resetTicks
(const TimeType &interval)¶ Start the timer with a new expiry interval.
- Note
- If time interval is 0, timer will expire immediately, and if it exceeds the maximum interval the timer will never expire.
- Parameters
interval
: Clock ticks to expire after last call to start()
- Return Value
bool
: true on success, false if interval is out of range
-
void
cancel
()¶ Cancelling a timer means it will never expire.
-
bool
canExpire
() const¶
-
bool
canWait
() const¶
-
bool
expired
()¶ Determine if timer has expired.
- Return Value
bool
:
Public Static Functions
-
static constexpr TickType
maxInterval
()¶
-
static constexpr Margin
margin
()¶
-
static constexpr BasicRatio32
ticksPerUnit
() Number of clock ticks per unit of time.
- Return Value
BasicRatio32
: Result as a rational fraction
-
static Ratio32
ticksPerUnit
(Unit unit) Get ticks per unit as a Ratio object.
- Return Value
BasicRatio32
:
-
static constexpr MaxClockTime
maxClockTime
()
-
static constexpr TimeConst<time>
timeConst
() Obtain a TimeConst type representing the given time quantity.
- Note
- Use methods of TimeConst to obtain corresponding tick count, etc.
- Template Parameters
time
:
- Return Value
TimeConst
:
-
static constexpr TicksConst<ticks>
ticksConst
() Class template defining a fixed tick quantity.
- Note
- Use methods of TickConst to obtain corresponding time values, etc.
- Template Parameters
ticks
:
- Return Value
TicksConst
:
-
static constexpr Time<TimeType>
maxCalcTime
() The maximum time value supported by timeToTicks without overflowing.
- Return Value
TimeType
: Passing values larger than this totimeToTicks()
will truncate at maximum value
-
static constexpr Ticks<Clock, TimeType>
maxCalcTicks
() The maximum tick value supported by ticksToTime without overflowing.
- Return Value
TimeType
: Passing values larger than this toticksToTime()
will truncate at maximum value
-
static Ticks<Clock, TimeType>
timeToTicks
(TimeType time) Get the number of ticks for a given time.
- Parameters
time
:
- Return Value
TimeType
: Tick count, rounded to the nearest tick
-
static constexpr uint64_t
timeToTicks
() Get the number of ticks for a given time.
- Template Parameters
time
:
- Return Value
uint64_t
: Tick count, rounded to the nearest tick
-
static constexpr uint64_t
ticksToTime
() Get the time for a given number of clock ticks.
- Template Parameters
ticks
:
- Return Value
TimeType
: Time count, rounded to the nearest unit
-
static Time<TimeType>
ticksToTime
(TimeType ticks) Get the time for a given number of clock ticks.
- Parameters
ticks
:
- Return Value
TimeType
: Time count, rounded to the nearest unit
-
static String
toString
()
-
static constexpr const char *
typeName
()
-
static constexpr uint32_t
frequency
()
-
static constexpr MaxTicks
maxTicks
()
-
template <Unit unit>
static constexpr MaxTime<unit>maxTime
()
-
template <Unit unit, typename TimeType>
static constexpr TimeSource<unit, TimeType>timeSource
() Create a Time Source for this Clock.
- Template Parameters
unit
:TimeType
:
-
using
-
using
Timer range¶
The maximum interval for a timer varies depending on the clock source and the selected prescaler. The count may be further restricted by hardware. For example, Timer1 only provides a 23-bit count which means with a /16 prescaler (the default for HardwareTimer) it overflows after only 1.67 seconds.
It’s therefore important to check that timers are being used within their valid range. There are generally two ways to do this:
- Runtime checks
This means checking function/method return values and acting accordingly. This often gets omitted because it can lead to cluttered code, which then leads to undiagnosed bugs creeping in which can be very difficult to track down later on.
With a polled timer, you’d use one of these methods to set the time interval:
bool reset(const TimeType& timeInterval); bool resetTicks(const TimeType& interval);
They both return true on success.
- Static checks
These checks are performed during code compilation, so if a check fails the code won’t compile. In regular ‘C’ code you’d do this using #if statements, but C++ offers a much better way using static_assert.
To reset a polled timer and incorporate a static check, use this method:
template <uint64_t timeInterval> void reset();
Note that timeInterval cannot be a variable (even if it’s const) as the compiler must be able to determine its value. It must therefore be constexpr compatible.
You can use static checking to pre-validate the range for a timer before using it:
timer.checkTime<10>();
timer.checkTime<10000>();
This will throw a compile-time error if the timer is not capable of using intervals in the range 10 - 10000 microseconds (or whichever time unit you’ve selected). It doesn’t add any code to the application. If the code compiles, then you can be confident that the timer will function as expected and you don’t need to check return values.
You can see these checks in action in the Live Debug sample, which uses the HardwareTimer
with a /16 prescaler. If you change BLINK_INTERVAL_MS
to 2000 then the code will not compile.
Clocks¶
Timers and their capabilities can vary considerably. For example, Timer1 can be configured with a prescaler of 1, 16 or 256 which affects both the resolution and range of the timer. One might also consider the CPU cycle counter to have a selectable prescaler of 1 or 2, depending on whether it’s running at 80MHz or 160MHz.
A Clock
definition is a class template which allows us to query timer properties and perform time
conversions for a specific timer configuration. These definitions can be found in Sming/Platform/Clocks.h.
Note
A Clock is a purely virtual construct and does not provide any means to configure the hardware,
although it does provide the ticks()
method to obtain the current timer value.
Clocks are made more useful by TimeSource
, a generic class template defined in Sming/Core/NanoTime.h.
This provides methods to convert between time values and tick values for a specific time unit.
Let’s say we want a microsecond source using Timer2:
TimeSource<Timer2Clock, NanoTime::Microseconds, uint32_t> t2source;
We can now call methods of t2source
like this:
// What's the maximum Timer2 value in microseconds?
Serial.println(t2source.maxClockTime());
// How many clock ticks per microsecond ?
Serial.println(t2source.ticksPerUnit()); // 5/1
// How many clock ticks for 100us ?
Serial.println(t2source.template timeConst<100>().ticks());
Note that all of these values are computed at compile time. Some runtime conversions:
Serial.println(t2source.timeToTicks(100));
Serial.println(t2source.ticksToTime(10000));
The results of conversions are rounded rather than truncated, which provides more accurate results and reduces timing jitter.
For debugging purposes you can print a description:
Serial.println(t2source.toString()); // "Timer2Clock/5MHz/32-bit/microseconds"
See Sming/Core/NanoTime.h for further details.
System Clock API¶
-
template <hw_timer_clkdiv_t clkdiv>
structTimer1Clock
: public NanoTime::Clock<Timer1Clock<clkdiv>, HW_TIMER_BASE_CLK / (1 << clkdiv), uint32_t, MAX_HW_TIMER1_INTERVAL>¶ - #include <Clocks.h>
Clock implementation for Hardware Timer 1.
- Template Parameters
clkdiv
: Prescaler in use
Public Types
-
template<>
usingTickType
= uint32_t¶
-
template<>
usingTicksConst
= TicksConst<Clock, ticks>¶
-
template<>
usingTicksPerUnit
= std::ratio_divide<std::ratio<frequency_>, UnitTickRatio<unit>>¶
-
template<>
usingTimeSource
= TimeSource<Clock, unit, TimeType>¶
-
template<>
usingMaxTicks
= TicksConst<maxTicks_>¶
Public Static Functions
-
static constexpr uint32_t
prescale
()¶
-
static constexpr const char *
typeName
()¶
-
static uint32_t
ticks
()¶
-
static constexpr uint32_t
frequency
()¶
-
static constexpr MaxTicks
maxTicks
()¶
-
static constexpr MaxTime<unit>
maxTime
()¶
-
static Ratio32
ticksPerUnit
(Unit unit)¶ Get ticks per unit as a Ratio object.
- Return Value
BasicRatio32
:
-
static constexpr TimeConst<unit, time>
timeConst
()¶ Class template defining a fixed time quantity.
- Template Parameters
time
:
- Return Value
TimeConst
:
-
static constexpr TicksConst<ticks>
ticksConst
()¶ Class template defining a fixed tick quantity.
- Template Parameters
ticks
:
- Return Value
TicksConst<Clockticks>
:
-
static constexpr TimeSource<unit, TimeType>
timeSource
()¶ Create a Time Source for this Clock.
- Template Parameters
unit
:TimeType
:
-
static Ticks<TimeType>
timeToTicks
(TimeType time)¶ Get the number of ticks for a given time.
- Parameters
time
:
- Return Value
TimeType
: Tick count, rounded to the nearest tick
NanoTime¶
Utilities for handling time periods at nanosecond resolution.
-
namespace
NanoTime
¶ Enums
Functions
-
const char *
unitToLongString
(Unit unit)¶ Get a long string identifying the given time units, e.g. “seconds”.
-
template <uint64_t time, Unit unitsFrom, Unit unitsTo, typename R = std::ratio_divide<UnitTickRatio<unitsTo>, UnitTickRatio<unitsFrom>>>
constexpr uint64_tconvert
()¶ Function template to convert a constant time quantity from one unit to another.
- Note
- example:
uint32_t micros = convert<50, Milliseconds, Microseconds>();
- Template Parameters
time
: The time to convertunitsFrom
: Units fortime
parameterunitsTo
: Units for return value
- Return Value
TimeType
: Converted time
-
template <typename TimeType>
TimeTypeconvert
(const TimeType &time, Unit unitsFrom, Unit unitsTo)¶ Function template to convert a time quantity from one unit to another.
- Template Parameters
TimeType
: Variable type to use for calculation
- Parameters
time
: The time to convertunitsFrom
: Units fortime
parameterunitsTo
: Units for return value
- Return Value
TimeType
: Converted time, returns TimeType(-1) if calculation overflowed
-
template <typename T>
Time<T>time
(Unit unit, T value)¶ Helper function to create a Time and deduce the type.
-
template <Unit unitsFrom, Unit unitsTo, typename TimeType>
TimeTypeconvert
(const TimeType &time)¶ Function template to convert a time quantity from one unit to another.
- Template Parameters
unitsFrom
: Units fortime
parameterunitsTo
: Units for return valueTimeType
: Variable type to use for calculation
- Parameters
time
: The time to convert
- Return Value
TimeType
: Converted time, returns TimeType(-1) if calculation overflowed
Variables
-
constexpr BasicRatio32
unitTicks
[UnitMax
+ 1]= {
{1000000000, 1},
{1000000, 1},
{1000, 1},
{1, 1},
{1, 60},
{1, 60 * 60},
{1, 24 * 60 * 60},
}
¶ List of clock ticks for each supported unit of time.
-
template <typename ClockDef, uint32_t frequency_, typename TickType_, TickType_ maxTicks_>
structClock
¶ - #include <NanoTime.h>
Class template representing a physical Clock with fixed timing characteristics.
- Note
- Physical clocks are implemented using this as a base. The provided frequency accounts for any prescaler setting in force. Fixing this at compile time helps to avoid expensive runtime calculations and permits static range checks.
- See
- Use
TimeSource
to work with a Clock in specific time units - Template Parameters
Subclassed by NanoTime::TimeSource< Clock, unit_, TimeType >
Public Types
-
template<>
usingTickType
= TickType_¶
-
template<>
usingTicksConst
= TicksConst<Clock, ticks>¶
-
template<>
usingTicksPerUnit
= std::ratio_divide<std::ratio<frequency_>, UnitTickRatio<unit>>¶
-
template<>
usingTimeSource
= TimeSource<Clock, unit, TimeType>¶
-
template<>
usingMaxTicks
= TicksConst<maxTicks_>¶
Public Static Functions
-
static constexpr const char *
typeName
()¶
-
static constexpr uint32_t
frequency
()
-
static constexpr MaxTicks
maxTicks
()
-
template <Unit unit>
static constexpr MaxTime<unit>maxTime
()
-
static Ratio32
ticksPerUnit
(Unit unit) Get ticks per unit as a Ratio object.
- Return Value
BasicRatio32
:
-
template <Unit unit, uint64_t time>
static constexpr TimeConst<unit, time>timeConst
() Class template defining a fixed time quantity.
- Template Parameters
time
:
- Return Value
-
template <uint64_t ticks>
static constexpr TicksConst<ticks>ticksConst
() Class template defining a fixed tick quantity.
- Template Parameters
ticks
:
- Return Value
TicksConst<Clockticks>
:
-
template <Unit unit, typename TimeType>
static constexpr TimeSource<unit, TimeType>timeSource
() Create a Time Source for this Clock.
- Template Parameters
unit
:TimeType
:
-
template <Unit unit, typename TimeType>
static Ticks<TimeType>timeToTicks
(TimeType time) Get the number of ticks for a given time.
- Parameters
time
:
- Return Value
TimeType
: Tick count, rounded to the nearest tick
-
template <Unit unit, typename TimeType>
static Time<TimeType>ticksToTime
(TimeType ticks) Get the time for a given number of clock ticks.
- Parameters
ticks
:
- Return Value
TimeType
: Time count, rounded to the nearest unit
-
static String
toString
()
-
struct
Frequency
¶ - #include <NanoTime.h>
Class to represent a frequency.
Public Members
-
uint32_t
frequency
¶
-
uint32_t
-
template <typename Clock_, typename T>
structTicks
¶ - #include <NanoTime.h>
Class to handle a tick value associated with a clock.
Public Types
-
template<>
usingClock
= Clock_¶
Public Members
-
T
ticks
¶
-
template<>
-
template <class Clock_, uint64_t ticks_>
structTicksConst
¶ - #include <NanoTime.h>
Class template representing a fixed clock tick count.
- Note
- Includes compile-time range checking
- Template Parameters
Source_
:ticks_
:
Public Types
-
template<>
usingClock
= Clock_¶
-
template<>
usingTickType
= uint64_t¶
-
template<>
usingTimeType
= uint64_t¶
Public Functions
-
constexpr
operator TickType
()¶
Public Static Functions
-
static constexpr TickType
ticks
()¶
-
static constexpr void
check
()¶ Obtain the tick count with a static range check against Clock maxTicks.
- Return Value
TimeType
:
-
template <typename T>
structTime
¶ - #include <NanoTime.h>
Class to handle a simple time value with associated unit.
Friends
-
Time &
operator+
(Time lhs, const Time &rhs)¶
-
Time &
-
template <class Clock_, Unit unit_, uint64_t time_>
structTimeConst
¶ - #include <NanoTime.h>
Class template to represent a fixed time value for a specific Clock.
- Note
- Includes compile-time range checking. Time is taken as reference for conversions.
- Template Parameters
Clock_
:unit_
:time_
:
Public Types
-
template<>
usingClock
= Clock_¶
Public Functions
-
constexpr
operator uint64_t
()¶
Public Static Functions
-
static constexpr uint64_t
time
()¶
-
static Ratio32
ticksPerUnit
()¶ Get ticks per unit as a Ratio object.
- Return Value
BasicRatio32
:
-
static constexpr uint64_t
ticks
()¶ Return the corresponding tick value for the time interval.
- Return Value
TimeType
:
-
static constexpr void
check
()¶ Use this function to perform a static (compile-time) range check against Clock maxTicks.
- Return Value
TimeType
:
-
static constexpr uint64_t
clockTime
()¶ Obtain the actual Clock time by converting tick value.
- Return Value
TimeType
:
-
template <class Clock_, Unit unit_, typename TimeType_>
structTimeSource
: public Clock_¶ - #include <NanoTime.h>
Class template for accessing a Clock in specific time units.
- Note
- Includes compile-time range checking. Time is taken as reference for conversions.
- Template Parameters
Clock_
:units_
:TimeType_
: Limits range of calculations
Public Types
-
template<>
usingClock
= Clock_¶
-
template<>
usingTimeType
= TimeType_¶
-
template<>
usingTicksConst
= TicksConst<Clock, ticks>¶
Public Static Functions
-
static constexpr BasicRatio32
ticksPerUnit
()¶ Number of clock ticks per unit of time.
- Return Value
BasicRatio32
: Result as a rational fraction
-
static constexpr MaxClockTime
maxClockTime
()¶
-
template <uint64_t time>
static constexpr TimeConst<time>timeConst
()¶ Obtain a TimeConst type representing the given time quantity.
-
template <uint64_t ticks>
static constexpr TicksConst<ticks>ticksConst
()¶ Class template defining a fixed tick quantity.
- Note
- Use methods of TickConst to obtain corresponding time values, etc.
- Template Parameters
ticks
:
- Return Value
-
static constexpr Time<TimeType_>
maxCalcTime
()¶ The maximum time value supported by timeToTicks without overflowing.
- Return Value
TimeType
: Passing values larger than this totimeToTicks()
will truncate at maximum value
-
static constexpr Ticks<Clock_, TimeType_>
maxCalcTicks
()¶ The maximum tick value supported by ticksToTime without overflowing.
- Return Value
TimeType
: Passing values larger than this toticksToTime()
will truncate at maximum value
-
static Ticks<Clock_, TimeType_>
timeToTicks
(TimeType time)¶ Get the number of ticks for a given time.
- Parameters
time
:
- Return Value
TimeType
: Tick count, rounded to the nearest tick
-
template <uint64_t time>
static constexpr uint64_ttimeToTicks
()¶ Get the number of ticks for a given time.
- Template Parameters
time
:
- Return Value
uint64_t
: Tick count, rounded to the nearest tick
-
template <uint64_t ticks>
static constexpr uint64_tticksToTime
()¶ Get the time for a given number of clock ticks.
- Template Parameters
ticks
:
- Return Value
TimeType
: Time count, rounded to the nearest unit
-
struct
TimeValue
¶ - #include <NanoTime.h>
A time time broken into its constituent elements.
- Note
- Useful for analysing and printing time values
Public Functions
-
TimeValue
()¶
-
template <typename TimeType>
TimeValue
(Unit unit, TimeType time)¶ Resolve a time value into constituent components.
- Parameters
time
: The time to resolveunit
: Units for given time
-
uint32_t
getMicroseconds
() const¶ Get sub-second time entirely in microseconds.
-
uint32_t
getNanoseconds
() const¶ Get sub-second time entirely in nanoseconds.
-
operator String
() const¶
-
template <Unit unit>
structUnitTickRatio
¶ - #include <NanoTime.h>
Class template to define tick std::ratio type.
- Note
- This would be preferable:
template <Unit unit> using UnitTickRatio = std::ratio<unitTicks[unit].num, unitTicks[unit].den>;
But GCC 4.8 doesn’t like it (lvalue required as unary ‘&’ operand) - Template Parameters
unit
:
- Return Value
std::ratio
: Ticks per second
-
const char *
Core Framework¶
Program Space¶
Support for storing and accessing data from Program Space (flash memory).
A string literal (e.g. “string”) used in code gets emitted to the .rodata segment by the compiler. That means it gets read into RAM at startup and remains there.
To avoid this, and reclaim the RAM, the data must be stored in a different segment. This is done
using the PROGMEM
macro.
Such strings are usually defined using the PSTR()
macro, which also ensures that any duplicate
strings are merged and thus avoids storing them more than once. This is particularly beneficial
for debugging strings.
Templated code¶
Attention
PROGMEM
may not work when used in templated code.
GCC silently ignores ‘section attributes’ in templated code, which means const variables will remain
in the default .rodata
section.
Strings defined using PSTR()
(and related macros) or FlashString definitions
are handled correctly because internally they use special names (__pstr__
and __fstr__
)
which the linker picks up on.
memcpy_aligned¶
Once in flash memory, string data must be read into RAM before it can be used. Accessing the flash memory directly is awkard. If locations are not strictly accessed as 4-byte words the system will probably crash; I say ‘probably’ because sometimes it just behaves weirdly if the RAM address isn’t aligned.
So, the location being accessed, the RAM buffer it’s being copied to and the length all have to be
word-aligned, i.e. integer multiples of 4 bytes.
If these conditions are satisfied, then it’s safe to use a regular memcpy()
call.
However, you are strongly discouraged from doing this.
Instead, use memcpy_aligned()
, which will check the parameters and raise an assertion in debug mode
if they are incorrect.
FakePgmSpace¶
Standard string functions such as memcpy_P()
, strcpy_P()
, etc. are provided to enable
working with P-strings. With the new arduino-provided toolchains these are now part of the standard
library, however Sming has some additions and differences.
F()
Loads a String object with the given text, which is allocated to flash:
String s = F("test");
Note
The
F()
macro differs from the Arduino/Esp8266 implementation in that it instantiates aString
object.Since the length of the string is known at compile-time, it can be passed to the String constructor which avoids an additional call to
strlen_P()
._F()
Like F() except buffer is allocated on stack. Most useful where nul-terminated data is required:
m_printf(_F("C-style string\n"));
This macro is faster than
F()
, but you need to be careful as the temporary stack buffer becomes invalid as soon as the containing block goes out of scope. Used as a function parameter, that means the end of the function call.Examples:
println(_F("Debug started")); commandOutput->print(_F("Welcome to the Tcp Command executor\r\n"));
Bad:
char* s = _F("string")
An assignment such as this will not work because the temporary will be out of scope after the statement, hence s will point to garbage. In this instance
PSTR_ARRAY(s, "string")
can be used.DEFINE_PSTR()
- Declares a PSTR stored in flash. The variable (name) points to flash memory so must be accessed using the appropriate xxx_P function.
LOAD_PSTR()
Loads pre-defined PSTR into buffer on stack:
// The ``_LOCAL`` macro variants include static allocation DEFINE_PSTR_LOCAL(testFlash, "This is a test string\n"); LOAD_PSTR(test, testFlash) m_printf(test);
PSTR_ARRAY()
Create and load a string into the named stack buffer. Unlike
_F()
, this ensures a loaded string stays in scope:String testfunc() { //char * test = "This is a string"; <<- BAD PSTR_ARRAY(test, "This is a string"); m_printf(test); ... return test; // Implicit conversion to String }
Both DEFINE_PSTR()
and PSTR_ARRAY()
load a PSTR into a stack buffer, but using
sizeof()
on that buffer will return a larger value than the string itself because it’s aligned.
Calling sizeof()
on the original flash data will get the right value.
If it’s a regular nul-terminated string then strlen_P()
will get the length, although it’s
time-consuming.
FlashString¶
For efficient, fast and flexible use of PROGMEM data see FlashString.
API Documentation¶
-
FLASH_MEMORY_START_ADDR
¶
-
PROGMEM
¶ Place entity into flash memory.
Attach to const variable declaration to have it stored in flash memory
Such variables should not be accessed like regular pointers as aligned instructions are required. Use the provided library functions, such as
memcpy_P
, instead.
-
PROGMEM_PSTR
¶ Place NUL-terminated string data into flash memory.
Duplicate string data will be merged according to the rules laid out in https://sourceware.org/binutils/docs/as/Section.html
-
PSTR
(str)¶ Define and use a NUL-terminated ‘C’ flash string inline.
- Note
- Uses string section merging so must not contain embedded NULs
- Parameters
str
:
- Return Value
char[]
: In flash memory, access using flash functions
-
PGM_P
¶ Identifies a char pointer as living in flash memory Use to clarify code.
-
PRIPSTR
¶ Remove ?
-
void *
memcpy_aligned
(void *dst, const void *src, unsigned len)¶ copy memory aligned to word boundaries
dst and src must be aligned to word (4-byte) boundaries
len
will be rounded up to the nearest word boundary, so the dst buffer MUST be large enough for this.- Parameters
dst
:src
:len
: Size of the source data
-
int
memcmp_aligned
(const void *ptr1, const void *ptr2, unsigned len)¶ compare memory aligned to word boundaries
ptr1 and ptr2 must all be aligned to word (4-byte) boundaries. len is rounded up to the nearest word boundary
- Parameters
ptr1
:ptr2
:len
:
- Return Value
int
: 0 if all bytes match
-
FLASH_MEMORY_START_ADDR
-
isFlashPtr
(ptr)¶ Simple check to determine if a pointer refers to flash memory.
-
IS_ALIGNED
(_x)¶ determines if the given value is aligned to a word (4-byte) boundary
-
ALIGNUP4
(n)¶ Align a size up to the nearest word boundary.
-
ALIGNDOWN4
(n)¶ Align a size down to the nearest word boundary.
-
printf_P_heap
(f_P, ...)¶
-
printf_P_stack
(f_P, ...)¶
-
printf_P
¶
-
PSTR_COUNTED
(str)¶ Define and use a counted flash string inline.
- Note
- Strings are treated as binary data so may contain embedded NULs, but duplicate strings are not merged.
- Parameters
str
:
- Return Value
char[]
: In flash memory, access using flash functions
-
_F
(str)¶ Declare and use a flash string inline.
- Parameters
str
:
- Return Value
char[]
: Returns a pointer to a stack-allocated buffer of the precise size required.
-
DEFINE_PSTR
(name, str)¶ define a PSTR
- Parameters
name
: name of stringstr
: the string data
-
DEFINE_PSTR_LOCAL
(name, str)¶ define a PSTR for local (static) use
- Parameters
name
: name of stringstr
: the string data
-
DECLARE_PSTR
(name)¶ Declare a global reference to a PSTR instance.
- Parameters
name
:
-
LOAD_PSTR
(name, flash_str)¶ Create a local (stack) buffer called
name
and load it with flash data.If defining a string within a function or other local context, must declare static.
- Parameters
name
:flash_str
: Content stored in flash. The compiler knows its size (length + nul), which is rounded up to multiple of 4 bytes for fast copy.
Example:
void testfunc() { static DEFINE_PSTR(test, "This is a test string\n"); m_printf(LOAD_PSTR(test)); }
-
_FLOAD
(pstr)¶
-
PSTR_ARRAY
(name, str)¶ Define a flash string and load it into a named array buffer on the stack.
For example, this:
PSTR_ARRAY(myText, "some text");
- Note
- Must not contain embedded NUL characters
is roughly equivalent to this:
char myText[ALIGNED_SIZE] = "some text";
where ALIGNED_SIZE is the length of the text (including NUL terminator) rounded up to the next word boundary. To get the length of the text, excluding NUL terminator, use:
sizeof(PSTR_myText) - 1
Core Data Classes¶
CStringArray¶
This is a class to manage a double NUL-terminated list of strings, such as "one\0two\0three\0"
.
It’s similar in operation to Vector<String>
, but more memory-efficient as all the data is
stored in a single String
object. (CStringArray is a subclass of String.)
You can see some examples in Sming/Core/DateTime.cpp and Sming/Core/Network/WebConstants.cpp.
Each value in the sequence is terminated by a NUL character \0
.
For clarity, placing one string per line is suggested:
// ["one", "two", "three"]
CStringArray csa = F(
"one\0"
"two\0"
"three\0"
);
Note use of the F()
macro.
Assignments require a length because of the NUL characters, so this won’t work as expected:
// ["one"]
CStringArray csa =
"one\0"
"two\0"
"three\0";
When assigning sequences, the final NUL separator may be omitted (it will be added automatically):
// ["one", "two", "three"]
CStringArray csa = F(
"one\0"
"two\0"
"three"
);
Sequences may contain empty values, so this example contains four values:
// ["one", "two", "three", ""]
CStringArray csa = F(
"one\0"
"two\0"
"three\0"
"\0"
);
Elements can be added using standard concatenation operators:
CStringArray arr;
arr += "string1";
arr += 12;
arr += 5.4;
arr += F("data");
Be mindful that each call may require a heap re-allocation, so consider
estimating or calculating the required space and using String::reserve()
:
CStringArray arr;
arr.reserve(250);
// now add content
You can use a single FlashString
containing these values and load them all
at the same time into a CStringArray:
DEFINE_FSTR_LOCAL(fstr_list,
"a\0"
"b\0"
"c\0"
"d\0"
"e\0"
);
CStringArray list(fstr_list);
for(unsigned i = 0; i < list.count(); ++i) {
debug_i("list[%u] = '%s'", i, list[i]);
}
Note
The entire FlashString is loaded into RAM so better suited for occasional lookups or if instantiated outside of a loop.
You may find FSTR::Array
, FSTR::Vector
or FSTR::Map
more appropriate.
See FlashString for details.
Looping by index is slow because the array must be scanned from the start for each access. Iterators are simpler to use and much more efficient:
for(auto s: list) {
debug_i("'%s'", s);
}
For more complex operations:
CStringArray::Iterator pos;
for(auto it = list.begin(); it != list.end(); ++it) {
debug_i("list[%u] = '%s' @ %u", it.index(), *it, it.offset());
// Can use direct comparison with const char* or String
if(it == "c") {
pos = it; // Note position
}
}
if(pos) {
debug_i("Item '%s' found at index %u, offset %u", pos.str(), pos.index(), pos.offset());
} else {
debug_i("Item not found");
}
- Advantages
- More memory efficient Uses only a single heap allocation (assuming content is passed to constructor) Useful for simple lookups, e.g. mapping enumerated values to strings
- Disadvantages
- Slower. Items must be iterated using multiple strlen() calls Ordering and insertions / deletions not supported
An example of use can be found in Sming/Core/Network/Http/HttpHeaders.h.
-
class
CStringArray
: String¶ Class to manage a double null-terminated list of strings, such as “one\0two\0three\0”.
Constructors
-
CStringArray
(const char *cstr = nullptr)¶
-
CStringArray
(const char *cstr, unsigned int length)¶
-
CStringArray
(flash_string_t pstr, int length = -1)¶
-
CStringArray
(const FlashString &fstr)¶
Concatenation operators
-
CStringArray &
operator+=
(const String &str)¶
-
CStringArray &
operator+=
(const char *cstr)¶
-
template <typename T>
CStringArray &operator+=
(T value)¶ Append numbers, etc. to the array.
- Parameters
value
: char, int, float, etc. as supported by String
Concatenation methods
Works with built-in types. On failure, the string is left unchanged. If the argument is null or invalid, the concatenation is considered unsucessful.
- Return Value
bool
: true on success, false on failure
-
bool
concat
(const FlashString &fstr)¶
-
bool
concat
(const char *cstr)¶
-
bool
concat
(const char *cstr, size_t length)¶
-
bool
concat
(char c)¶
-
bool
concat
(unsigned char num)¶
-
bool
concat
(int num)¶
-
bool
concat
(unsigned int num)¶
-
bool
concat
(long num)¶
-
bool
concat
(long long num)¶
-
bool
concat
(unsigned long num)¶
-
bool
concat
(unsigned long long num)¶
-
bool
concat
(float num)¶
-
bool
concat
(double num)¶
Concatenation operators
If there’s not enough memory for the concatenated value, the string will be left unchanged (but this isn’t signalled in any way)
Comparison methods
Works with String and ‘c’ string
Comparisons are case-sensitive, binary comparison null strings (including cstr == nullptr) are treated as empty.
- Return Value
int
: Returns < 0 if String is lexically before the argument, > 0 if after or 0 if the same
-
int
compareTo
(const char *cstr, size_t length) const¶
Test for equality
Compares content byte-for-byte using binary comparison
null strings (including cstr == nullptr) are treated as empty.
- Return Value
bool
: Returns true if strings are identical
-
bool
equals
(const char *cstr) const¶
-
bool
equals
(const char *cstr, size_t length) const¶
-
bool
equals
(const FlashString &fstr) const¶
Equality operator ==
- Return Value
bool
: true if Strings are identical
-
bool
operator==
(const char *cstr) const¶
-
bool
operator==
(const FlashString &fstr) const¶
In-equality operator !=
- Return Value
bool
: Returns true if strings are not identical
-
bool
operator!=
(const char *cstr) const¶
Comparison operators
Test for equality, without case-sensitivity
null strings are treated as empty.
- Return Value
bool
: true if strings are considered the same
-
bool
equalsIgnoreCase
(const char *cstr) const¶
-
bool
equalsIgnoreCase
(const char *cstr, size_t length) const¶
-
bool
equalsIgnoreCase
(const FlashString &fstr) const¶
Array operators
If index is invalid, returns NUL \0
-
char
operator[]
(size_t index) const¶
-
char &
operator[]
(size_t index)¶
int indexOf(…)
Locate a character or String within another String.
By default, searches from the beginning of the
String, but can also start from a given index, allowing for the locating of all instances of the character or String.- Return Value
int
: Index if found, -1 if not found
-
int
indexOf
(char ch, size_t fromIndex = 0) const¶
-
int
indexOf
(const char *s2_buf, size_t fromIndex, size_t s2_len) const¶
-
int
indexOf
(const char *s2_buf, size_t fromIndex = 0) const¶
int lastIndexOf(…)
Locate a character or String within another String
By default, searches from the end of the
String, but can also work backwards from a given index, allowing for the locating of all instances of the character or String.- Return Value
int
: Index if found, -1 if not found
-
int
lastIndexOf
(char ch) const¶
-
int
lastIndexOf
(char ch, size_t fromIndex) const¶
-
int
lastIndexOf
(const char *s2_buf, size_t fromIndex, size_t s2_len) const¶
String substring(…)
Get a substring of a String.
The starting index is inclusive (the corresponding character is included in the substring), but the optional ending index is exclusive (the corresponding character is not included in the substring).
- Parameters
from
: Index of first character to retrieveto
: (optional) One-past the ending character to retrieve
If the ending index is omitted, the substring continues to the end of the String.
If you don’t need the original String, consider using remove() instead:
String original("This is the original string."); String sub = original.substring(0, 13);
This produces the same result:
original.remove(13);
replace(…)
Replace all instances of a given character or substring with another character or substring.
Replacing a single character always succeeds as this is handled in-place.
- Return Value
bool
: true on success, false on allocation failure
Where
replace
is longer thanfind
the String may need to be re-allocated, which could fail. If this happens the method returns false and the String is left unchanged.-
void
replace
(char find, char replace)¶
-
bool
replace
(const char *find_buf, size_t find_len, const char *replace_buf, size_t replace_len)¶
remove()
Remove characters from a String.
If no count is provided then all characters from the given index to the end of the
String are removed.- Note
- The String is modified in-situ without any reallocation
- Parameters
index
: Index of the first character to removecount
: Number of characters to remove
-
void
remove
(size_t index)¶
-
void
remove
(size_t index, size_t count)¶
Public Functions
-
CStringArray &
operator=
(const char *cstr)¶
-
bool
add
(const char *str, int length = -1)¶ Append a new string (or array of strings) to the end of the array.
- Note
- If str contains any NUL characters it will be handled as an array
- Parameters
str
:length
: Length of new string in array (default is length of str)
- Return Value
bool
: false on memory allocation error
-
bool
add
(const String &str)¶ Append a new string (or array of strings) to the end of the array.
- Note
- If str contains any NUL characters it will be handled as an array
- Parameters
str
:
- Return Value
bool
: false on memory allocation error
-
int
indexOf
(const char *str, bool ignoreCase = true) const¶ Find the given string and return its index.
- Note
- Comparison is not case-sensitive
- Parameters
str
: String to findignoreCase
: Whether search is case-sensitive or not
- Return Value
int
: index of given string, -1 if not found
-
int
indexOf
(const String &str, bool ignoreCase = true) const¶ Find the given string and return its index.
- Note
- Comparison is not case-sensitive
- Parameters
str
: String to findignoreCase
: Whether search is case-sensitive or not
- Return Value
int
: index of given string, -1 if not found
-
bool
contains
(const char *str, bool ignoreCase = true) const¶ Check if array contains a string.
- Note
- Search is not case-sensitive
- Parameters
str
: String to search forignoreCase
: Whether search is case-sensitive or not
- Return Value
bool
: True if string exists in array
-
bool
contains
(const String &str, bool ignoreCase = true) const¶ Check if array contains a string.
- Note
- Search is not case-sensitive
- Parameters
str
: String to search forignoreCase
: Whether search is case-sensitive or not
- Return Value
bool
: True if string exists in array
-
const char *
getValue
(unsigned index) const¶ Get string at the given position.
- Parameters
index
: 0-based index of string to obtain
- Return Value
const
: char* nullptr if index is not valid
-
const char *
operator[]
(unsigned index) const¶ Get string at the given position.
- Parameters
index
: 0-based index of string to obtain
- Return Value
const
: char* nullptr if index is not valid
-
void
clear
()¶ Empty the array.
-
unsigned
count
() const¶ Get quantity of strings in array.
- Return Value
unsigned
: Quantity of strings
Private Functions
-
void
setString
(const char *cstr, int length = -1)¶
-
void
setString
(flash_string_t pstr, int length = -1)¶
-
bool
reserve
(size_t size)¶ Pre-allocate String memory.
On failure, the
String is left unchanged. reserve(0), if successful, will validate an invalid string (i.e., “if (s)” will be true afterwards)- Parameters
size
:
- Return Value
bool
: true on success, false on failure
-
bool
setLength
(size_t length)¶ set the string length accordingly, expanding if necessary
- Note
- extra characters are undefined
- Parameters
length
: required for string (nul terminator additional)
- Return Value
true
: on success, false on failure
-
operator StringIfHelperType
() const¶ Provides safe bool() operator.
Evaluates as false if String is null, otherwise evaluates as true
-
bool
startsWith
(const String &prefix) const¶ Compare the start of a String Comparison is case-sensitive, must match exactly.
- Parameters
prefix
:
- Return Value
bool
: true on match
-
bool
startsWith
(const String &prefix, size_t offset) const¶ Compare a string portion.
mis-named as does not necessarily compare from start
- Note
- Comparison is case-sensitive, must match exactly
- Parameters
prefix
:offset
: Index to start comparison at
- Return Value
bool
: true on match
-
bool
endsWith
(const String &suffix) const¶ Compare the end of a String.
- Parameters
suffix
:
- Return Value
bool
: true on match
-
char
charAt
(size_t index) const¶ Obtain the character at the given index.
- Note
- If index is invalid, returns NUL \0
- Parameters
index
:
- Return Value
char
:
-
void
setCharAt
(size_t index, char c)¶ Sets the character at a given index.
- Note
- If index is invalid, does nothing
- Parameters
index
:c
:
-
size_t
getBytes
(unsigned char *buf, size_t bufsize, size_t index = 0) const¶ Read contents of a String into a buffer.
- Note
- Returned data always nul terminated so buffer size needs to take this into account
- Parameters
buf
: buffer to write databufsize
: size of buffer in bytesindex
: offset to start
- Return Value
unsigned
: number of bytes copied, excluding nul terminator
-
void
toCharArray
(char *buf, size_t bufsize, size_t index = 0) const¶ Read contents of String into a buffer.
- See
- See
getBytes()
-
const char *
c_str
() const¶ Get a constant (un-modifiable) pointer to String content.
- Return Value
const
: char* Always valid, even for a null string
-
char *
end
()¶ Get a modifiable pointer to one-past the end of the String.
- Note
- Points to the terminating NUL character. If String is NUL, returns nullptr.
-
long
toInt
(void) const¶
-
float
toFloat
(void) const¶
Private Static Attributes
-
constexpr size_t
SSO_CAPACITY
= STRING_OBJECT_SIZE - 2¶ Max chars. (excluding NUL terminator) we can store in SSO mode.
-
class
Iterator
¶ -
Public Functions
-
Iterator
()¶
-
Iterator
(const CStringArray *array, uint16_t offset, uint16_t index)¶
-
operator bool
() const¶
-
bool
equals
(const char *rhs) const¶
-
bool
equalsIgnoreCase
(const char *rhs) const¶
-
bool
operator==
(const char *rhs) const¶
-
bool
operator!=
(const char *rhs) const¶
-
const char *
str
() const¶
-
const char *
operator*
() const¶
-
uint16_t
index
() const¶
-
uint16_t
offset
() const¶
-
void
next
()¶
-
-
Networking Protocols¶
DNS: Domain Name System¶
https://en.m.wikipedia.org/wiki/Domain_Name_System
-
enum
dnsserver
::
DnsReplyCode
¶ Values:
-
NoError
= 0¶
-
FormError
= 1¶
-
ServerFailure
= 2¶
-
NonExistentDomain
= 3¶
-
NotImplemented
= 4¶
-
Refused
= 5¶
-
YXDomain
= 6¶
-
YXRRSet
= 7¶
-
NXRRSet
= 8¶
-
-
DNS_QR_QUERY
¶
-
DNS_QR_RESPONSE
¶
-
DNS_OPCODE_QUERY
¶
-
struct
DnsHeader
¶ - #include <DnsServer.h>
-
class
DnsServer
: public UdpConnection¶ - #include <DnsServer.h>
Public Functions
-
DnsServer
()¶
-
void
setErrorReplyCode
(DnsReplyCode replyCode)¶
-
void
setTTL
(uint32_t ttl)¶
-
void
stop
()¶
-
virtual bool
listen
(int port)¶
-
virtual bool
connect
(IpAddress ip, uint16_t port)¶
-
virtual void
close
()¶
-
virtual bool
send
(const char *data, int length)¶
-
bool
sendString
(const char *data)¶
-
virtual bool
sendTo
(IpAddress remoteIP, uint16_t remotePort, const char *data, int length)¶
-
bool
sendStringTo
(IpAddress remoteIP, uint16_t remotePort, const char *data)¶
-
FTP: File Transfer Protocol¶
https://en.m.wikipedia.org/wiki/File_Transfer_Protocol
-
class
FtpServer
: public TcpServer¶ - #include <FtpServer.h>
Public Functions
-
FtpServer
()¶
-
virtual bool
listen
(int port, bool useSsl = false)¶
-
void
setKeepAlive
(uint16_t seconds)¶
-
void
shutdown
()¶
-
const Vector<TcpConnection *> &
getConnections
() const¶
-
virtual bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)¶
-
virtual void
close
()¶
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)¶
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY)¶ Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)¶
-
uint16_t
getAvailableWriteSize
()¶
-
void
flush
()¶
-
void
setTimeOut
(uint16_t waitTimeOut)¶
-
IpAddress
getRemoteIp
() const¶
-
uint16_t
getRemotePort
() const¶
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate)¶ Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler)¶ Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)¶
Public Members
-
uint16_t
activeClients
= 0¶
-
HTTP: HyperText Transfer Protocol¶
https://en.m.wikipedia.org/wiki/Hypertext_Transfer_Protocol
-
HTTP_SERVER_EXPOSE_NAME
¶ Default: 1 (enabled)
Adds “HttpServer/Sming” to the SERVER field in response headers. If disabled, the SERVER field is omitted from all responses.
-
HTTP_SERVER_EXPOSE_VERSION
¶ Default: 0 (disabled)
Adds the current Sming build version to the SERVER field in response headers. For example, “Sming/4.0.0-rc2”.
Requires HTTP_SERVER_EXPOSE_NAME to be enabled.
-
HTTP_SERVER_EXPOSE_DATE
¶ Default: 0 (disabled)
Sets the DATE field in response headers.
-
namespace
ContentType
¶ Functions
-
String
fromFileExtension
(const char *extension)¶ Obtain content type string from file extension.
- Parameters
extension
: excluding ‘.’ separator (e.g. “htm”, “json”)
- Return Value
-
static String
fromFileExtension
(const String &extension)¶ Obtain content type string from file extension.
- Parameters
extension
:
- Return Value
-
String
toString
(enum MimeType m)¶ Get textual representation for a MIME type.
- Parameters
m
: the MIME type
- Return Value
-
MimeType
fromString
(const char *str)¶ Get enumerated value for a MIME type string.
- Parameters
str
:
- Return Value
MimeType
: If empty, null or unrecognised returns MIME_UNKNOWN
-
MimeType
fromString
(const String &str)¶ Get enumerated value for a MIME type string.
- Parameters
str
:
- Return Value
MimeType
: If empty, null or unrecognised returns MIME_UNKNOWN
-
String
-
class
HttpClient
¶ - #include <HttpClient.h>
Public Functions
-
virtual
~HttpClient
()¶ HttpClient destructor.
- Note
- DON’T call cleanup. If you want to free all resources from HttpClients the correct sequence will be to
- Delete all instances of HttpClient
- Call the static method HttpClient::cleanup();
-
bool
sendRequest
(const HttpMethod method, const Url &url, const HttpHeaders &headers, RequestCompletedDelegate requestComplete)¶
-
bool
sendRequest
(const HttpMethod method, const Url &url, const HttpHeaders &headers, const String &body, RequestCompletedDelegate requestComplete)¶
-
bool
downloadFile
(const Url &url, const String &saveFileName, RequestCompletedDelegate requestComplete = nullptr)¶ Queue request to download a file.
- Parameters
url
: Source of file datasaveFileName
: Path to save file to. Optional: specify nullptr to use name from urlrequestComplete
: Completion callback
-
bool
send
(HttpRequest *request)¶
Public Static Functions
-
static void
cleanup
()¶ Use this method to clean all request queues and object pools
-
virtual
-
struct
HttpServerSettings
¶ - #include <HttpServer.h>
Public Members
-
uint16_t
maxActiveConnections
= 10¶ maximum number of concurrent requests..
-
uint16_t
keepAliveSeconds
= 0¶ default seconds to keep the connection alive before closing it
-
int
minHeapSize
= -1¶ min heap size that is required to accept connection, -1 means use server default
-
bool
useDefaultBodyParsers
= 1¶ if the default body parsers, as form-url-encoded, should be used
-
bool
closeOnContentError
=
true
¶ close the connection if a body parser or resource fails to parse the body content.
-
uint16_t
-
class
HttpServer
: public TcpServer¶ - #include <HttpServer.h>
Public Functions
-
HttpServer
()¶
-
HttpServer
(const HttpServerSettings &settings)¶
-
void
configure
(const HttpServerSettings &settings)¶ Allows changing the server configuration.
-
void
setBodyParser
(const String &contentType, HttpBodyParserDelegate parser)¶ Allows content-type specific parsing of the body based on content-type.
- Parameters
contentType
: Can be full content-type like ‘application/json’, or ‘application/*’ or ‘*’. If there is exact match for the content-type wildcard content-types will not be used. There can be only one catch-all ‘*’ body parser and that will be the last registeredparser
:
-
void
setBodyParser
(MimeType mimeType, HttpBodyParserDelegate parser)¶ Allows content-type specific parsing of the body based on content-type.
- Parameters
mimeType
:parser
:
-
void
setDefaultHandler
(const HttpPathDelegate &callback)¶
-
void
setDefaultResource
(HttpResource *resource)¶
-
virtual bool
listen
(int port, bool useSsl = false)
-
void
setKeepAlive
(uint16_t seconds)
-
void
shutdown
()
-
const Vector<TcpConnection *> &
getConnections
() const
-
virtual bool
connect
(const String &server, int port, bool useSsl = false)
-
virtual bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
virtual void
close
()
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
Public Members
-
HttpResourceTree
paths
¶ Maps paths to resources which deal with incoming requests.
-
uint16_t
activeClients
= 0
-
MQTT: MQ Telemetry Transport¶
https://en.m.wikipedia.org/wiki/MQTT
-
typedef Delegate<int(MqttClient &client, mqtt_message_t *message)>
MqttDelegate
¶
-
typedef ObjectQueue<mqtt_message_t, MQTT_REQUEST_POOL_SIZE>
MqttRequestQueue
¶
-
typedef Delegate<void(uint16_t msgId, int type)>
MqttMessageDeliveredCallback
¶
-
MQTT_REQUEST_POOL_SIZE
¶
-
MQTT_CLIENT_CONNECTED
¶
-
MQTT_FLAG_RETAINED
¶
-
MQTT_MAX_BUFFER_SIZE
¶
-
MQTT_MSG_PUBREC
¶
-
class
MqttClient
: protected TcpClient¶ - #include <MqttClient.h>
Public Functions
-
MqttClient
(bool withDefaultPayloadParser = true, bool autoDestruct = false)¶
-
~MqttClient
()¶
-
void
setKeepAlive
(uint16_t seconds)¶ Sets keep-alive time. That information is sent during connection to the server.
- Parameters
seconds
:
-
void
setPingRepeatTime
(unsigned seconds)¶ Sets the interval in which to ping the remote server if there was no activity
- Parameters
seconds
:
-
bool
setWill
(const String &topic, const String &message, uint8_t flags = 0)¶ Sets last will and testament
- Parameters
topic
:message
:flags
: QoS, retain, etc flags
- Return Value
bool
:
-
bool
connect
(const Url &url, const String &uniqueClientName)¶ Connect to a MQTT server.
- Parameters
url
: URL in the form “mqtt://user:password@server:port” or “mqtts://user:password@server:port”uniqueClientName
:
- Return Value
bool
:
-
void
setEventHandler
(mqtt_type_t type, MqttDelegate handler)¶
-
void
setPayloadParser
(MqttPayloadParser payloadParser = nullptr)¶ Sets or clears a payload parser (for PUBLISH messages from the server to us)
- Note
- We no longer have size limitation for incoming or outgoing messages but in order to prevent running out of memory we have a “sane” payload parser that will read up to 1K of payload
-
void
setConnectedHandler
(MqttDelegate handler)¶ Sets a handler to be called after successful MQTT connection.
- Parameters
handler
:
-
void
setPublishedHandler
(MqttDelegate handler)¶ Sets a handler to be called after receiving confirmation from the server for a published message from the client.
- Parameters
handler
:
-
void
setMessageHandler
(MqttDelegate handler)¶ Sets a handler to be called after receiving a PUBLISH message from the server.
- Parameters
handler
:
-
void
setDisconnectHandler
(TcpClientCompleteDelegate handler)¶ Sets a handler to be called on disconnect from the server.
- Parameters
handler
:
-
bool
publishWithQoS
(const String &topic, const String &message, int QoS, bool retained = false, MqttMessageDeliveredCallback onDelivery = nullptr)¶ bool publish(String& topic, String& message, bool retained = false) Use publish(const String& topic, const String& message, uint8_t flags = 0) instead.
-
void
setCallback
(MqttStringSubscriptionCallback subscriptionCallback = nullptr)¶ Provide a function to be called when a message is received from the broker.
Protected Functions
-
bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)¶
-
void
close
()¶
-
void
setReceiveDelegate
(TcpClientDataDelegate receiveCb = nullptr)¶ Set or clear the callback for received data.
- Parameters
receiveCb
: callback delegate or nullptr
-
void
setCompleteDelegate
(TcpClientCompleteDelegate completeCb = nullptr)¶ Set or clear the callback for connection close.
- Parameters
completeCb
: callback delegate or nullptr
-
bool
send
(const char *data, uint16_t len, bool forceCloseAfterSent = false)¶
-
bool
isProcessing
()¶
-
TcpClientState
getConnectionState
()¶
-
void
setCloseAfterSent
(bool ignoreIncomingData = false)¶ Schedules the connection to get closed after the data is sent
- Parameters
ignoreIncomingData
: when that flag is set the connection will start ignoring incoming data.
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
-
NTP: Network Time Protocol¶
https://en.m.wikipedia.org/wiki/Network_Time_Protocol
-
NTP_PORT
¶
-
NTP_PACKET_SIZE
¶
-
NTP_VERSION
¶
-
NTP_MODE_CLIENT
¶
-
NTP_MODE_SERVER
¶
-
NTP_DEFAULT_SERVER
¶
-
NTP_DEFAULT_AUTOQUERY_SECONDS
¶
-
NTP_MIN_AUTOQUERY_SECONDS
¶ Minimum autoquery interval.
-
NTP_CONNECTION_TIMEOUT_MS
¶ Time to retry query when network connection unavailable.
-
NTP_RESPONSE_TIMEOUT_MS
¶ Time to wait before retrying NTP query.
-
class
NtpClient
: protected UdpConnection¶ - #include <NtpClient.h>
NTP client class.
Public Functions
-
NtpClient
()¶ Instantiates NTP client object.
-
NtpClient
(NtpTimeResultDelegate onTimeReceivedCb)¶ Instantiates NTP client object.
- Parameters
onTimeReceivedCb
: Callback delegate to be called when NTP time result is received
-
NtpClient
(const String &reqServer, unsigned reqIntervalSeconds, NtpTimeResultDelegate onTimeReceivedCb = nullptr)¶ Instantiates NTP client object.
- Parameters
reqServer
: IP address or hostname of NTP server; nullptr to use default serverreqIntervalSeconds
: Quantity of seconds between NTP requestsonTimeReceivedCb
: Callback delegate to be called when NTP time result is received (Default: None)
-
void
requestTime
()¶ Request time from NTP server.
- Note
- Instigates request. Result is handled by NTP result handler function if defined
-
void
setNtpServer
(const String &server)¶ Set the NTP server.
- Parameters
server
: IP address or hostname of NTP server
-
void
setAutoQuery
(bool autoQuery)¶ Enable / disable periodic query.
- Parameters
autoQuery
: True to enable periodic query of NTP server
-
void
setAutoQueryInterval
(unsigned seconds)¶ Set query period.
- Parameters
seconds
: Period in seconds between periodic queries
-
void
setAutoUpdateSystemClock
(bool autoUpdateClock)¶ Enable / disable update of system clock.
- Parameters
autoUpdateClock
: True to update system clock with NTP result.
Protected Functions
-
virtual bool
listen
(int port)
-
virtual bool
connect
(IpAddress ip, uint16_t port)
-
virtual void
close
()
-
virtual bool
send
(const char *data, int length)
-
bool
sendString
(const char *data)
-
bool
sendString
(const String &data)
-
virtual bool
sendTo
(IpAddress remoteIP, uint16_t remotePort, const char *data, int length)
-
bool
sendStringTo
(IpAddress remoteIP, uint16_t remotePort, const char *data)
-
bool
sendStringTo
(IpAddress remoteIP, uint16_t remotePort, const String &data)
-
SMTP: Simple Mail Transfer Protocol¶
https://en.m.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
-
enum
smtpclient
::
SmtpState
¶ Values:
-
eSMTP_Banner
= 0¶
-
eSMTP_Hello
¶
-
eSMTP_StartTLS
¶
-
eSMTP_SendAuth
¶
-
eSMTP_SendingAuthLogin
¶
-
eSMTP_RequestingAuthChallenge
¶
-
eSMTP_SendAuthResponse
¶
-
eSMTP_SendingAuth
¶
-
eSMTP_Ready
¶
-
eSMTP_SendMail
¶
-
eSMTP_SendingMail
¶
-
eSMTP_SendRcpt
¶
-
eSMTP_SendingRcpt
¶
-
eSMTP_SendData
¶
-
eSMTP_SendingData
¶
-
eSMTP_SendHeader
¶
-
eSMTP_SendingHeaders
¶
-
eSMTP_StartBody
¶
-
eSMTP_SendingBody
¶
-
eSMTP_Sent
¶
-
eSMTP_Quitting
¶
-
eSMTP_Disconnect
¶
-
-
typedef Delegate<int(SmtpClient &client, int code, char *status)>
SmtpClientCallback
¶
-
SMTP_QUEUE_SIZE
¶
-
SMTP_ERROR_LENGTH
¶
-
SMTP_CODE_SERVICE_READY
¶ SMTP response codes
-
SMTP_CODE_BYE
¶
-
SMTP_CODE_AUTH_OK
¶
-
SMTP_CODE_REQUEST_OK
¶
-
SMTP_CODE_AUTH_CHALLENGE
¶
-
SMTP_CODE_START_DATA
¶
-
SMTP_OPT_PIPELINE
¶
-
SMTP_OPT_STARTTLS
¶
-
SMTP_OPT_AUTH_PLAIN
¶
-
SMTP_OPT_AUTH_LOGIN
¶
-
SMTP_OPT_AUTH_CRAM_MD5
¶
-
class
MailMessage
¶ - #include <MailMessage.h>
Public Functions
-
MailMessage &
setHeader
(const String &name, const String &value)¶ Set a header value.
- Parameters
name
:value
:
- Return Value
MailMessage&
:
-
HttpHeaders &
getHeaders
()¶ Get a reference to the current set of headers.
- Return Value
HttpHeaders&
:
-
MailMessage &
setBody
(const String &body, MimeType mime = MIME_TEXT)¶ Sets the body of the email.
- Parameters
body
:mime
:
- Return Value
MailMessage&
:
-
MailMessage &
setBody
(IDataSourceStream *stream, MimeType mime = MIME_TEXT)¶ Sets the body of the email.
- Parameters
stream
:mime
:
- Return Value
MailMessage&
:
-
MailMessage &
addAttachment
(FileStream *stream)¶ Adds attachment to the email.
- Parameters
stream
:
- Return Value
MailMessage&
:
-
MailMessage &
addAttachment
(IDataSourceStream *stream, MimeType mime, const String &filename = "")¶ Adds attachment to the email.
- Parameters
stream
:mime
:filename
:
- Return Value
MailMessage&
:
-
MailMessage &
addAttachment
(IDataSourceStream *stream, const String &mime, const String &filename = "")¶ Adds attachment to the email.
- Parameters
stream
:mime
:filename
:
- Return Value
MailMessage&
:
-
MailMessage &
-
class
SmtpClient
: protected TcpClient¶ - #include <SmtpClient.h>
Public Functions
-
SmtpClient
(bool autoDestroy = false)¶
-
~SmtpClient
()¶
-
bool
connect
(const Url &url)¶ Connects to remote URL.
- Parameters
url
: Provides the protocol, remote server, port and user credentials allowed protocols:- smtp - clear text SMTP
- smtps - SMTP over SSL connection
-
bool
send
(const String &from, const String &to, const String &subject, const String &body)¶ Queues a single message before it is sent later to the SMTP server.
- Parameters
from
:to
:subject
:body
: The body in plain text format
- Return Value
bool
: true when the message was queued successfully, false otherwise
-
bool
send
(MailMessage *message)¶ Powerful method to queues a single message before it is sent later to the SMTP server.
- Parameters
message
:
- Return Value
bool
: true when the message was queued successfully, false otherwise
-
MailMessage *
getCurrentMessage
()¶ Gets the current message.
- Return Value
MailMessage*
: The message, or NULL if none is scheduled
-
size_t
countPending
()¶
-
void
quit
()¶ Sends a quit command to the server and closes the TCP conneciton.
-
SmtpState
getState
()¶ Returns the current state of the SmtpClient.
-
void
onMessageSent
(SmtpClientCallback callback)¶ Callback that will be called every time a message is sent successfully.
- Parameters
callback
:
-
void
onServerError
(SmtpClientCallback callback)¶ Callback that will be called every an error occurs.
- Parameters
callback
:
Protected Functions
-
bool
connect
(const String &server, int port, bool useSsl = false)
-
bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
void
close
()
-
void
setReceiveDelegate
(TcpClientDataDelegate receiveCb = nullptr) Set or clear the callback for received data.
- Parameters
receiveCb
: callback delegate or nullptr
-
void
setCompleteDelegate
(TcpClientCompleteDelegate completeCb = nullptr) Set or clear the callback for connection close.
- Parameters
completeCb
: callback delegate or nullptr
-
bool
send
(const char *data, uint16_t len, bool forceCloseAfterSent = false)
-
bool
sendString
(const String &data, bool forceCloseAfterSent = false)
-
bool
isProcessing
()
-
TcpClientState
getConnectionState
()
-
void
setCloseAfterSent
(bool ignoreIncomingData = false) Schedules the connection to get closed after the data is sent
- Parameters
ignoreIncomingData
: when that flag is set the connection will start ignoring incoming data.
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
-
TCP: Transmission Control Protocol¶
https://en.m.wikipedia.org/wiki/Transmission_Control_Protocol
-
enum
tcp
::
TcpConnectionEvent
¶ Values:
-
eTCE_Connected
= 0¶ Occurs after connection establishment.
-
eTCE_Received
¶ Occurs on data receive.
-
eTCE_Sent
¶
-
eTCE_Poll
¶
-
-
typedef Delegate<void(TcpConnection&)>
TcpConnectionDestroyedDelegate
¶
-
NETWORK_DEBUG
¶
-
NETWORK_SEND_BUFFER_SIZE
¶
-
class
TcpConnection
¶ - #include <TcpConnection.h>
Subclassed by FtpDataStream, FtpServerConnection, TcpClient, TcpServer
Public Functions
-
TcpConnection
(bool autoDestruct)¶
-
TcpConnection
(tcp_pcb *connection, bool autoDestruct)¶
-
virtual
~TcpConnection
()¶
-
virtual bool
connect
(const String &server, int port, bool useSsl = false)
-
virtual bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
virtual void
close
()
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
-
-
enum
tcpclient
::
TcpClientState
¶ Values:
-
eTCS_Ready
¶
-
eTCS_Connecting
¶
-
eTCS_Connected
¶
-
eTCS_Successful
¶
-
eTCS_Failed
¶
-
-
enum
tcpclient
::
TcpClientCloseAfterSentState
¶ Values:
-
eTCCASS_None
¶
-
eTCCASS_AfterSent
¶
-
eTCCASS_AfterSent_Ignore_Received
¶
-
-
TCP_CLIENT_TIMEOUT
¶
-
class
TcpClient
: public TcpConnection¶ - #include <TcpClient.h>
Subclassed by HttpConnection, MqttClient, SmtpClient
Public Functions
-
TcpClient
(bool autoDestruct)¶
-
TcpClient
(tcp_pcb *clientTcp, TcpClientDataDelegate clientReceive, TcpClientCompleteDelegate onCompleted)¶
-
TcpClient
(TcpClientCompleteDelegate onCompleted, TcpClientEventDelegate onReadyToSend, TcpClientDataDelegate onReceive = nullptr)¶
-
TcpClient
(TcpClientCompleteDelegate onCompleted, TcpClientDataDelegate onReceive = nullptr)¶
-
TcpClient
(TcpClientDataDelegate onReceive)¶
-
~TcpClient
()¶
-
bool
connect
(const String &server, int port, bool useSsl = false)
-
bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
void
close
()
-
void
setReceiveDelegate
(TcpClientDataDelegate receiveCb = nullptr) Set or clear the callback for received data.
- Parameters
receiveCb
: callback delegate or nullptr
-
void
setCompleteDelegate
(TcpClientCompleteDelegate completeCb = nullptr) Set or clear the callback for connection close.
- Parameters
completeCb
: callback delegate or nullptr
-
bool
send
(const char *data, uint16_t len, bool forceCloseAfterSent = false)
-
bool
sendString
(const String &data, bool forceCloseAfterSent = false)
-
bool
isProcessing
()
-
TcpClientState
getConnectionState
()
-
void
setCloseAfterSent
(bool ignoreIncomingData = false) Schedules the connection to get closed after the data is sent
- Parameters
ignoreIncomingData
: when that flag is set the connection will start ignoring incoming data.
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
-
-
TCP_SERVER_TIMEOUT
¶
-
class
TcpServer
: public TcpConnection¶ - #include <TcpServer.h>
Subclassed by FtpServer, HttpServer, TelnetServer
Public Functions
-
TcpServer
()¶
-
TcpServer
(TcpClientConnectDelegate onClientHandler, TcpClientDataDelegate clientReceiveDataHandler, TcpClientCompleteDelegate clientCompleteHandler)¶
-
TcpServer
(TcpClientDataDelegate clientReceiveDataHandler, TcpClientCompleteDelegate clientCompleteHandler)¶
-
TcpServer
(TcpClientDataDelegate clientReceiveDataHandler)¶
-
~TcpServer
()¶
-
virtual bool
listen
(int port, bool useSsl = false)
-
void
setKeepAlive
(uint16_t seconds)
-
void
shutdown
()
-
const Vector<TcpConnection *> &
getConnections
() const
-
virtual bool
connect
(const String &server, int port, bool useSsl = false)
-
virtual bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
virtual void
close
()
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
Public Members
-
uint16_t
activeClients
= 0
-
Telnet¶
https://en.m.wikipedia.org/wiki/Telnet
-
TELNETSERVER_MAX_COMMANDSIZE
¶
-
class
TelnetServer
: public TcpServer¶ - #include <TelnetServer.h>
Public Functions
-
TelnetServer
()¶
-
void
enableDebug
(bool reqStatus)¶
-
void
enableCommand
(bool reqStatus)¶
-
virtual bool
listen
(int port, bool useSsl = false)
-
void
setKeepAlive
(uint16_t seconds)
-
void
shutdown
()
-
const Vector<TcpConnection *> &
getConnections
() const
-
virtual bool
connect
(const String &server, int port, bool useSsl = false)
-
virtual bool
connect
(IpAddress addr, uint16_t port, bool useSsl = false)
-
virtual void
close
()
-
int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)
-
virtual int
write
(const char *data, int len, uint8_t apiflags = TCP_WRITE_FLAG_COPY) Base write operation.
- Parameters
data
:len
:apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE
- Return Value
int
: -1 on error
-
int
write
(IDataSourceStream *stream)
-
uint16_t
getAvailableWriteSize
()
-
void
flush
()
-
void
setTimeOut
(uint16_t waitTimeOut)
-
IpAddress
getRemoteIp
() const
-
uint16_t
getRemotePort
() const
-
void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate) Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler) Set the SSL session initialisation callback.
- Parameters
handler
:
-
bool
setSslConnection
(Ssl::Connection *connection)
-
Ssl::Session *
getSsl
() Get a pointer to the current SSL session object.
Note that this is typically used so we can query properties of an established session. If you need to change session parameters this must be done via
setSslInitHandler
.
Public Members
-
uint16_t
activeClients
= 0
-
UDP: User Datagram Protocol¶
https://en.m.wikipedia.org/wiki/User_Datagram_Protocol
-
typedef Delegate<void(UdpConnection &connection, char *data, int size, IpAddress remoteIP, uint16_t remotePort)>
UdpConnectionDataDelegate
¶
-
class
UdpConnection
¶ - #include <UdpConnection.h>
Subclassed by DnsServer, NtpClient
Public Functions
-
UdpConnection
()¶
-
UdpConnection
(UdpConnectionDataDelegate dataHandler)¶
-
virtual
~UdpConnection
()¶
-
virtual bool
listen
(int port)
-
virtual bool
connect
(IpAddress ip, uint16_t port)
-
virtual void
close
()
-
virtual bool
send
(const char *data, int length)
-
bool
sendString
(const char *data)
-
bool
sendString
(const String &data)
-
virtual bool
sendTo
(IpAddress remoteIP, uint16_t remotePort, const char *data, int length)
-
bool
sendStringTo
(IpAddress remoteIP, uint16_t remotePort, const char *data)
-
bool
sendStringTo
(IpAddress remoteIP, uint16_t remotePort, const String &data)
-
URL: Uniform Resource Locator¶
https://en.m.wikipedia.org/wiki/URL
-
XX
(name, str, port)¶ Common URI scheme strings.
-
class
Url
¶ - #include <Url.h>
Class to manage URL instance.
- Note
- The various URL components are stored in un-escaped format for ease of editing. Unless otherwise indicated, methods act on un-escaped text. Methods used to obtain escaped versions are clearly marked. Any attached fragment (marked bv ‘#’) in the URL is discarded
Public Functions
-
Url
()¶
-
Url
(const String &urlString)¶ Construct a URL object from a regular escaped string.
- Parameters
urlString
: Escaped URL
-
Url
(const char *urlString)¶ Construct a URL object from a regular null-terminated escaped string.
- Parameters
urlString
: Escaped URL
-
Url
(const String &scheme, const String &user, const String &password, const String &host, int port = 0, const String &path = nullptr, const String &query = nullptr, const String &fragment = nullptr)¶
-
Url &
operator=
(String urlString)¶ Copy assignment operator.
- Note
- urlString is modified by so no point in passing const reference
- Parameters
urlString
: Escaped URL
-
Url &
operator=
(const char *urlString)¶ Copy assignment operator, for C-style strings.
- Parameters
urlString
: Escaped URL
-
operator String
() const¶
-
int
getPort
() const¶ Obtain the actual port number to be used.
- Note
- If not specified, the default scheme port is returned
- Return Value
int
:
-
String
getHostWithPort
() const¶ Get hostname+port part of URL string.
- Note
- Neither of these is subject to escaping
- Return Value
-
String
getPathWithQuery
() const¶ Get path with any query parameters attached.
- Note
- Both path and query values are escaped
- Return Value
-
void
debugPrintTo
(Print &p) const¶ Printable output for debugging.
- Parameters
p
:
WebSocket Protocol¶
https://en.m.wikipedia.org/wiki/WebSocket
-
typedef Vector<WebsocketConnection *>
WebsocketList
¶
-
typedef Delegate<void(WebsocketConnection&)>
WebsocketDelegate
¶
-
typedef Delegate<void(WebsocketConnection&, const String&)>
WebsocketMessageDelegate
¶
-
typedef Delegate<void(WebsocketConnection&, uint8_t *data, size_t size)>
WebsocketBinaryDelegate
¶
-
WEBSOCKET_VERSION
¶
-
struct
WsFrameInfo
¶ - #include <WebsocketConnection.h>
-
class
WebsocketConnection
¶ - #include <WebsocketConnection.h>
Subclassed by WebsocketClient
Public Functions
-
WebsocketConnection
(HttpConnection *connection, bool isClientConnection = true)¶ Constructs a websocket connection on top of http client or server connection.
- Parameters
connection
: the transport connectionisClientConnection
: true when the passed connection is an http client conneciton
-
virtual
~WebsocketConnection
()¶
-
bool
bind
(HttpRequest &request, HttpResponse &response)¶ Binds websocket connection to an http server connection.
- Parameters
request
:response
:
- Return Value
bool
: true on success, false otherwise
-
virtual void
send
(const char *message, size_t length, ws_frame_type_t type = WS_FRAME_TEXT)¶ Sends a websocket message from a buffer.
- Parameters
message
:length
: Quantity of data in messagetype
:
-
void
send
(const String &message, ws_frame_type_t type = WS_FRAME_TEXT)¶ Sends websocket message from a String.
-
void
sendBinary
(const uint8_t *data, size_t length)¶ Sends a binary websocket message.
- Parameters
data
:length
:
-
void
close
()¶ Closes a websocket connection (without closing the underlying http connection.
-
void
reset
()¶ Resets a websocket connection.
-
void
setUserData
(void *userData)¶ Attaches a user data to a websocket connection.
- Parameters
userData
:
-
void *
getUserData
()¶ Retrieves user data attached.
- Return Value
void*
: The user data previously set bysetUserData()
-
bool
operator==
(const WebsocketConnection &rhs) const¶ Test if another connection refers to the same object.
- Parameters
rhs
: The other WebsocketConnection to compare with
- Return Value
bool
:
-
void
setConnectionHandler
(WebsocketDelegate handler)¶ Sets the callback handler to be called after successful websocket connection.
- Parameters
handler
:
-
void
setMessageHandler
(WebsocketMessageDelegate handler)¶ Sets the callback handler to be called after a websocket message is received.
- Parameters
handler
:
-
void
setBinaryHandler
(WebsocketBinaryDelegate handler)¶ Sets the callback handler to be called after a binary websocket message is received.
- Parameters
handler
:
-
void
setDisconnectionHandler
(WebsocketDelegate handler)¶ Sets the callback handler to be called before closing a websocket connection.
- Parameters
handler
:
-
void
activate
()¶ Should be called after a websocket connection is established to activate the websocket parser and allow sending of websocket data.
-
bool
onConnected
()¶ Call this method when the websocket connection was (re)activated.
- Return Value
bool
: true on success
-
HttpConnection *
getConnection
()¶ Gets the underlying HTTP connection.
- Return Value
HttpConnection*
:
-
void
setConnection
(HttpConnection *connection, bool isClientConnection = true)¶ Sets the underlying (transport ) HTTP connection.
- Parameters
connection
: the transport connectionisClientConnection
: true when the passed connection is an http client conneciton
-
WsConnectionState
getState
()¶ Gets the state of the websocket connection.
- Return Value
WsConnectionState
:
Public Static Functions
-
static void
broadcast
(const char *message, size_t length, ws_frame_type_t type = WS_FRAME_TEXT)¶ Broadcasts a message to all active websocket connections.
- Parameters
message
:length
:type
:
-
static void
broadcast
(const String &message, ws_frame_type_t type = WS_FRAME_TEXT)¶ Broadcasts a message to all active websocket connections.
- Parameters
message
:type
:
-
static const WebsocketList &
getActiveWebsockets
()¶ Obtain the list of active websockets.
- Note
- Return value is const as only restricted operations should be carried out on the list.
- Return Value
const
: WebsocketList&
-
-
class
WebsocketClient
: protected WebsocketConnection¶ - #include <WebsocketClient.h>
Websocket Client.
Public Functions
-
WebsocketClient
()¶
-
WebsocketClient
(HttpConnection *connection)¶
-
HttpConnection *
getHttpConnection
()¶
-
bool
connect
(const Url &url)¶ Connects websocket client to server.
- Parameters
url
: Url address of websocket server
-
void
sendPing
(const String &payload = nullptr)¶ Send websocket ping to server.
- Parameters
payload
: Maximum 255 bytes
- Return Value
bool
: true if the data can be send, false otherwise
-
void
sendPong
(const String &payload = nullptr)¶ Send websocket ping to server.
- Parameters
payload
: Maximum 255 bytes
- Return Value
bool
: true if the data can be send, false otherwise
-
void
setSslInitHandler
(Ssl::Session::InitDelegate handler)¶ Set the SSL session initialisation callback.
- Parameters
handler
:
-
void
disconnect
()¶ Disconnects websocket client from server.
Protected Functions
-
bool
bind
(HttpRequest &request, HttpResponse &response) Binds websocket connection to an http server connection.
- Parameters
request
:response
:
- Return Value
bool
: true on success, false otherwise
-
virtual void
send
(const char *message, size_t length, ws_frame_type_t type = WS_FRAME_TEXT) Sends a websocket message from a buffer.
- Parameters
message
:length
: Quantity of data in messagetype
:
-
void
send
(const String &message, ws_frame_type_t type = WS_FRAME_TEXT) Sends websocket message from a String.
-
void
sendString
(const String &message) Sends a string websocket message.
- Parameters
message
:
-
void
sendBinary
(const uint8_t *data, size_t length) Sends a binary websocket message.
- Parameters
data
:length
:
-
void
close
() Closes a websocket connection (without closing the underlying http connection.
-
void
reset
() Resets a websocket connection.
-
void
setUserData
(void *userData) Attaches a user data to a websocket connection.
- Parameters
userData
:
-
void *
getUserData
() Retrieves user data attached.
- Return Value
void*
: The user data previously set bysetUserData()
-
bool
operator==
(const WebsocketConnection &rhs) const Test if another connection refers to the same object.
- Parameters
rhs
: The other WebsocketConnection to compare with
- Return Value
bool
:
-
void
setConnectionHandler
(WebsocketDelegate handler) Sets the callback handler to be called after successful websocket connection.
- Parameters
handler
:
-
void
setMessageHandler
(WebsocketMessageDelegate handler) Sets the callback handler to be called after a websocket message is received.
- Parameters
handler
:
-
void
setBinaryHandler
(WebsocketBinaryDelegate handler) Sets the callback handler to be called after a binary websocket message is received.
- Parameters
handler
:
-
void
setDisconnectionHandler
(WebsocketDelegate handler) Sets the callback handler to be called before closing a websocket connection.
- Parameters
handler
:
-
void
activate
() Should be called after a websocket connection is established to activate the websocket parser and allow sending of websocket data.
-
bool
onConnected
() Call this method when the websocket connection was (re)activated.
- Return Value
bool
: true on success
-
HttpConnection *
getConnection
() Gets the underlying HTTP connection.
- Return Value
HttpConnection*
:
-
void
setConnection
(HttpConnection *connection, bool isClientConnection = true) Sets the underlying (transport ) HTTP connection.
- Parameters
connection
: the transport connectionisClientConnection
: true when the passed connection is an http client conneciton
-
WsConnectionState
getState
() Gets the state of the websocket connection.
- Return Value
WsConnectionState
:
Protected Static Functions
-
static void
broadcast
(const char *message, size_t length, ws_frame_type_t type = WS_FRAME_TEXT) Broadcasts a message to all active websocket connections.
- Parameters
message
:length
:type
:
-
static void
broadcast
(const String &message, ws_frame_type_t type = WS_FRAME_TEXT) Broadcasts a message to all active websocket connections.
- Parameters
message
:type
:
-
static const WebsocketList &
getActiveWebsockets
() Obtain the list of active websockets.
- Note
- Return value is const as only restricted operations should be carried out on the list.
- Return Value
const
: WebsocketList&
-
Platform Support¶
WiFi¶
Build variables¶
-
ENABLE_WPS
¶ Set to 1 to enable WiFi Protected Setup (WPS).
WPS is not enabled by default to preserve resources, and because there may be security implications which you should consider carefully.
-
ENABLE_SMART_CONFIG
¶ Set to 1 to enable WiFi Smart Configuration API.
SmartConfig requires extra libraries and
ENABLE_ESPCONN
.See Basic Smart Config sample application.
If you want to provide a default SSID and Password for connection to your default Access Point, you can do this:
make WIFI_SSID=MyAccessPoint WIFI_PWD=secret
These are provided as #defined symbols for your application to use. See Basic WiFi for a simple example, or MeteoControl for a more flexible solution using configuration files.
-
WIFI_SSID
¶ SSID identifying default Access Point to connect to. By default, this is undefined.
API Documentation¶
-
group
wifi_sta
Control and monitoring of WiFi station interface.
- Note
- The WiFi station interface provides client access to a WiFi network. Control of WiFi connection including WiFi SSID and password and IP address, DHCP, etc.
- See
- WiFi Access Point
- See
- WiFi Events Interface
Typedefs
-
typedef Delegate<void(bool success, BssList &list)>
ScanCompletedDelegate
¶ Scan complete handler function.
-
typedef Delegate<bool(SmartConfigEvent event, const SmartConfigEventInfo &info)>
SmartConfigDelegate
¶ Smart configuration handler function.
- Parameters
event
:info
:
- Return Value
bool
: return true to perform default configuration
-
typedef Delegate<bool(WpsStatus status)>
WPSConfigDelegate
¶ WPS configuration callback function.
- Parameters
status
:
- Return Value
bool
: return true to perform default configuration
Enums
-
enum
StationConnectionStatus
¶ WiFi station connection states.
Values:
-
eSCS_Idle
¶ Connection idle.
-
eSCS_Connecting
¶ Connecting.
-
eSCS_WrongPassword
¶ Wrong password.
-
eSCS_AccessPointNotFound
¶ AP not found.
-
eSCS_ConnectionFailed
¶ Connection failed.
-
eSCS_GotIP
¶ Got IP address.
-
-
enum
SmartConfigType
¶ Smart configuration type.
Values:
-
SCT_None
= -1¶
-
SCT_EspTouch
¶ ESP Touch.
-
SCT_AirKiss
¶ Air Kiss.
-
SCT_EspTouch_AirKiss
¶ ESP Touch and Air Kiss.
-
Variables
-
StationClass &
WifiStation
¶ Global instance of WiFi station object.
- Note
- Use WifiStation.function to access WiFi station functions
- Note
- Example:
if(WifiStation.config("My_WiFi", "My_Password")) WifiStation.enable(true);
-
struct
SmartConfigEventInfo
¶ - #include <Station.h>
Smart Config callback information.
-
class
StationClass
¶ - #include <Station.h>
WiFi station class.
Public Functions
-
virtual
~StationClass
()¶
-
virtual void
enable
(bool enabled, bool save = false) = 0¶ Enable / disable WiFi station.
- Note
- Disabling WiFi station will also disable and clear the handler set with waitConnection.
- Parameters
enabled
: True to enable station. False to disable.save
: True to save operational mode to flash, False to set current operational mode only
-
virtual bool
isEnabled
() const = 0¶ Get WiFi station enable status.
- Return Value
bool
: True if WiFi station enabled
-
virtual bool
config
(const String &ssid, const String &password, bool autoConnectOnStartup = true, bool save = true) = 0¶ Configure WiFi station.
- Parameters
ssid
: WiFi SSIDpassword
: WiFi passwordautoConnectOnStartup
: True to auto connect. False for manual. (Default: True)save
: True to save the SSID and password in Flash. False otherwise. (Default: True)
-
virtual bool
connect
() = 0¶ Connect WiFi station to network.
-
virtual bool
disconnect
() = 0¶ Disconnect WiFi station from network.
-
bool
isConnected
() const¶ Get WiFi station connectoin status.
- Return Value
bool
: True if connected.
-
bool
isConnectionFailed
() const¶ Get WiFi station connection failure status.
- Return Value
bool
: True if connection failed
-
virtual StationConnectionStatus
getConnectionStatus
() const = 0¶ Get WiFi station connection status.
- Return Value
StationConnectionStatus
: Connection status structure
-
virtual bool
isEnabledDHCP
() const = 0¶ Get WiFi station DHCP enabled status.
- Return Value
bool
: True if DHCP enabled
-
virtual void
enableDHCP
(bool enable) = 0¶ Enable or disable WiFi station DHCP.
- Parameters
enable
: True to enable WiFi station DHCP
-
virtual void
setHostname
(const String &hostname) = 0¶ Set WiFi station DHCP hostname.
- Parameters
hostname
: - WiFi station DHCP hostname
-
virtual String
getHostname
() const = 0¶ Set WiFi station DHCP hostname.
- Return Value
WiFi
: station DHCP hostname
-
virtual IpAddress
getIP
() const = 0¶ Get WiFi station IP address.
- Return Value
IpAddress
: IP address of WiFi station
-
virtual MacAddress
getMacAddress
() const = 0¶ Get WiFi station MAC address.
- Return Value
MacAddress
:
-
String
getMAC
(char sep = '0') const¶ Get WiFi station MAC address.
- Parameters
sep
: Optional separator between bytes (e.g. ‘:’)
- Return Value
String
: WiFi station MAC address
-
virtual IpAddress
getNetworkMask
() const = 0¶ Get WiFi station network mask.
- Return Value
IpAddress
: WiFi station network mask
-
virtual IpAddress
getNetworkGateway
() const = 0¶ Get WiFi station default gateway.
- Return Value
IpAddress
: WiFi station default gateway
-
virtual IpAddress
getNetworkBroadcast
() const = 0¶ GetWiFi station broadcast address.
- Return Value
IpAddress
: WiFi station broadcast address
-
bool
setIP
(IpAddress address)¶ Set WiFi station IP address.
- Parameters
address
: IP address
- Return Value
bool
: True on success
-
virtual bool
setIP
(IpAddress address, IpAddress netmask, IpAddress gateway) = 0¶ Set WiFi station IP parameters.
- Parameters
address
: IP addressnetmask
: Network maskgateway
: Default gatway
- Return Value
bool
: True on success
-
virtual String
getPassword
() const = 0¶ Get WiFi station password.
- Return Value
String
: WiFi station password
-
virtual int8_t
getRssi
() const = 0¶ Get WiFi signal strength.
- Return Value
int8_t
: Value in dBm
-
virtual uint8_t
getChannel
() const = 0¶ Get active WiFi channel.
- Return Value
uint8_t
: channel number
-
virtual bool
startScan
(ScanCompletedDelegate scanCompleted) = 0¶ Start WiFi station network scan.
- Parameters
scanCompleted
: Function to call when scan completes
- Return Value
bool
: True on success
-
virtual
-
group
wifi_ap
Control and monitoring of WiFi access point interface.
- Note
- The WiFi access point interface provides a WiFi network access point. Control of WiFi AP including WiFi SSID and password and IP address.
- See
- WiFi Station Interface
- See
- WiFi Events Interface
Variables
-
AccessPointClass &
WifiAccessPoint
¶ Global instance of WiFi access point object.
- Note
- Use WifiAccessPoint.function to access WiFi access point functions
- Note
- Example:
if(WifiAccessPoint.config("ESP_AP", AUTH_OPEN)) WifiAccessPoint.enable(true);
-
class
AccessPointClass
¶ - #include <AccessPoint.h>
Access point class.
Public Functions
-
virtual
~AccessPointClass
()¶
-
virtual void
enable
(bool enabled, bool save = false) = 0¶ Enable or disable WiFi AP.
- Parameters
enabled
: True to enable AP. False to disable.save
: True to save operational mode to flash, False to set current operational mode only
-
virtual bool
isEnabled
() const = 0¶ Get WiFi AP enable status.
- Return Value
bool
: True if WiFi AP enabled.
-
virtual bool
config
(const String &ssid, String password, WifiAuthMode mode, bool hidden = false, int channel = 7, int beaconInterval = 200) = 0¶ Configure WiFi AP.
- Parameters
ssid
: WiFi AP SSIDpassword
: WiFi AP passwordmode
: WiFi AP modehidden
: True to hide WiFi AP (Default: Visible)channel
: WiFi AP channel (Default: 7)beaconInterval
: WiFi AP beacon interval in milliseconds (Default: 200ms)
- Return Value
bool
: True on success
-
virtual IpAddress
getIP
() const = 0¶ Get WiFi AP IP address.
- Return Value
IpAddress
: WiFi AP IP address
-
virtual bool
setIP
(IpAddress address) = 0¶ Set WiFi AP IP addres.
- Parameters
address
: New IP address for WiFi AP
- Return Value
bool
: True on success
-
virtual MacAddress
getMacAddress
() const = 0¶ Get WiFi AP MAC address.
- Return Value
MacAddress
:
-
String
getMAC
(char sep = '0') const¶ Get WiFi AP MAC address.
- Parameters
sep
: separator between bytes (e.g. ‘:’)
- Return Value
String
: WiFi AP MAC address
-
virtual IpAddress
getNetworkMask
() const = 0¶ Get WiFi AP network mask.
- Return Value
IpAddress
: WiFi AP network mask
-
virtual IpAddress
getNetworkGateway
() const = 0¶ Get WiFi AP default gateway.
- Return Value
IpAddress
: WiFi AP default gateway
-
virtual IpAddress
getNetworkBroadcast
() const = 0¶ Get WiFi AP broadcast address.
- Return Value
IpAddress
: WiFi AP broadcast address
-
virtual
-
group
wifi_ev
Event callback interface for WiFi events.
Defines
-
WIFI_DISCONNECT_REASON_CODES_MAP
(XX)¶ Common set of reason codes to IEEE 802.11-2007.
Some acronymns used here - see the full standard for more precise definitions.
- SSID: Service Set Identifier (the visible name given to an Access Point)
- BSSID: Basic Service Set Identifier (a MAC address physically identifying the AP)
- IE: Information Element (standard piece of information carried within WiFi packets)
- STA: Station (any device which supports WiFi, including APs though the term commonly refers to a client)
- AP: Access Point (device to which other stations may be associated)
- RSN: Robust Security Network
- AUTH: Authentication (how a station proves its identity to another)
- Note
- Codes at 200+ are non-standard, defined by Espressif.
Typedefs
-
typedef Delegate<void(const String &ssid, MacAddress bssid, uint8_t channel)>
StationConnectDelegate
¶ Delegate type for ‘station connected’ event.
- Note
- This event occurs when the station successfully connects to the target AP. Upon receiving this event, the DHCP client begins the process of getting an IP address.
- Parameters
ssid
:bssid
:channel
:
-
typedef Delegate<void(const String &ssid, MacAddress bssid, WifiDisconnectReason reason)>
StationDisconnectDelegate
¶ Delegate type for ‘station disconnected’ event.
- Note
- This event can be generated in the following scenarios:
- When the station is already connected to the AP, and a manual disconnect or re-configuration is taking place. e.g.
WifiStation.disconnect()
- When
WifiStation.connect()
is called, but the Wi-Fi driver fails to set up a connection with the AP due to certain reasons, e.g. the scan fails to find the target AP, authentication times out, etc. If there are more than one AP with the same SSID, the disconnected event is raised after the station fails to connect all of the found APs. - When the Wi-Fi connection is disrupted because of specific reasons, e.g., the station continuously loses N beacons, the AP kicks off the station, the AP’s authentication mode is changed, etc.
- When the station is already connected to the AP, and a manual disconnect or re-configuration is taking place. e.g.
- Parameters
ssid
: SSID from which we’ve disconnectedbssid
:reason
: Why the connection was dropped
-
typedef Delegate<void(WifiAuthMode oldMode, WifiAuthMode newMode)>
StationAuthModeChangeDelegate
¶ Delegate type for ‘station authorisation mode changed’ event.
- Note
- This event arises when the AP to which the station is connected changes its authentication mode, e.g., from ‘no auth’ to WPA. Generally, the application event callback does not need to handle this.
- Parameters
oldMode
:newMode
:
-
typedef Delegate<void(IpAddress ip, IpAddress netmask, IpAddress gateway)>
StationGotIPDelegate
¶ Delegate type for ‘station got IP address’ event.
- Note
- This event arises when the DHCP client successfully gets the IPV4 address from the DHCP server, or when the IPV4 address is changed. The IPV4 may be changed because of the following reasons:
- The DHCP client fails to renew/rebind the IPV4 address, and the station’s IPV4 is reset to 0.
- The DHCP client rebinds to a different address.
- The static-configured IPV4 address is changed.
- Parameters
ip
:netmask
:gateway
:
-
typedef Delegate<void(MacAddress mac, uint16_t aid)>
AccessPointConnectDelegate
¶ Delegate type for ‘Access Point Connect’ event.
- Note
- This event occurs every time a station is connected to our Access Point.
- Parameters
mac
: MAC address of the stationaid
: Association ID representing the connected station
-
typedef Delegate<void(MacAddress mac, uint16_t aid)>
AccessPointDisconnectDelegate
¶ Delegate type for ‘Access Point Disconnect’ event.
- Note
- This event occurs every time a station is disconnected from our Access Point.
- Parameters
mac
: MAC address of the stationaid
: Association ID assigned to the station
-
typedef Delegate<void(int rssi, MacAddress mac)>
AccessPointProbeReqRecvedDelegate
¶ Delegate type for ‘Access Point Probe Request Received’ event.
- Note
- Probe Requests are a low-level management frame which are used to determine informaton about our Access Point, such as which authentication modes are supported.
- Parameters
rssi
: Signal strengthmac
:
Enums
-
enum
WifiDisconnectReason
¶ Reason codes for WiFi station disconnection.
Values:
Variables
-
WifiEventsClass &
WifiEvents
¶ Global reference to architecture-specific implementation.
-
class
WifiEventsClass
¶ - #include <WifiEvents.h>
WiFi events class.
Public Functions
-
void
onStationConnect
(StationConnectDelegate delegateFunction)¶ Set callback for ‘station connected’ event.
-
void
onStationDisconnect
(StationDisconnectDelegate delegateFunction)¶ Set callback for ‘station disconnected’ event.
-
void
onStationAuthModeChange
(StationAuthModeChangeDelegate delegateFunction)¶ Set callback for ‘station authorisation mode change’ event.
-
void
onStationGotIP
(StationGotIPDelegate delegateFunction)¶ Set callback for ‘station connected with IP address’ event.
-
void
onAccessPointConnect
(AccessPointConnectDelegate delegateFunction)¶ Set callback for ‘access point client connected’ event.
-
void
onAccessPointDisconnect
(AccessPointDisconnectDelegate delegateFunction)¶ Set callback for ‘access point client disconnected’ event.
-
void
onAccessPointProbeReqRecved
(AccessPointProbeReqRecvedDelegate delegateFunction)¶ Set callback for ‘access point probe request received’ event.
-
void
-
See WiFi Sniffer for an example of how to use this.
-
group
wifi_sniffer
WiFi promiscuous mode sniffer support.
Defines
-
ETH_MAC_LEN
¶
Typedefs
-
typedef Delegate<void(uint8_t *data, uint16_t length)>
WifiSnifferCallback
¶
-
typedef Delegate<void(const BeaconInfo &beacon)>
WifiBeaconCallback
¶
-
typedef Delegate<void(const ClientInfo &client)>
WifiClientCallback
¶
-
struct
BeaconInfo
¶ - #include <WifiSniffer.h>
Decoded Wifi beacon (Access Point) information.
-
struct
ClientInfo
¶ - #include <WifiSniffer.h>
Decoded Wifi client information.
-
class
BeaconInfoList
: public Vector<BeaconInfo>¶ - #include <WifiSniffer.h>
For applications to use to manage list of unique beacons.
Public Types
-
template<>
typedef int (*Comparer
)(const BeaconInfo &lhs, const BeaconInfo &rhs)¶
Public Functions
-
int
indexOf
(const uint8_t bssid[])¶
-
unsigned int
capacity
() const
-
bool
contains
(const BeaconInfo &elem) const¶
-
const BeaconInfo &
firstElement
() const
-
int
indexOf
(const BeaconInfo &elem) const¶
-
bool
isEmpty
() const
-
const BeaconInfo &
lastElement
() const
-
int
lastIndexOf
(const BeaconInfo &elem) const¶
-
unsigned int
count
() const
-
unsigned int
size
() const
-
void
copyInto
(BeaconInfo *array) const¶
-
bool
add
(const BeaconInfo &obj)¶
-
bool
addElement
(const BeaconInfo &obj)¶
-
bool
addElement
(BeaconInfo *objp)¶
-
void
clear
()
-
bool
ensureCapacity
(unsigned int minCapacity)
-
void
removeAllElements
()
-
bool
removeElement
(const BeaconInfo &obj)¶
-
bool
setSize
(unsigned int newSize)
-
void
trimToSize
()
-
const BeaconInfo &
elementAt
(unsigned int index) const
-
bool
insertElementAt
(const BeaconInfo &obj, unsigned int index)¶
-
const void
remove
(unsigned int index)
-
void
removeElementAt
(unsigned int index)
-
bool
setElementAt
(const BeaconInfo &obj, unsigned int index)¶
-
const BeaconInfo &
get
(unsigned int index) const
-
const BeaconInfo &
operator[]
(unsigned int index) const
-
BeaconInfo &
operator[]
(unsigned int index)
-
void
sort
(Comparer compareFunction)
-
const BeaconInfo &
at
(unsigned int i) const
-
template<>
-
class
ClientInfoList
: public Vector<ClientInfo>¶ - #include <WifiSniffer.h>
For applications to use to manage list of unique clients.
Public Types
-
template<>
typedef int (*Comparer
)(const ClientInfo &lhs, const ClientInfo &rhs)¶
Public Functions
-
int
indexOf
(const uint8_t station[])¶
-
unsigned int
capacity
() const
-
bool
contains
(const ClientInfo &elem) const¶
-
const ClientInfo &
firstElement
() const
-
int
indexOf
(const ClientInfo &elem) const¶
-
bool
isEmpty
() const
-
const ClientInfo &
lastElement
() const
-
int
lastIndexOf
(const ClientInfo &elem) const¶
-
unsigned int
count
() const
-
unsigned int
size
() const
-
void
copyInto
(ClientInfo *array) const¶
-
bool
add
(const ClientInfo &obj)¶
-
bool
addElement
(const ClientInfo &obj)¶
-
bool
addElement
(ClientInfo *objp)¶
-
void
clear
()
-
bool
ensureCapacity
(unsigned int minCapacity)
-
void
removeAllElements
()
-
bool
removeElement
(const ClientInfo &obj)¶
-
bool
setSize
(unsigned int newSize)
-
void
trimToSize
()
-
const ClientInfo &
elementAt
(unsigned int index) const
-
bool
insertElementAt
(const ClientInfo &obj, unsigned int index)¶
-
const void
remove
(unsigned int index)
-
void
removeElementAt
(unsigned int index)
-
bool
setElementAt
(const ClientInfo &obj, unsigned int index)¶
-
const ClientInfo &
get
(unsigned int index) const
-
const ClientInfo &
operator[]
(unsigned int index) const
-
ClientInfo &
operator[]
(unsigned int index)
-
void
sort
(Comparer compareFunction)
-
const ClientInfo &
at
(unsigned int i) const
-
template<>
-
class
WifiSniffer
: public ISystemReadyHandler¶ - #include <WifiSniffer.h>
Public Functions
-
void
begin
()¶ Initialise the sniffer.
-
void
end
()¶ Stop the sniffer.
-
void
onBeacon
(WifiBeaconCallback callback)¶ Register notification for beacon (AP) info.
-
void
onClient
(WifiClientCallback callback)¶ Register notification for client info.
-
void
onSniff
(WifiSnifferCallback callback)¶ Register notification for all incoming data.
- Note
- Callback invoked for all packet types, including beacon/client
-
void
setChannel
(unsigned channel)¶ Set the channel to listen on.
- Parameters
channel
:
-
unsigned
getChannel
()¶ Get the current channel being listened on.
-
void
-
System¶
Task Queue¶
Sming has a task queue which allows execution of a function to be deferred until
the system is less busy. This is done by calling SystemClass::queueCallback()
.
Callbacks are executed as soon as possible, and allow other higher priority tasks (such as servicing the WiFi stack) to be handled in a timely manner.
A common use for the queue is to initiate processing from an interrupt service routine.
You must not spend too much time in the callback. How much time depends on the nature of your application, but tasks consuming more than 100ms will probably affect responsiveness and should be broken into smaller chunks. You might do this by wrapping such tasks in a class together with some state information. At the end of the initial callback if there is further work to be done simply make another call to queueCallback().
The task queue size is fixed, so the call to queueCallback() will fail if there is no room.
-
TASK_QUEUE_LENGTH
¶ Maximum number of entries in the task queue (default 10).
-
ENABLE_TASK_COUNT
¶ If problems are suspected with task queuing, it may be getting flooded. For this reason you should check the return value from queueCallback().
You can enable this option to keep track of the number of active tasks,
SystemClass::getTaskCount()
, and the maximum,SystemClass::getMaxTaskCount()
.By default this is disabled and both methods will return 255. This is because interrupts must be disabled to ensure an accurate count, which may not be desirable.
API Documentation¶
-
group
system
Access to the ESP8266 system Provides system control and monitoring of the ESP8266.
Typedefs
-
typedef void (*
TaskCallback32
)(uint32_t param)¶ Task callback function type, uint32_t parameter.
- Note
- Callback code does not need to be in IRAM
-
typedef void (*
TaskCallback
)(void *param)¶ Task callback function type, void* parameter.
- Note
- Callback code does not need to be in IRAM
-
typedef Delegate<void()>
TaskDelegate
¶ Task Delegate callback type.
-
typedef TaskDelegate
SystemReadyDelegate
¶ Handler function for system ready.
Enums
-
enum
DeepSleepOptions
¶ Deep sleep options.
Values:
-
eDSO_RF_CAL_BY_INIT_DATA
= 0¶ RF_CAL or not after deep-sleep wake up, depends on init data byte 108.
-
eDSO_RF_CAL_ALWAYS
= 1¶ RF_CAL after deep-sleep wake up, there will be large current.
-
eDSO_RF_CAL_NEVER
= 2¶ no RF_CAL after deep-sleep wake up, there will only be small current.
-
eDSO_DISABLE_RF
=
4
¶ disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current.
-
Variables
-
SystemClass
System
¶ Global instance of system object.
- Note
- Use system.function to access system functions
- Note
- Example:
system.reset();
-
class
ISystemReadyHandler
¶ - #include <System.h>
Interface class implemented by classes to support on-ready callback.
Subclassed by WDTClass, WifiSniffer
-
class
SystemClass
¶ - #include <System.h>
System class.
Public Functions
-
SystemClass
()¶
-
bool
isReady
()¶ Check if system ready.
- Return Value
bool
: True if system initialisation is complete and system is now ready
-
void
restart
(unsigned deferMillis = 0)¶ Request a restart of the system.
- Note
- A delay is often required to allow network callback code to complete correctly. The restart is always deferred, either using the task queue (if deferMillis == 0) or using a timer. This method always returns immediately.
- Parameters
deferMillis
: defer restart request by a number of milliseconds
-
void
setCpuFrequency
(CpuFrequency freq)¶ Set the CPU frequency.
- Parameters
freq
: Frequency to set CPU
-
CpuFrequency
getCpuFrequency
()¶ Get the CPU frequency.
- Return Value
CpuFrequency
: The frequency of the CPU
-
bool
deepSleep
(uint32_t timeMilliseconds, DeepSleepOptions options = eDSO_RF_CAL_BY_INIT_DATA)¶ Enter deep sleep mode.
- Parameters
timeMilliseconds
: Quantity of milliseconds to remain in deep sleep modeoptions
: Deep sleep options
-
void
onReady
(SystemReadyDelegate readyHandler)¶ Set handler for system ready event.
- Note
- if system is ready, callback is executed immediately without deferral
- Parameters
readyHandler
: Function to handle event
-
void
onReady
(ISystemReadyHandler *readyHandler)¶ Set handler for system ready event.
- Note
- if system is ready, callback is executed immediately without deferral
- Parameters
readyHandler
: Function to handle event
Public Static Functions
-
static bool
initialize
()¶ System initialisation.
- Note
- Called by user_main: applications should not call this function or the task queue will be re-initialised and any currently queued tasks won’t be called.
- Return Value
bool
: true on success
-
static bool
queueCallback
(TaskCallback32 callback, uint32_t param = 0)¶ Queue a deferred callback.
- Note
- It is important to check the return value to avoid memory leaks and other issues, for example if memory is allocated and relies on the callback to free it again. Note also that this method is typically called from interrupt context so must avoid things like heap allocation, etc.
- Parameters
callback
: The function to be calledparam
: Parameter passed to the callback (optional)
- Return Value
bool
: false if callback could not be queued
-
static bool
queueCallback
(TaskCallback callback, void *param = nullptr)¶ Queue a deferred callback, with optional void* parameter.
-
static bool
queueCallback
(InterruptCallback callback)¶ Queue a deferred callback with no callback parameter.
-
static bool
queueCallback
(TaskDelegate callback)¶ Queue a deferred Delegate callback.
- Note
- Provides flexibility and ease of use for using capturing lambdas, etc. but requires heap allocation and not as fast as a function callback. DO NOT use from interrupt context, use a Task/Interrupt callback.
- Parameters
callback
: The Delegate to be called
- Return Value
bool
: false if callback could not be queued
-
static unsigned
getTaskCount
()¶ Get number of tasks currently on queue.
- Return Value
unsigned
:
-
static unsigned
getMaxTaskCount
()¶ Get maximum number of tasks seen on queue at any one time.
- Note
- If return value is higher than maximum task queue TASK_QUEUE_LENGTH then the queue has overflowed at some point and tasks have been left un-executed.
- Return Value
unsigned
:
-
-
typedef void (*
Services¶
Command Executor¶
Introduction¶
Command handler provides a common command line interface. CLI is available for the following remote access methods:
- Serial
- Telnet
- Websockets
By default, CLI is disabled. Enable CLI by calling “commandProcessing” on the appropriate access class object, e.g:
Serial.commandProcessing(true)
Commands can be added to and removed from the command handler. Each command will trigger a defined Delegate.
A welcome message may be shown when a user connects and end of line character may be defined. An automatic “help” display is available.
Build Variables¶
-
ENABLE_CMD_EXECUTOR
¶ Default: 1 (ON)
This feature enables execution of certain commands by registering token handlers for text received via serial, websocket or telnet connection. If this feature is not used additional RAM/Flash can be obtained by setting
ENABLE_CMD_EXECUTOR=0
. This will save ~1KB RAM and ~3KB of flash memory.
API Documentation¶
-
typedef Delegate<void(String commandLine, CommandOutput *commandOutput)>
CommandFunctionDelegate
¶ Command delegate function.
- Note
- CommandFunctionDelegate defines the structure of a function that handles individual commands
- Note
- Can use standard print functions on commandOutput
- Parameters
commandLine
: Command line entered by user at CLI, including command and parameterscommandOutput
: Pointer to the CLI print stream
-
typedef CommandFunctionDelegate
commandFunctionDelegate
¶
-
CommandHandler
commandHandler
¶ Global instance of CommandHandler.
-
class
CommandDelegate
¶ - #include <CommandDelegate.h>
Command delegate class.
Public Functions
-
CommandDelegate
(String reqName, String reqHelp, String reqGroup, CommandFunctionDelegate reqFunction)¶ Instantiate a command delegate
- Parameters
reqName
: Command name - the text a user types to invoke the commandreqHelp
: Help message shown by CLI “help” commandreqGroup
: The command group to which this command belongsreqFunction
: Delegate that should be invoked (triggered) when the command is entered by a user
-
~CommandDelegate
()¶
-
-
class
CommandHandler
¶ - #include <CommandHandler.h>
Command handler class.
Public Functions
-
CommandHandler
()¶ Instantiate a CommandHandler.
-
~CommandHandler
()¶
-
bool
registerCommand
(CommandDelegate reqDelegate)¶ Add a new command to the command handler.
- Note
- If command already exists, it will not be replaced and function will fail. Call unregisterCommand first if you want to replace a command.
- Parameters
reqDelegate
: Command delegate to register
- Return Value
bool
: True on success
-
bool
unregisterCommand
(CommandDelegate reqDelegate)¶ Remove a command from the command handler.
reqDelegate Delegate to remove from command handler
-
void
registerSystemCommands
()¶ Register default system commands.
- Note
- Adds the following system commmands to the command handler
- status
- echo
- help
- debugon
- debugoff
- command
-
CommandDelegate
getCommandDelegate
(const String &commandString)¶ Get the command delegate for a command.
- Parameters
commandString
: Command to query
- Return Value
CommandDelegate
: The command delegate matchin the command
-
VerboseMode
getVerboseMode
()¶ Get the verbose mode.
- Return Value
VerboseMode
: Verbose mode
-
void
setVerboseMode
(VerboseMode reqVerboseMode)¶ Set the verbose mode.
- Parameters
reqVerboseMode
: Verbose mode to set
-
String
getCommandPrompt
()¶ Get the command line prompt.
- Note
- This is what is shown on the command line before user input Default is Sming>
- Return Value
String
: The command line prompt
-
void
setCommandPrompt
(const String &reqPrompt)¶ Set the command line prompt.
- Note
- This is what is shown on the command line before user input Default is Sming>
- Parameters
reqPrompt
: The command line prompt
-
char
getCommandEOL
()¶ Get the end of line character.
- Note
- Only supports one EOL, unlike Windows
- Return Value
char
: The EOL character
-
void
setCommandEOL
(char reqEOL)¶ Set the end of line character.
- Note
- Only supports one EOL, unlike Windows
- Parameters
reqEOL
: The EOL character
-
Profiling¶
CPU Usage¶
Class to provide a CPU usage indication based on task callback availability.
To use, instantiate a single instance of Profiling::CpuUsage
and call Profiling::CpuUsage::begin()
from the application’s init()
function, passing a callback function to be invoked after calibration has completed.
This function will continue with your application’s normal execution.
See RingTone Player for an example.
CPU usage is calculated over an update period which begins with a call to Profiling::CpuUsage::reset()
.
The actual update period must be managed elsewhere, using a callback timer, web request
or other mechanism. It doesn’t need to be exact as the actual elapsed time in CPU
cycles is used for the calculation.
After the update period has elapsed, call Profiling::CpuUsage::getUtilisation()
to obtain a CPU usage figure.
This figure is obtained using the number of task callbacks made within the update period.
- loop cycles
- Set up repeating task callback and measure invocations between successive calls
- total cycles
- The total number of CPU cycles between calls to
Profiling::CpuUsage::update()
. - used
- total - loop
- utilisation
- used / total
-
class
CpuUsage
¶ Class to provide a CPU usage indication based on task callback availability.
Public Functions
-
void
begin
(InterruptCallback ready)¶ Calibrate the baseline figure for minimum CPU usage.
- Note
- Typically call this in
init()
- Parameters
ready
: Function to call when calibration is complete
-
void
reset
()¶ Reset counters to start a new update period.
-
unsigned
getLoopIterations
()¶ Get the number of task callbacks made so far.
-
uint32_t
getMinLoopCycles
()¶ Get the figure used as the baseline cycle count.
-
unsigned
getUtilisation
()¶ Get the CPU utilisation figure in 1/100ths of a percent.
-
void
Min-Max¶
-
template <typename T>
classMinMax
: public Printable¶ Class to track minimum and maximum values of a set of data, with average, total and count.
Subclassed by Profiling::MinMaxTimes< Timer >
Min-Max Times¶
-
template <class Timer>
classMinMaxTimes
: public Profiling::MinMax<uint32_t>, public Timer¶ Public Types
-
template<>
usingMillis
= NanoTime::TimeSource<Clock, NanoTime::Milliseconds, uint32_t>¶
-
template<>
usingMicros
= NanoTime::TimeSource<Clock, NanoTime::Microseconds, TimeType>¶
Public Functions
-
void
update
()¶
-
size_t
printTo
(Print &p) const¶
-
const String &
getTitle
() const
-
void
clear
()
-
void
update
(T value)
-
T
getMin
() const
-
T
getMax
() const
-
T
getTotal
() const
-
T
getAverage
() const
-
unsigned
getCount
() const
-
DelegateCallbackTimer &
initializeUs
(TimerDelegate delegateFunction)¶ Initialise timer in microseconds, with static check.
- Template Parameters
microseconds
: Timer interval in microseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeUs
(uint32_t microseconds, TimerDelegate delegateFunction)¶ Initialise microsecond timer.
- Note
- Delegate callback method
- Parameters
microseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeUs
(TimerCallback callback, void *arg = nullptr)¶ Initialise timer in microseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(InterruptCallback callback = nullptr)¶ Initialise timer in microseconds (static check) with optional Interrupt Callback (no argument)
-
CallbackTimer &
initializeUs
(TimeType microseconds, TimerCallback callback, void *arg = nullptr)¶ Initialise timer in microseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeUs
(TimeType microseconds, InterruptCallback callback = nullptr)¶ Initialise timer in microseconds with optional Interrupt Callback (no arg)
-
DelegateCallbackTimer &
initializeMs
(TimerDelegate delegateFunction)¶ Initialise hardware timer in milliseconds, with static check.
- Template Parameters
milliseconds
: Timer interval in milliseconds
- Parameters
delegateFunction
: Function to call when timer triggers
- Return Value
ExtendedCallbackTimer&
: Reference to timer
-
DelegateCallbackTimer &
initializeMs
(uint32_t milliseconds, TimerDelegate delegateFunction)¶ Initialise millisecond timer.
- Note
- Delegate callback method
- Parameters
milliseconds
: Duration of timer in millisecondsdelegateFunction
: Function to call when timer triggers
-
CallbackTimer &
initializeMs
(TimerCallback callback, void *arg = nullptr)¶ Initialise hardware timer in milliseconds (static check) with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(InterruptCallback callback = nullptr)¶ Initialise hardware timer in milliseconds (static check) and optional Interrupt Callback (no arg)
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, TimerCallback callback, void *arg = nullptr)¶ Initialise hardware timer in milliseconds with Timer Callback and optional argument.
-
CallbackTimer &
initializeMs
(uint32_t milliseconds, InterruptCallback callback = nullptr)¶ Initialise hardware timer in milliseconds with optional Interrupt Callback (no arg)
-
void
setCallback
(TimerDelegate delegateFunction)¶ Set timer trigger function using Delegate callback method.
- Note
- Don’t use this for interrupt timers
- Parameters
delegateFunction
: Function to be called on timer trigger
-
void
setCallback
(TimerCallback callback, void *arg = nullptr)¶ Set timer trigger callback.
- Parameters
callback
: Function to call when timer triggersarg
: Optional argument passed to callback
-
void
setCallback
(InterruptCallback callback)¶ Set timer trigger callback.
- Note
- Provided for convenience where callback argument not required
- Parameters
callback
: Function to call when timer triggers
-
CallbackTimer &
initialize
(TimerCallback callback, void *arg = nullptr)¶ Initialise timer with an interval (static check) and callback.
- Note
- If interval out of range compilation will fail with error
- Template Parameters
unit
: Time unit for intervaltime
: Timer interval
- Parameters
callback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
CallbackTimer &
initialize
(TimeType time, TimerCallback callback, void *arg = nullptr)¶ Initialise timer with an interval and callback.
- Template Parameters
unit
: Time unit for interval
- Parameters
time
: Timer intervalcallback
: Callback function to call when timer triggersarg
: Optional argument passed to callback
- Return Value
CallbackTimer&
: Reference to timer
-
bool
start
(bool repeating = true)¶ Start timer running.
- Parameters
repeating
: True to restart timer when it triggers, false for one-shot (Default: true)
- Return Value
bool
: True if timer started
-
bool
startOnce
()¶ Start one-shot timer.
- Note
- Timer starts and will run for configured period then stop
- Return Value
bool
: True if timer started
-
void
stop
()¶ Stops timer.
-
bool
restart
()¶ Restart timer.
- Note
- Timer is stopped then started with current configuration
- Return Value
bool
: True if timer started
-
bool
isStarted
() const¶ Check if timer is started.
- Return Value
bool
: True if started
-
TickType
getInterval
() const¶ Get timer interval in clock ticks.
-
bool
checkInterval
(TickType ticks) const¶ Check timer interval is valid.
- Parameters
ticks
: Interval to check
- Return Value
bool
: true if interval is within acceptable range for this timer
-
bool
setInterval
(TickType ticks)¶ Set timer interval in timer ticks.
- Parameters
ticks
: Interval in timer ticks
-
void
setInterval
()¶ Set timer interval in timer ticks (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Interval in ticks
-
void
setInterval
() Set timer interval in specific time unit (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
:time
: Interval to set
-
bool
setInterval
(TimeType time)¶ Set timer interval in timer ticks.
- Template Parameters
unit
:
- Parameters
time
: Interval in given units
-
bool
setIntervalUs
(TimeType microseconds)¶ Set timer interval in microseconds.
-
void
setIntervalUs
()¶ Set timer interval in microseconds (static check)
-
bool
setIntervalMs
(uint32_t milliseconds)¶ Set timer interval in milliseconds.
-
void
setIntervalMs
()¶ Set timer interval in milliseconds (static check)
Public Static Functions
-
static constexpr Millis
millis
()¶ Get a millisecond time source.
-
static constexpr Micros
micros
()¶ Get a microsecond time source.
-
static constexpr uint64_t
usToTicks
()¶ Convert microsecond count into timer ticks.
-
static TickType
usToTicks
(TimeType time)¶ Convert microsecond count into timer ticks.
-
static constexpr uint64_t
ticksToUs
()¶ Convert timer ticks into microseconds.
-
static TimeType
ticksToUs
(TickType ticks)¶ Convert timer ticks into microseconds.
-
static constexpr void
checkInterval
()¶ Check timer interval in ticks is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
ticks
: Timer interval to check
-
static constexpr void
checkInterval
() Check timer interval in specific time unit is valid (static check)
- Note
- On error, compilation fails with error message
- Template Parameters
unit
: Time unit for intervaltime
: Interval to check
-
static constexpr void
checkIntervalMs
()¶ Check timer interval in milliseconds is valid (static check)
-
static constexpr void
checkIntervalUs
()¶ Check timer interval in microseconds is valid (static check)
Protected Types
-
template<>
usingClock
= OsTimerApi::Clock¶
-
template<>
usingTickType
= uint64_t¶
-
template<>
usingTimeType
= uint64_t¶
-
template<>
Wiring¶
The Wiring Framework is common to all Arduino platforms.
Some adaptations and improvements have been made for Sming which are documented here.
Vector¶
-
template <typename Element>
classVector
: public Countable<Element>¶ Vector class template.
Public Types
-
template<>
typedef int (*Comparer
)(const Element &lhs, const Element &rhs)¶
Public Functions
-
Vector
(unsigned int initialCapacity = 10, unsigned int capacityIncrement = 10)¶
-
~Vector
()¶
-
unsigned int
capacity
() const
-
bool
contains
(const Element &elem) const¶
-
const Element &
firstElement
() const
-
int
indexOf
(const Element &elem) const¶
-
bool
isEmpty
() const
-
const Element &
lastElement
() const
-
int
lastIndexOf
(const Element &elem) const¶
-
unsigned int
count
() const
-
unsigned int
size
() const
-
void
copyInto
(Element *array) const¶
-
bool
add
(const Element &obj)¶
-
bool
addElement
(const Element &obj)¶
-
bool
addElement
(Element *objp)¶
-
void
clear
()
-
bool
ensureCapacity
(unsigned int minCapacity)
-
void
removeAllElements
()
-
bool
removeElement
(const Element &obj)¶
-
bool
setSize
(unsigned int newSize)
-
void
trimToSize
()
-
const Element &
elementAt
(unsigned int index) const
-
bool
insertElementAt
(const Element &obj, unsigned int index)¶
-
const void
remove
(unsigned int index)
-
void
removeElementAt
(unsigned int index)
-
bool
setElementAt
(const Element &obj, unsigned int index)¶
-
const Element &
get
(unsigned int index) const
-
const Element &
operator[]
(unsigned int index) const
-
Element &
operator[]
(unsigned int index)
-
void
sort
(Comparer compareFunction)
-
const Element &
at
(unsigned int i) const
-
template<>
HashMap¶
-
template <typename K, typename V>
classHashMap
¶ HashMap class template.
Public Types
-
template<>
typedef bool (*comparator
)(const K&, const K&)¶
Public Functions
-
HashMap
()¶
-
HashMap
(comparator compare)¶
-
~HashMap
()¶
-
unsigned int
count
() const¶
-
const K &
keyAt
(unsigned int idx) const¶
-
K &
keyAt
(unsigned int idx)¶
-
const V &
valueAt
(unsigned int idx) const¶
-
V &
valueAt
(unsigned int idx)¶
-
const V &
operator[]
(const K &key) const¶
-
V &
operator[]
(const K &key)¶
-
void
allocate
(unsigned int newSize)¶
-
int
indexOf
(const K &key) const¶
-
bool
contains
(const K &key) const¶
-
void
removeAt
(unsigned index)¶
-
void
remove
(const K &key)¶
-
void
clear
()¶
-
void
setNullValue
(const V &nullv)¶
-
template<>
Wiring String¶
Small String Optimisation¶
The String
class is probably the most used class in Arduino and Sming.
Unfortunately it gets the blame for one of the most indidious problems in the embedded world, heap fragmentation.
To alleviate this problem, Sming uses a technique known as Small String Optimisation, which uses the available space inside the String object itself to avoid using the heap for small allocations of 10 characters or fewer.
This was lifted from the Arduino Esp8266 core <https://github.com/esp8266/arduino/pull/5690>. Superb work - thank you!
Configuration Variables¶
-
STRING_OBJECT_SIZE
¶ minimum: 12 bytes (default) maximum: 128 bytes
Must be an integer multiple of 4 bytes.
This is an experimental feature which lets you increase the size of a String object to reduce heap allocations further. The effect of this will vary depending on your application, but you can see some example figures in Pull Request #1951.
Benefits of increasing
STRING_OBJECT_SIZE
:- Increase code speed
- Fewer heap allocations
Drawbacks:
- Increased static memory usage for global/static String objects or embedded within global/static class instances.
- A String can use SSO or the heap, but not both together, so in heap mode any additional SSO space will remain unused.
Allows the size of a String object to be changed to increase the string length available before the heap is used.
Note
The current implementation uses one byte for a NUL terminator, and another to store the length, so the maximum SSO string length is (STRING_OBJECT_SIZE - 2) characters.
However, the implementation may change so if you need to check the maximum SSO string size in your code, please use
String::SSO_CAPACITY
.
API Documentation¶
-
class
String
¶ The String class.
Note that a string object’s default constructor creates an empty string. This is not the same as a null string. A null string evaluates to false, but an empty string evaluates to true.
Small String Optimisation means that heap is only used for strings longer than 10 characters, not including the NUL terminator. This is simply making use of existing storage within the String object.
This length can be increased using STRING_OBJECT_SIZE, but note the additional space remains unused when switching to heap storage for longer Strings.
Subclassed by CStringArray, StringSumHelper
Copy constructors
If the initial value is null or invalid, or if memory allocation fails, the string will be marked as invalid (i.e. “if (s)” will be false).
-
String
(const char *cstr)¶
-
String
(const char *cstr, size_t length)¶
-
String
(flash_string_t pstr, int length = -1)¶
-
String
(StringSumHelper &&rval)¶
-
String
(char c)¶
-
String
(unsigned char, unsigned char base = 10)¶
-
String
(int, unsigned char base = 10)¶
-
String
(unsigned int, unsigned char base = 10)¶
-
String
(long, unsigned char base = 10)¶
-
String
(long long, unsigned char base = 10)¶
-
String
(unsigned long, unsigned char base = 10)¶
-
String
(unsigned long long, unsigned char base = 10)¶
-
String
(float, unsigned char decimalPlaces = 2)¶
-
String
(double, unsigned char decimalPlaces = 2)¶
Copy operators
If the value is null or invalid, or if the memory allocation fails, the String will be marked as invalid (“if (s)” will be false).
Move operators
Move content from one String to another without any heap allocation.
Move operators are automatically selected by the compiler when it is able, such as when returning temporary String objects from functions.
In other situations, use
std::move
:String original("A String"); String copy("This is the content for the copy"); copy = std::move(myString);
copy
will now contain “A String”, whilstoriginal
will be invalidated.Concatenation methods
Works with built-in types. On failure, the string is left unchanged. If the argument is null or invalid, the concatenation is considered unsucessful.
- Return Value
bool
: true on success, false on failure
-
bool
concat
(const String &str)
-
bool
concat
(const FlashString &fstr)
-
bool
concat
(const char *cstr)
-
bool
concat
(const char *cstr, size_t length)
-
bool
concat
(char c)
-
bool
concat
(unsigned char num)
-
bool
concat
(int num)
-
bool
concat
(unsigned int num)
-
bool
concat
(long num)
-
bool
concat
(long long num)
-
bool
concat
(unsigned long num)
-
bool
concat
(unsigned long long num)
-
bool
concat
(float num)
-
bool
concat
(double num)
Concatenation operators
If there’s not enough memory for the concatenated value, the string will be left unchanged (but this isn’t signalled in any way)
-
String &
operator+=
(const FlashString &rhs)
-
String &
operator+=
(char c)
-
String &
operator+=
(unsigned char num)
-
String &
operator+=
(int num)
-
String &
operator+=
(unsigned int num)
-
String &
operator+=
(long num)
-
String &
operator+=
(long long num)
-
String &
operator+=
(unsigned long num)
-
String &
operator+=
(unsigned long long num)
-
String &
operator+=
(float num)
-
String &
operator+=
(double num)
Comparison methods
Works with String and ‘c’ string
Comparisons are case-sensitive, binary comparison null strings (including cstr == nullptr) are treated as empty.
- Return Value
int
: Returns < 0 if String is lexically before the argument, > 0 if after or 0 if the same
-
int
compareTo
(const char *cstr, size_t length) const
-
int
compareTo
(const String &s) const
Test for equality
Compares content byte-for-byte using binary comparison
null strings (including cstr == nullptr) are treated as empty.
- Return Value
bool
: Returns true if strings are identical
-
bool
equals
(const String &s) const
-
bool
equals
(const char *cstr) const
-
bool
equals
(const char *cstr, size_t length) const
-
bool
equals
(const FlashString &fstr) const
Equality operator ==
- Return Value
bool
: true if Strings are identical
-
bool
operator==
(const String &rhs) const
-
bool
operator==
(const char *cstr) const
-
bool
operator==
(const FlashString &fstr) const
In-equality operator !=
- Return Value
bool
: Returns true if strings are not identical
-
bool
operator!=
(const String &rhs) const
-
bool
operator!=
(const char *cstr) const
Comparison operators
-
bool
operator<
(const String &rhs) const
-
bool
operator>
(const String &rhs) const
-
bool
operator<=
(const String &rhs) const
-
bool
operator>=
(const String &rhs) const
Test for equality, without case-sensitivity
null strings are treated as empty.
- Return Value
bool
: true if strings are considered the same
-
bool
equalsIgnoreCase
(const char *cstr) const
-
bool
equalsIgnoreCase
(const char *cstr, size_t length) const
-
bool
equalsIgnoreCase
(const String &s2) const
-
bool
equalsIgnoreCase
(const FlashString &fstr) const
Array operators
If index is invalid, returns NUL \0
-
char
operator[]
(size_t index) const
-
char &
operator[]
(size_t index)
int indexOf(…)
Locate a character or String within another String.
By default, searches from the beginning of the
String, but can also start from a given index, allowing for the locating of all instances of the character or String.- Return Value
int
: Index if found, -1 if not found
-
int
indexOf
(char ch, size_t fromIndex = 0) const
-
int
indexOf
(const char *s2_buf, size_t fromIndex, size_t s2_len) const
-
int
indexOf
(const char *s2_buf, size_t fromIndex = 0) const
-
int
indexOf
(const String &s2, size_t fromIndex = 0) const
int lastIndexOf(…)
Locate a character or String within another String
By default, searches from the end of the
String, but can also work backwards from a given index, allowing for the locating of all instances of the character or String.- Return Value
int
: Index if found, -1 if not found
-
int
lastIndexOf
(char ch) const
-
int
lastIndexOf
(char ch, size_t fromIndex) const
-
int
lastIndexOf
(const String &s2) const
-
int
lastIndexOf
(const String &s2, size_t fromIndex) const
-
int
lastIndexOf
(const char *s2_buf, size_t fromIndex, size_t s2_len) const
String substring(…)
Get a substring of a String.
The starting index is inclusive (the corresponding character is included in the substring), but the optional ending index is exclusive (the corresponding character is not included in the substring).
- Parameters
from
: Index of first character to retrieveto
: (optional) One-past the ending character to retrieve
If the ending index is omitted, the substring continues to the end of the String.
If you don’t need the original String, consider using remove() instead:
String original("This is the original string."); String sub = original.substring(0, 13);
This produces the same result:
original.remove(13);
-
String
substring
(size_t from, size_t to) const
-
String
substring
(size_t from) const
replace(…)
Replace all instances of a given character or substring with another character or substring.
Replacing a single character always succeeds as this is handled in-place.
- Return Value
bool
: true on success, false on allocation failure
Where
replace
is longer thanfind
the String may need to be re-allocated, which could fail. If this happens the method returns false and the String is left unchanged.-
void
replace
(char find, char replace)
-
bool
replace
(const char *find_buf, size_t find_len, const char *replace_buf, size_t replace_len)
remove()
Remove characters from a String.
If no count is provided then all characters from the given index to the end of the
String are removed.- Note
- The String is modified in-situ without any reallocation
- Parameters
index
: Index of the first character to removecount
: Number of characters to remove
-
void
remove
(size_t index)
-
void
remove
(size_t index, size_t count)
Public Functions
-
~String
(void)¶
-
void
setString
(const char *cstr, int length = -1)
-
void
setString
(flash_string_t pstr, int length = -1)
-
bool
reserve
(size_t size) Pre-allocate String memory.
On failure, the
String is left unchanged. reserve(0), if successful, will validate an invalid string (i.e., “if (s)” will be true afterwards)- Parameters
size
:
- Return Value
bool
: true on success, false on failure
-
bool
setLength
(size_t length) set the string length accordingly, expanding if necessary
- Note
- extra characters are undefined
- Parameters
length
: required for string (nul terminator additional)
- Return Value
true
: on success, false on failure
-
size_t
length
(void) const Obtain the String length in characters, excluding NUL terminator.
-
operator StringIfHelperType
() const Provides safe bool() operator.
Evaluates as false if String is null, otherwise evaluates as true
-
bool
startsWith
(const String &prefix) const Compare the start of a String Comparison is case-sensitive, must match exactly.
- Parameters
prefix
:
- Return Value
bool
: true on match
-
bool
startsWith
(const String &prefix, size_t offset) const Compare a string portion.
mis-named as does not necessarily compare from start
- Note
- Comparison is case-sensitive, must match exactly
- Parameters
prefix
:offset
: Index to start comparison at
- Return Value
bool
: true on match
-
bool
endsWith
(const String &suffix) const Compare the end of a String.
- Parameters
suffix
:
- Return Value
bool
: true on match
-
char
charAt
(size_t index) const Obtain the character at the given index.
- Note
- If index is invalid, returns NUL \0
- Parameters
index
:
- Return Value
char
:
-
void
setCharAt
(size_t index, char c) Sets the character at a given index.
- Note
- If index is invalid, does nothing
- Parameters
index
:c
:
-
size_t
getBytes
(unsigned char *buf, size_t bufsize, size_t index = 0) const Read contents of a String into a buffer.
- Note
- Returned data always nul terminated so buffer size needs to take this into account
- Parameters
buf
: buffer to write databufsize
: size of buffer in bytesindex
: offset to start
- Return Value
unsigned
: number of bytes copied, excluding nul terminator
-
void
toCharArray
(char *buf, size_t bufsize, size_t index = 0) const Read contents of String into a buffer.
- See
- See
getBytes()
-
const char *
c_str
() const Get a constant (un-modifiable) pointer to String content.
- Return Value
const
: char* Always valid, even for a null string
-
char *
end
() Get a modifiable pointer to one-past the end of the String.
- Note
- Points to the terminating NUL character. If String is NUL, returns nullptr.
-
const char *
begin
() const¶
-
const char *
end
() const¶
-
void
toLowerCase
(void) Convert the entire String content to lower case.
-
void
toUpperCase
(void) Convert the entire String content to upper case.
-
void
trim
(void) Remove all leading and trailing whitespace characters from the String.
-
long
toInt
(void) const
-
float
toFloat
(void) const
Public Members
-
PtrBuf
ptr
-
SsoBuf
sso
Public Static Attributes
-
const String
nullstr
A null string evaluates to false.
-
const String
empty
An empty string evaluates to true.
-
constexpr size_t
SSO_CAPACITY
= STRING_OBJECT_SIZE - 2 Max chars. (excluding NUL terminator) we can store in SSO mode.
Friends
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, const char *cstr)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, char c)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, unsigned char num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, int num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, unsigned int num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, long num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, unsigned long num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, unsigned long long num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, float num)¶
-
StringSumHelper &
operator+
(const StringSumHelper &lhs, double num)¶
-
Sample Projects¶
Sming comes with a set of samples to illustrate and test various aspects of the framework. Some are related to specific Libraries.
MMA7455 Accelerometer¶
Simple demonstration which reads and displays output from an I2C accelerometer.
References¶
- Source Code
- Sming (main) Component
- MMA-7455 Accelerometer Library
Arducam¶
A demonstration application for controlling ArduCAM camera modules via web or telnet interface.
References¶
- Source Code
- Sming (main) Component
- ArduCAM Library Library
Basic APA102¶
Demonstrates use of APA102 library for controlling smart LEDs via SPI.
References¶
- Source Code
- Sming (main) Component
- APA102 LED Library
Basic Audio¶
Demonstrates how to set up I2S driver to produce audio output.
References¶
- Source Code
- Sming (main) Component
- Signal Generator Library
Basic Blink¶
Simple blink example. We use Timer instead of a loop because we want to allow WiFi communications to work in the background.

References¶
- Source Code
- Sming (main) Component
Basic Capsense¶
Simple demonstration showing Displays raw output from a capacitive sensor.
References¶
- Source Code
- Sming (main) Component
- Capacitive Sensor Library Library
Basic DateTime¶
A basic demonstration of Sming’s date and time handling functions.
Connect a serial terminal and enter a unix timestamp as a numeric value, then press ENTER to display it in various formats.
You can delete characters, or press ESC to clear the entry.
References¶
- Source Code
- Sming (main) Component
Basic Delegates¶
Demonstrates the various ways you can use callbacks within Sming.
References¶
- Source Code
- Sming (main) Component
Basic Hardware PWM¶
Demonstrates how to generate PWM signals on multiple pins using Sming’s HardwarePWM class.
References¶
- Source Code
- Sming (main) Component
Basic Interrupts¶
Simple example of how interrupts can be used within Sming.
References¶
- Source Code
- Sming (main) Component
Basic NFC¶
Sample application to read an RFID tag using a suitable reader connected via SPI interface.
References¶
- Source Code
- Sming (main) Component
- MFRC522 RFID Module Library
Basic Neopixel¶
Demonstration of the Adafruit Neopixel library for controlling single-wire-based LED pixels and strip.
References¶
- Source Code
- Sming (main) Component
- Adafruit NeoPixel Library Library
Basic ProgMem¶
This sample application demonstrates the various ways to access data stored in Flash memory.
References¶
- Source Code
- Sming (main) Component
Basic I2C Scanner¶
Classic Arduino I2C scanner with adaptations for Sming framework.
References¶
- Source Code
- Sming (main) Component
Basic Serial¶
Demonstrates Sming’s asynchronous capabilities using the UART to send and receive simultaneously using two serial ports.
Use the primary serial port to enter commands:
- cat
- Send the contents of the Readme.md file to the second serial port.
- text
- Echo a block of text
Note that you can continue to type commands while serial data is being transmitted as all operations are fully asynchronous. This becomes more obvious if you try using a low baud rate, for example:
make COM_SPEED_SERIAL=9600 COM_SPEED_ESPTOOL=921600
We’d still like a decent speed for flashing though!
If you want to set the two ports to different speeds the code will need to be modified.
References¶
- Source Code
- Sming (main) Component
Basic Servo¶
Demonstrates use of the Servo library for controlling multiple servo actuators.
References¶
- Source Code
- Sming (main) Component
- Servo RC PWM Control Library
Basic Smart Config¶
Introduction¶
SmartConfig is a mechanism to more easily configure an ESP device using a smart phone.
Calling smartConfigStart() starts a search for an Access Point (AP) with a special signature. It then tries to extract data like SSID and password from it. The App on your smart phone sends out that information.
The example here shows how to use ESP_TOUCH method to do smart configuration on the device. It ported from the C code that Espressif provides in the SDK examples.
You will need an App for your Smart Phone, such as:
- Android https://github.com/EspressifApp/EsptouchForAndroid
- iOS https://github.com/EspressifApp/EsptouchForIOS
- ESP8266 SmartConfig (search on Android Play)
See also https://www.espressif.com/en/products/software/esp-touch/overview.
References¶
- Source Code
- Sming (main) Component
Basic SSL¶
Compilation¶
In Sming the SSL support is not enabled by default.
In order to enable it you should compile your project with the
ENABLE_SSL
=1 directive. This can be done using the following command:
make ENABLE_SSL=1
Now you can flash your application to your ESP8266 device.
Debug Information¶
If you want to see more debug information during compile type you should
add the directive SSL_DEBUG
=1, like this:
make ENABLE_SSL=1 SSL_DEBUG=1
Slow SSL negotiation¶
The initial SSL negotiation is CPU intensive. By default SmingFramework switches the CPU frequency from 80 to 160 MHz. After the negotiation the CPU is switched back to 80 MHz.
If your device is running on battery this can drain the battery much
faster. If you do not want the switch from 80 to 160 MHz to happen then
make sure to recompile SmingFramework with SSL_SLOW_CONNECT
directive:
make USER_CFLAGS="SSL_SLOW_CONNECT=1"
Memory usage¶
SSL uses a significant amount of RAM. You can build this sample to track heap usage and output statistics every 5 seconds:
make ENABLE_MALLOC_COUNT = 1
References¶
- Source Code
- Sming (main) Component
- malloc_count Component
Basic Web Skeleton¶
Introduction¶
Basic application that can be used as a start point for some useful App.
Features:
- can setup wifi ssid and wifi password for STA (wifi client) mode either from own AP or as connected to some wifi network
- demonstrate new way of catching wif-events with WifiEvents class
- if preconfigured wifi network is unreachable start AP named TyTherm with hardcoded password (see source)
- can enable/disable STA (wifi client) mode
- own AP autodisable after successful connection to preconfigured wifi network
- form population and sending is done with json+ajax
- demonstrate usage of getting raw http request body to be processed as json
- demonstrate how to fill html template on client side with more flexible than Smings Templating - JavaScript
App called TyTherm because it is base for TinY TermOmeter :)
FlashString¶
This sample also demonstrates how to use FlashString maps as an alternative to using SPIFFS for serving files.
To test this out, build the application without a filesystem image:
make DISABLE_SPIFFS=1
See webserver.cpp for the details.
References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 6 Library
Basic Web Skeleton (LTS)¶
Introduction¶
This is a copy of the Basic_WebSkeletonApp from the Sming LTS branch, modified to build for Sming 4.0. Sming uses ArduinoJson version 6 by default, so this sample demonstrates how to continue using version 5.
This is how it was done:
- When including SmingCore.h, just use #include <SmingCore.h>.
- Remove the file include/user_config.h. Sming provides this by default, but if you have made changes for your project then remove everything except your changes, but be sure to add #include_next <user_config.h> at the top.
- Remove any #include <user_config.h> statements from your files. This file is automatically included by Sming.
- Rename Makefile-user.mk file to component.mk.
- Replace the file Makefile with the one from the Basic_Blink sample project. If you’ve ignored the instructions and modified the file (!) then you’ll need to move those changes into your new component.mk file instead.
- Sming uses #pragma once style for header guards, so consider updating your own files if you’re not already doing this.
- We use the OneWire Arduino Library, so add ARDUINO_LIBRARIES := OneWire to our component.mk file. Sming now only builds libraries which are specifically requested for a project.
- We’re using ArduinoJson, version 6. Sming supports version 5 or 6, but you must specify which one:
- Add ARDUINO_LIBRARIES=ArduinoJson6 to the project’s component.mk file.
- Add #include <JsonObjectStream.h>. If you’re not using the stream class, add #include <ArduinoJson6.h> to code.
- Update callback function parameter lists for
STADisconnect
andSTAGotIP
. We can also get a description for disconnection reasons, so display that instead of just a number. See Sming/Platform/WifiEvents.h.
That’s it.
References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 5 Library
- OneWire for Arduino Library
Basic WiFi¶
Demonstrates WiFi network connection and scanning functionality.
Enables an unsecured Software Access Point called Sming InternetOfThings which you can connect to from your smart phone (or other WiFi device).
Prints details of any probe requests, so you can see who’s scanning your device.
Scans list of available Access Points and displays them.
References¶
- Source Code
- Sming (main) Component
Basic rBoot¶
Introduction¶
This sample integrates rBoot and Sming, for the many people who have been asking for it. It demonstrates dual rom booting, big flash support, OTA updates and dual spiffs filesystems. You must enable big flash support in rBoot and use on an ESP12 (or similar device with 4MB flash). When using rBoot big flash support with multiple 1MB slots only one rom image needs to be created. If you don’t want to use big flash support (e.g. for a device with smaller flash) see the separate instructions below. You can easily take the ota files and add them to your own project to add OTA support.
Building¶
- Set
ESP_HOME
&SMING_HOME
, as environment variables or edit component.mk as you would for general Sming app compiling. - Set
WIFI_SSID
&WIFI_PWD
environment variables with your wifi details. - Edit the OTA server details at the top of
app/application.cpp
. - Check overridable variables in component.mk, or set as env vars.
make && make flash
- Put rom0.bin and spiff_rom.bin in the root of your webserver for OTA.
- Interact with the sample using a terminal (
make terminal
). Sorry - no web-gui (yet).
Flashing¶
If flashing manually use esptool.py to flash rBoot, rom & spiffs e.g.:
esptool.py –port write_flash -fs 32m 0x00000 rboot.bin 0x02000 rom0.bin 0x100000 spiffs.rom
Using the correct -fs parameter is important. This will be -fs 32m
on an ESP12.
You can also flash rom0.bin to 0x202000, but booting and using OTA is quicker!
Technical Notes¶
spiffs_mount_manual(address, length)
must be called from init.
Important compiler flags used:
- BOOT_BIG_FLASH - when using big flash mode, ensures flash mapping code is built in to the rom.
- RBOOT_INTEGRATION - ensures Sming specific options are pulled in to the rBoot source at compile time.
- SPIFF_SIZE=value - passed through to code for mounting the filesystem. Also used in the Makefile to create the SPIFFS.
Flash layout considerations¶
If you want to use, for example, two 512k roms in the first 1MB block of flash (old style) then Sming will automatically create two separately linked roms. If you are flashing a single rom to multiple 1MB flash blocks, all using the same offset inside their 1MB blocks, only a single rom is created. See the rBoot readme for further details.
- If using a very small flash (e.g. 512k) there may be no room for a spiffs fileystem, disable it with DISABLE_SPIFFS = 1
- If you are using spiffs set RBOOT_SPIFFS_0 & RBOOT_SPIFFS_1 to indicate where the filesystems are located on the flash.
- After building copy all the rom*.bin files to the root of your web server.
If you want more than two roms you must be an advanced user and should be able to work out what to copy and edit to acheive this!
Credits¶
This sample was made possible with the assistance of piperpilot, gschmott and robotiko on the esp8266.com forum.
References¶
- Source Code
- Sming (main) Component
CANBUS¶
Demonstrates communication with MCP2515-compatible devices via SPI interface.
References¶
- Source Code
- Sming (main) Component
- MCP_CAN Library for Arduino Library
CommandProcessing Debug¶
Demonstrates Sming’s command handling capability via HTTP, FTP and Telnet interfaces.
References¶
- Source Code
- Sming (main) Component
HMC5883L Compass¶
ESP8266 HMC5883L sensor reader.

References¶
- Source Code
- Sming (main) Component
- HMC5883L Compass Library
- I2C Device Class Library
DFPlayer Mini¶
Introduction¶
The DFPlayer Mini MP3 Player is a small and low price MP3 module with an simplified output directly to the speaker. The module can be used as a stand alone module with attached battery, speaker and push buttons or used in combination with an ESP8266 via RX/TX.
For more details see this link: https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299
Building¶
Steps to test this sample: * Connect DFPlayer Mini using RX/TX pins to TX/RX pins respectively of ESP8266. * Copy one or more mp3 file to an SD card. The example playes one file for some time and moves to next one. * Insert that SD card in the slot of the DF Player module. * Flash and run the sample code.
References¶
- Source Code
- Sming (main) Component
- DFPlayer - A Mini MP3 Player For Arduino Library
DS3232RTC NTP Setter¶
Connecting a real-time clock chip allows time to be maintained when OFF or in deep sleep modes without requiring an active network connection.
This example demonstrates how to do this using the popular DS3232 I2C device, and also how to set it up using a network time server.
References¶
- Source Code
- Sming (main) Component
- Arduino DS3232RTC Library v1.0 Library
TM1637 Display¶
Demonstrates use of 7-segment LED displays using TM1637 controller. This only requires 2 GPIO connections.
References¶
- Source Code
- Sming (main) Component
- TM1637 LED Driver Library
Distance measurement with Vl530xl sensor¶
This sample demonstrates how to use an inexpensive laser sensor VL53L0X to measure distance via I2C interface.
In addition to the original library a “long range” mode is added to measure distances up to 2 meter.
References¶
- Source Code
- Sming (main) Component
- References Library
DNS Captive Portal¶
Demonstrates how to use Sming to create a default landing page when configured as an Access Point.
References¶
- Source Code
- Sming (main) Component
Echo SSL¶
This example talks to an SSL-enabled TCP server. If you do not have such you can use ncat (from the nmap package) and run something like this:
ncat -vvv -l 0.0.0.0 4444 --ssl --ssl-key ~/Private/x.key --ssl-cert ~/Private/x.cert
See Basic SSL for information on compiling and configuring SSL.
References¶
- Source Code
- Sming (main) Component
FTP Server Files¶
This example sets up a simple FTP server with a couple of files stored in SPIFFS.
You’ll need to have WiFi configured. You can set this information when building like this:
make WIFI_SSID=ssid WIFI_PWD=password
substituting your actual Access Point details for ssid and password.
After flashing:
make flashapp
You should be able to connect using an FTP client:
ftp ipaddress
References¶
- Source Code
- Sming (main) Component
APDS-9660 Gesture¶
Gesture sensors allow ambient light and colour measuring, proximity detection and touchless gesture sensing.
This sample demonstrates how to use the APDS-9660 which is connected via I2C interface.
References¶
- Source Code
- Sming (main) Component
- SparkFun APDS9960 RGB and Gesture Sensor Arduino Library Library
HTTP Client¶
See Basic SSL for information on compiling and configuring SSL.
References¶
- Source Code
- Sming (main) Component
HttpClient Instapush¶
Instapush is an event notification service created in 2014.
For details, see https://pushbots.com/.
References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 6 Library
ThingSpeak Http Client¶
Example of HttpClient and direct ESP8266 ThingSpeak data pushing.

References¶
- Source Code
- Sming (main) Component
AJAX Http Server¶
Demonstration of a simple web server with page updates using AJAX.
References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 6 Library
Bootstrap Http Server¶
ESP8266 embedded web server.
At start ESP will download all requried files from remote server. All content, including JQuery and Bootstrap will be saved on device (and can work offline). Static files stored in GZIPed mode.

References¶
- Source Code
- Sming (main) Component
HttpServer Config Network¶
Introduction¶
The HTTP server coming with Sming is quite powerful but it is limited from the available resources of the underlining hardware (your favorite ESP8266 microcontroller). Serving multiple files at once can be problematic. It is not the size of the files that can cause problems, but the number of simultaneous files that need to be delivered. Therefore if you serve multiple CSS or JS files you can optimize your web application before uploading it into your ESP8266 using the advice below.
Optimizing File Delivery¶
In this example you will see how to combine CSS and JS files, compress them and deliver the optimized content via the HTTP server.
Installation¶
The file optimization uses gulp
. To install it and the needed gulp
packages you need to install first npm. Npm
is the Node.JS package manager. Once you are done with the installation
you can run from the command line the following:
npm install
The command above will install gulp and its dependencies.
Usage¶
During the development of your web application you should work only in
the web/dev/
folder. Once you are ready with the application you can
pack
the resources and upload
them to your device. The commands
are
make web-pack make web-upload
That should be it.
References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 6 Library
HttpServer Firmware Upload¶
This example combines the libraries Multipart Parser for file uploads and Over-the-Air Firmware Upgrade, to create a browser based firmware upgrade solution akin to what’s found in many consumer devices. The example is kept as minimal as possible to serve as a starting point for your own applications.
About HTTP server file upload¶
The HTTP server coming with Sming is quite powerful but it is limited by the available resources of the underlining hardware (your favorite ESP8266 microcontroller).
This sample demonstrates how to use the Multipart Parser library to enable file upload of the HTTP server. On a normal computer the file uploads are usually using temporary space on the hard disk or in memory to store the incoming data.
On an embedded device that is a luxury that we can hardly afford. In this sample we demonstrate how to define which file upload fields should be recognized and what (file) streams are responsible for processing and storing the data. If a field is not specified then its content will be discarded.
About OtaUpgrade¶
The OtaUpgrade component provides the OtaUpgradeStream
class which
is hooked up to the web server to process a firmware upgrade file uploaded to
the device.
The component is also responsible for creating the upgrade files during the build
process. A single upgrade file conveniently encapsulates all ROM images, thereby
relieving the user from having to know the slot that is updated and manually
selecting the corresponding ROM image in a Two-ROM configuration.
The file format also supports state-of-the-art security features like a digital
signature, encryption and downgrade protection. You are invited to play with
them and observe their impact on code size. See also the Over-the-Air Firmware Upgrade
documentation for further advice on how to use the security features properly.
Usage instructions¶
Configure your flash memory layout:
- Set
SPI_SIZE
to the flash memory size of your device. - If necessary, modify
RBOOT_ROM0_ADDR
,RBOOT_ROM1_ADDR
,RBOOT_SPIFFS_0
andSPIFF_SIZE
to fit both ROM slots and the file system into the available flash memory. Make sure that the flash areas do not overlap with each other or any the reserved regions. Refer to the rBoot documentation for further details.
- Set
Build the example by running:
make
Connect your device via USB/Serial cable and run:
make flashconfig
to clear any remains of the previous flash layout configuration, followed by:
make flash
to install the example firmware. You need to do this only once. Subsequent updates can be performed wirelessly using the web interface.
Point the browser to your ESP’s IP address to open the firmware upgrade page.
Select the upgrade file, which has been automatically created alongside step 2 from
out/Esp8266/<build-type>/firmware/firmware.ota
and hit the “Update” button.After a few seconds, you should see a confirmation the the upgrade was successful. The device now reboots into the upgraded firmware.
If the upgrade is not successful, rebuild with debug output enabled and check the serial console for error messages.
References¶
- Source Code
- Sming (main) Component
- Multipart Parser Library
- Over-the-Air Firmware Upgrade Library
HttpServer Websockets¶
Simple example of how to support persistent websocket connections in a server.
References¶
- Source Code
- Sming (main) Component
AM2321 Humidity Sensor¶
Example application demonstrating the use of the AM2321 Temperature/Humidity Sensor library.
References¶
- Source Code
- Sming (main) Component
- AM2321 Temperature/Humidity Sensor Library
DHT22 Humidity Sensor¶
Example application demonstrating the use of the DHT ESP Temperature/Humidity Sensors library with a DHT22 humidity sensor.

References¶
- Source Code
- Sming (main) Component
- DHT ESP Temperature/Humidity Sensors Library
SI7021 Humidity Sensor¶
Introduction¶
Example code for I2C SI7021 sensor board
This code uses the following GPIO:
- #define I2C_SCL 5 // SCL
- #define I2C_SDA 4 // SCA
Build instructions¶
Use make
and make flash
to build and flash the firmware to the
ESP8266 board.
References¶
- Source Code
- Sming (main) Component
- SI7020/SI7021 Environmental Sensors Library
IR Library¶
Example application demonstrating how to receive IR remote signals using the ESP8266.
References¶
- Source Code
- Sming (main) Component
- IRremoteESP8266 Library Library
WS2812 LEDs¶
Example application to demonstrate control of WS2812 RGB pixel-strip LEDs.
References¶
- Source Code
- Sming (main) Component
- WS2812 Neopixel Library
Yeelight LED bulbs¶
Demonstrates how to control Yeelight WiFi devices.
References¶
- Source Code
- Sming (main) Component
- Yeelight Library
BH1750 Light Sensor¶
ESP8266 BH1750 sensor reader.

References¶
- Source Code
- Sming (main) Component
- BH1750FVI Light Sensor Library
Liquid Crystal 44780¶
Introduction¶
Example code for I2C LiquidCrystal LCDs.

This code uses the following GPIO:
- GPIO0 SCL
- GPIO2 SDA
Build instructions¶
Use make
and make flash
to build and flash the firmware to the
ESP8266 board.
References¶
- Source Code
- Sming (main) Component
- Liquid Crystal Library
Live Debug¶
This project is an example of how to integrate GDB debugging into your project. It provides a basic command interface which you can use via regular serial terminal or with the GDB application.
To use this sample application with the command-line GDB application, simply build and flash the project as usual:
make clean
make flash
You should be presented with the GDB command prompt. Enter ‘c’ to continue running the application:
(gdb) c
Continuing.
(attached)
The (attached)
prompt is displayed by the LiveDebug application.
Type help
to get a list of available commands.
Note that if you run this application via serial terminal
(make terminal
) you’ll get the (Detached)
prompt instead.
- Debugging under eclipse
Interacting with the GDB console causes problems for eclipse, so compile
with the ENABLE_GDB_CONSOLE=0
option:
make clean
make flash ENABLE_CONSOLE=0
Alternatively, use the consoleOff
command from the GDB command
prompt, then quit the debugger and connect via eclipse.
Exception Handling¶
Sming comes with a built-in exception handling that takes care to display the stack trace leading to the issue. Usually it looks like this:
***** Fatal exception 28 (LOAD_PROHIBITED)
pc=0x40100e96 sp=0x3ffff640 excvaddr=0x000015b8
ps=0x00000033 sar=0x00000018 vpri=0x000000f0
r00: 0x40100d69=1074793833 r01: 0x3ffff640=1073739328 r02: 0x3fff3900=1073690880
r03: 0x2b265ed4= 723934932 r04: 0x3fffbff0=1073725424 r05: 0x000015b8= 5560
r06: 0x000015b8= 5560 r07: 0x14a8433b= 346571579 r08: 0x00000008= 8
r09: 0x14a842f3= 346571507 r10: 0x3fff22d0=1073685200 r11: 0x00000003= 3
r12: 0x00000048= 72 r13: 0x3fff38c0=1073690816 r14: 0x3ffe9da0=1073651104
r15: 0x3fff1138=1073680696
Stack dump:
To decode the stack dump call from command line:
make decode-stacktrace
and copy & paste the text enclosed in '===='.
================================================================
3ffff640: 40100e96 00000033 00000018 000000f0
3ffff650: 40100d69 3fff3900 2b265ed4 3fffbff0
3ffff660: 000015b8 000015b8 14a8433b 00000008
3ffff670: 14a842f3 3fff22d0 00000003 00000048
3ffff680: 3fff38c0 3ffe9da0 3fff1138 0000001c
3ffff690: 002222fb c0fb5c01 0bc10000 facfd1fb
3ffff6a0: 620020c0 6162802d 0020c004 59062c52
3ffff6b0: 0020c051 61492c48 210020c0 7c38fb50
...
================================================================
Enter make decode-stacktrace
then copy & paste the text
to produce something readable like this:
0x40100e96: pvPortRealloc at ??: ?
0x40100d69: pvPortMalloc at ??:?
0x402455f0: ax_port_malloc at C:\tools\Sming-3.1.2\Sming/third-party/axtls-8266/ replacements/mem.c:51
0x4024561a: ax_port_calloc at C:\tools\Sming-3.1.2\Sming/third-party/axtls-8266/ replacements/mem.c:63
0x40230acc: x509_new at c:\tools\Sming-3.1.2\Sming\third-party\axtls-8266/ssl/x5 09.c:81
0x4023d3e4: m_vsnprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:69
0x4023d4a6: m_vprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:83
0x40000a39: ?? ??:0
0x4021418a: pp_attach at ??:?
0x40221d60: pbuf_alloc at ??:?
0x40221f0a: pbuf_copy at ??:?
0x4023d3e4: m_vsnprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:69
Note that you can also put the stack trace into a file, for example dump.txt
then enter:
make decode-stacktrace TRACE=dump.txt
Using the information about the type of the exception (ex:
***** Fatal exception 28
) and the sequence of commands might help us
figure out the issue.
But that information might not be enough. And finding the root cause may take quite some time.
GDB Debugging¶
Debugging is a powerful technique allowing you to interactively run your code and be able to see much more information about the things that went wrong.
To use, (Re)compile your project with the ENABLE_GDB
option and
flash it to the board:
make clean
make ENABLE_GDB=1
make flash
Instead of a terminal, the GDB console will be opened automatically.
If you need to run GDB manually after resetting the board or after it has run into an exception, use the provided script:
make gdb
Note that software breakpoints (‘br’) only work on code that is in RAM. During development you can use the GDB_IRAM_ATTR attribute in your function declarations. Code in flash can only have a hardware breakpoint (‘hbr’).
Read the GDB stub Notes for more information.
References¶
- Source Code
- Sming (main) Component
MeteoControl¶
More complex example of Internet of Things device. Can read humidity and temperature data from sensor and output it to screen with actual time. Time loaded directly from Google. Also with device can automatically control any external load.
Features:
- temperature
- humidity
- actual time from internet
- built-in display
- web control interface
- automatically control external load
- HTTP API for data reading & writing
- initialization from internet at first run



How web interface looks like:

References¶
- Source Code
- Sming (main) Component
- ArduinoJson Version 6 Library
- DHT ESP Temperature/Humidity Sensors Library
- Liquid Crystal Library
MeteoControl MQTT¶
Similar to MeteoControl sample without LCD interface and instead controlled via MQTT.
References¶
- Source Code
- Sming (main) Component
- BMP180 Pressure/Temperature Sensor Library
- SI7020/SI7021 Environmental Sensors Library
Nextion Button¶
See this example in action: https://youtu.be/lHk6fqDBHyI
The HMI file included in this example needs to be compiled with the Nextion Editor and uploaded to the Nextion display using standard method.
On WEMOS mini D1 (where this example was tested), the Nextion device is connected to RX/TX pins as required. BUT it needs to be disconnected when uploading the firmware.
So the process is:
- Make changes to the cpp code
- Build it using “make”
- Disconnect the Nextion display if it is connected to Rx/Tx.
- Upload firmware (built in step 2) using “make flash”.
- Connect Nextion display back again to Rx/Tx.
Note
Always unplug the ESP8266 from USB (connecting with computer) or disconnect power before fiddling with the connections between ESP8266 and Nextion display.
References¶
- Source Code
- Sming (main) Component
- Nextion Serial Displays Library
MCP23017 I2C Port Expander¶
You can easily add more GPIO connections for an ESP8266 using a port expander. This example demonstrates how to do that with a common I2C port expander.
If you need a faster connection, see MCP23S17 SPI Port Expander.
References¶
- Source Code
- Sming (main) Component
- MCP23017 I2C Port Expander Library
MCP23S17 SPI Port Expander¶
You can easily add more GPIO connections for an ESP8266 using a port expander. This example demonstrates how to do that with a common SPI port expander.
These devices are perhaps a little less common than their I2C equivalents, see MCP23017 I2C Port Expander.
References¶
- Source Code
- Sming (main) Component
- MCP23S17 SPI Port Expander Library
BMP180 Pressure Sensor¶
Introduction¶
Example code for I2C BMP180 sensor board

This code uses the following GPIO:
- GPIO0 SCL
- GPIO2 SDA
Build instructions¶
Use make
and make flash
to build and flash the firmware to the
ESP8266 board.
References¶
- Source Code
- Sming (main) Component
- BMP180 Pressure/Temperature Sensor Library
RCSwitch Library¶
Demonstration of how to control wireless (radio-controlled) devices such as switched mains sockets, TVs, etc.
References¶
- Source Code
- Sming (main) Component
- rc-switch Library
nRF24L01 Radio¶
Example application showing how to interface with the popular nRF24L01 2.4GHz radio transceivers.
References¶
- Source Code
- Sming (main) Component
- Arduino driver for nRF24L01 2.4GHz Wireless Transceiver Library
- ILI9163C TFT Display Library
SI443 Radio¶
Example application for radio module Si4432 aka RF22 driver. Link: http://www.electrodragon.com/w/SI4432_433M-Wireless_Transceiver_Module_%281.5KM_Range,_Shield-Protected%29
References¶
- Source Code
- Sming (main) Component
- Si4432 RF Transceiver Library
RingTone Player¶
Introduction¶
You may find the need to include basic audio features such as haptic feedback or tune generation to support an existing application. The advantage of using I2S for this is the very low CPU overhead.
This sample demonstrates how simple audio can be added to an application using the I2S ToneGenerator and RingTone libraries. The sample contains a selection of tunes.
The sample may be controlled via serial terminal, or by web interface.
Serial connection¶
Because I2S uses the serial RX pin, the serial port uses the alternate pin mappings. See Tone Generator for connection details.
You’ll still need the regular serial port for programming. Here’s a sample setup for Windows:
- Using NodeMCU with standard serial port connected to COM4
- Second USB/UART converter connected to alternate serial pins as COM8
The command line to build, flash and open a terminal would be:
make -j COM_PORT=COM8 COM_SPEED=115200 COM_PORT_ESPTOOL=COM4 COM_SPEED_ESPTOOL=921600 SPI_MODE=dio SPI_SIZE=4M
make flashinit
make flash
Web interface¶
This is built using Bootstrap 4.3.1 and jQuery 3.4.1.

Reboot
- Un-installs the I2S driver then restarts the system after 5-seconds. The memory consumption drops as the DMA buffers are de-allocated.
Play controls
- ▢ Stop
- Tune playback stops at the current position, and the I2S driver is stopped so I2S interrupts are disabled. DMA buffers remain allocated.
- || Pause
- Tune playback stops at the current position, but I2S interrupts remain active.
- ▷ Play
- Resumes tune playback from stop/pause states.
Voice and Mode
Selects available voice for the tone generator (Sine, Triangular, Sawtooth or Square wave).
Playback mode
- ⇢ Sequential
- 🔀 Random
Playback speed¶
Tune selection¶
- ↤ Previous
- Play previous tune
- ↲ Rewind
- Rewind to start of current tune
- ↦ Next
- Play next tune
- → Skip
- Skip to a random tune
- Shows the current tune and elapsed play time. A drop-down list shows all available tunes.
Graphs¶
In addition to play controls, there are three graphs showing some statistics over a two-minute period. The data is sent from the ESP8266 via websocket once per second.
- CPU Usage
Gives an indication of processor loading. Try connecting a second web client to see what happens.
- Fill Time
Shows the time taken by the Tone Generator to create and buffer tone waveforms.
This graph has three traces, indicating time in milliseconds over the 1-second update period:
- Red: Longest time taken
- Green: Shortest time
- Black: Average time
You’ll see more activity during complex, fast tunes but also for lower notes which require more samples (and larger buffers).
The progress bar indicates the total time taken over the update period.
- Memory Usage
The graph has three traces:
- Black: Available memory
- Red: Maximum memory used during the update period
- Green: Memory in use at the time of update
The red/green traces generally follow each other and represent the allocation/deallocation of tone buffers.
References¶
- Source Code
- Sming (main) Component
- malloc_count Component
- ArduinoJson Version 6 Library
- RingTone Library
- Tone Generator Library
SD Card¶
SDCard/FAT file usage and write benchmark.
References¶
- Source Code
- Sming (main) Component
- SD Card Library
5110 LCD Screen¶
How to interface to Monochrome Nokia 5110 LCD Displays.
References¶
- Source Code
- Sming (main) Component
- Adafruit PCD8544 Display Library
SSD1306 OLED Screen¶
Example of direct work with SSD1306 OLED screen on ESP8266.
Minimal requirements: ESP-03

References¶
- Source Code
- Sming (main) Component
- Adafruit SSD1306 Display Library
ILI9163C TFT Screen¶
Example of direct work with ILI9163C 1.44” TFT screen on ESP8266.
Minimal requirements: ESP-03

References¶
- Source Code
- Sming (main) Component
- ILI9163C TFT Display Library
ILI9340 and ILI9341 TFT Screens¶
How to interface with displays such as the Adafruit 2.8” Touch Shield V2 (SPI).
References¶
- Source Code
- Sming (main) Component
- Adafruit ILI9341 Display Library
ST7735 TFT Screen¶
How to interface with various SPI displays using the Adafruit ST7735 library.
References¶
- Source Code
- Sming (main) Component
- Adafruit ST7735 Display Library
SMTP Client¶
Purpose¶
To show the basics of sending an email via SMTP
SMTP¶
When an IOT device detects a malfunction, it is good to be able to notify the user. We can do that either by sending them an email or via a service like MQTT.
This sample shows how to send an email via SMTP directly from the ESP8266.
smtp2go conveniently provides a free account.
Create an account here: https://www.smtp2go.com/setupguide/arduino/ .
It needs some configuration: * the name of the SMTP server, eg “mail.smtp2go.com” * a username and password * the name and email of the person from whom the email will be sent * the name and email of the person to send the email to
Edit the sample to replace these values and the SSID etc.
References¶
- Source Code
- Sming (main) Component
SystemClock NTP¶
Demonstrates various methods for keeping the system clock updated from a Network Time Server using the NtpClient class.
The Timezone class is used to convert between UTC and local times, accounting for daylight savings.
The SolarCalculator class is used to calculate times of next sunrise and sunset, which you might want to automate activation of lights, for example.
References¶
- Source Code
- Sming (main) Component
- Solar Calculator Library
- Timezone Library
TCP Client NarodMon¶
An example of sending data to narodmon.ru using a TCP client.
https://narodmon.ru was is a geo-information project to display on the world map and control (on PCs, smartphones and other gadgets) the sensor readings of its members (temperature, humidity, pressure, wind speed and direction, radiation, energy consumption and any other values), as well as private and urban webcams for public or private viewing.
References¶
- Source Code
- Sming (main) Component
Telnet TCP Client / Server¶
Demonstrates a simple Telnet server application.
References¶
- Source Code
- Sming (main) Component
DS1820 Temperature Sensor¶
ESP8266 DS1820/DS18B20 sensor reader.

References¶
- Source Code
- Sming (main) Component
- DS18S20 Temperature Sensor Library
UDP Server Echo¶
Sets up a UDP server which echoes back incoming packets. By default listens on port 1234.
References¶
- Source Code
- Sming (main) Component
UDP Server mDNS¶
Instructions¶
The multicast Domain Name System (mDNS) resolves host names to IP addresses within small networks that do not include a local name server.
More info on mDNS can be found at https://en.wikipedia.org/wiki/Multicast_DNS
mDNS has two parts:
- Advertise
- Listen
This example just does Advertise.
Listen implementation is still on going work and will be basically porting http://gkaindl.com/software/arduino-ethernet/bonjour to “Sming”.
In short this code will advertise other machines about its ipaddress.
But you can not convert other mDNS advertiser’s host name to ipaddress. (this is work of Listening)
How to use mDNS:
ADD your WIFI_SSID / Password
Flash the Complied code to ESP8266
According to OS of your PC / phone
- Mac OS (iphone/ipad/ mac)
in Safari browser type “http://test.local/” to open a sample webpage.
- Windows
You need Bonjour Service running. If you do not have it Install it from http://download.cnet.com/Bonjour-for-Windows/3000-18507_4-93550.html.
After installing in IE or Chrome or other browser type “http://test.local/” to open a sample webpage.
- Linux
You need to install Avahi mDNS/DNS-SD daemon.
In your browser type “http://test.local/” to open a sample webpage.
- Android
You need to install ZeroConf Browser or Bonjour Browser.
In those app you would be able to see IP address of your ESP module.
In android Chrome “http://test.local/” does not translate to IP address, so android Chrome is not supporting mDNS.
But you can make your own app using Network Service Discovery. See http://developer.android.com/training/connect-devices-wirelessly/nsd.html for details.
References¶
- Source Code
- Sming (main) Component
HCSR04 Ultrasonic Transducer¶
Shows how to use an HCSR04 module to measure distances.
Warning
Ultrasonic_HCSR04 modules usually work with 5v power and TTL levels, so You need voltage divider or level shifter for ECHO pin.
Trigger pin is tolerant for 3.3v and in my case work without problems
By nik.sharky http://esp8266.ru/forum/members/sharky.396/
References¶
- Source Code
- Sming (main) Component
- Ultrasonic Library
WebcamServer sample¶
A sample providing access to webcams via HTTP server.
References¶
- Source Code
- Sming (main) Component
- WebCam Library
Websocket Client¶
This is a simple demo of the WebsocketClient class.
The client tries to connect to echo.websocket.org. It sents 10 messages then client connection is closed. It reconnects and sends 25 messages and continues doing same.
This demo shows connecton, closing and reconnection methods of WebsocketClient.
References¶
- Source Code
- Sming (main) Component
WiFi Sniffer¶
Introduction¶
This is an adaptation of the WiFi promiscuous mode demo code from Arduino
See https://www.hackster.io/rayburne/esp8266-mini-sniff-f6b93a
// Notes.h tab in Arduino IDE is only for comments and references!
// based on RandDruid/esp8266-deauth (MIT) https://github.com/RandDruid/esp8266-deauth
// inspired by kripthor/WiFiBeaconJam (no license) https://github.com/kripthor/WiFiBeaconJam
// https://git.schneefux.xyz/schneefux/jimmiejammer/src/master/jimmiejammer.ino
// requires SDK v1.3: install esp8266/Arduino from git and checkout commit 1c5751460b7988041fdc80e0f28a31464cdf97a3
// Modified by M. Ray Burnette for publication as WiFi Sniffer 20161013
/*
Arduino 1.6.12 on Linux Mint 17.3
Sketch uses 227,309 bytes (21%) of program storage space. Maximum is 1,044,464 bytes.
Global variables use 45,196 bytes (55%) of dynamic memory, leaving 36,724 bytes for local variables. Maximum is 81,920 bytes.
*/
/*
// beacon template
uint8_t template_beacon[128] = { 0x80, 0x00, 0x00, 0x00,
/*4*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
/*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
/*22*/ 0xc0, 0x6c,
/*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00,
/*32*/ 0x64, 0x00,
/*34*/ 0x01, 0x04,
/* SSID */
/*36*/ 0x00, 0x06, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c,
0x03, 0x01,
/*56*/ 0x04
}
;
* /
/* Notes:
Ref: http://www.esp8266.com/viewtopic.php?f=32&t=7025
In the ESP8266WiFi.h, there is the function getNetworkInfo() which I presume allows you to get
info for hidden AP.
bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden);
CODE: SELECT ALL
/**
loads all infos from a scanned wifi in to the ptr parameters
@param networkItem uint8_t
@param ssid const char*
@param encryptionType uint8_t
@param RSSI int32_t
@param BSSID uint8_t *
@param channel int32_t
@param isHidden bool
@return (true if ok)
*/
/* Serial Console Sample Output:
ESP8266 mini-sniff by Ray Burnette http://www.hackster.io/rayburne/projects
Type: /-------MAC------/-----WiFi Access Point SSID-----/ /----MAC---/ Chnl RSSI
BEACON: <=============== [ TardisTime] 1afe34a08bc9 8 -76
BEACON: <=============== [ xfinitywifi] 56571a0730c0 11 -90
BEACON: <=============== [ ] 52571a0730c0 11 -91
BEACON: <=============== [ ATTGH6Gs22] 1005b1d6ff90 11 -95
BEACON: <=============== [ ATT4P3G9f8] 1c1448777420 11 -92
BEACON: <=============== [ HOME-30C2] 5c571a0730c0 11 -91
BEACON: <=============== [ ATT8Q4z656] b077acc4dfd0 11 -92
BEACON: <=============== [ HOME-B1C2] 94877c55b1c0 11 -94
BEACON: <=============== [ HUXU2012] 0c54a5d6e480 6 -94
BEACON: <=============== [ xfinitywifi] 0c54a5d6e482 6 -97
BEACON: <=============== [ ] 0c54a5d6e481 6 -96
DEVICE: 18fe34fdc2b8 ==> [ TardisTime] 1afe34a08bc9 8 -79
DEVICE: 18fe34f977a0 ==> [ TardisTime] 1afe34a08bc9 8 -94
DEVICE: 6002b4484f2d ==> [ ATTGH6Gs22] 0180c2000000 11 -98
BEACON: <=============== [ HOME-01FC-2.4] 84002da251d8 6 -100
DEVICE: 503955d34834 ==> [ ATT8Q4z656] 01005e7ffffa 11 -87
BEACON: <=============== [ ] 84002da251d9 6 -98
BEACON: <=============== [ xfinitywifi] 84002da251da 6 -95
BEACON: <=============== [ ] fa8fca34e26c 11 -94
DEVICE: cc0dec048363 ==> [ ATT8Q4z656] 01005e7ffffa 11 -88
BEACON: <=============== [ ] fa8fca95bad3 11 -92
BEACON: <=============== [ HOME-5475] 58238c3b5475 1 -96
BEACON: <=============== [ xfinitywifi] 5a238c3b5477 1 -94
BEACON: <=============== [ ] 5a238c3b5476 1 -96
DEVICE: 1859330bf08e ==> [ ATT8Q4z656] 01005e7ffffa 11 -92
BEACON: <=============== [ ] 92877c55b1c0 11 -92
DEVICE: f45fd47bd5e0 ==> [ ATTGH6Gs22] ffffffffffff 11 -93
BEACON: <=============== [ Lynch] 744401480a27 11 -96
BEACON: <=============== [ xfinitywifi] 96877c55b1c0 11 -93
DEVICE: f43e9d006c10 ==> [ xfinitywifi] 8485066ff726 6 -96
DEVICE: 285aeb4f16bf ==> [ ATTGH6Gs22] 3333ffb3c678 11 -94
DEVICE: 006b9e7fab90 ==> [ ATTGH6Gs22] 01005e7ffffa 11 -91
DEVICE: 78456155b9f0 ==> [ Lynch] 01005e7ffffa 11 -95
DEVICE: 6cadf84a419d ==> [ HOME-30C2] 88cb8787697a 11 -89
BEACON: <=============== [ Verizon-SM-G935V-6526] a608ea306526 11 -92
*/
References¶
- Source Code
- Sming (main) Component
Libraries¶
Sming comes with a number of ported libraries that cover many areas of embedded programming but for sure not all.
These are all the libraries included with Sming:
AM2321 Temperature/Humidity Sensor¶
- AM2321 sensor support for Arduino.
- See Arduino AM2321
Example:¶
#include <AM2321.h>
void readByAM2321()
{
AM2321 am2321;
am2321.read();
Serial.print("(");
Serial.print(am2321.temperature/10.0);
Serial.print(", ");
Serial.print(am2321.humidity/10.0);
Serial.println(')');
}
References¶
Used by¶
- AM2321 Humidity Sensor Sample
APA102 LED¶
APA102 library by HappyCodingRobot@github.com
APA102 class enhanced to work with hardware SPI and software SPI. Changed to work with the new SPI implementation.
See Pull Request #787.
References¶
Used by¶
- Basic APA102 Sample
Adafruit BME280 Humidity/Pressure/Temperature sensor¶
This is a library for the Adafruit BME280 Humidity, Barometric Pressure + Temp sensor
Designed specifically to work with the Adafruit BME280 Breakout
These sensors use I2C or SPI to communicate, up to 4 pins are required to interface
Use of this library also requires Adafruit_Sensor to be installed on your local system.
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Check out the links above for our tutorials and wiring diagrams
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
To download. click the DOWNLOAD ZIP button, rename the uncompressed folder Adafruit_BME280. Check that the Adafruit_BME280 folder contains Adafruit_BME280.cpp and Adafruit_BME280.h
Place the Adafruit_BME280 library folder your arduinosketchfolder/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
We also have a great tutorial on Arduino library installation at: http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use
Compatibility¶
MCU | Tested Works | Doesn’t Work | Not Tested | Notes |
---|---|---|---|---|
Atmega328 @ 16MHz | X | |||
Atmega328 @ 12MHz | X | |||
Atmega32u4 @ 16MHz | X | Use SDA/SCL on pins D2 & D3 | ||
Atmega32u4 @ 8MHz | X | Use SDA/SCL on pins D2 & D3 | ||
ESP8266 | X | I2C: just works, SPI: SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) | ||
ESP32 | X | I2C: just works, SPI: SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) | ||
Atmega2560 @ 16MHz | X | Use SDA/SCL on pins 20 & 21 | ||
ATSAM3X8E | X | Use SDA/SCL on pins 20 & 21 | ||
ATSAM21D | X | |||
ATtiny85 @ 16MHz | X | |||
ATtiny85 @ 8MHz | X | |||
Intel Curie @ 32MHz | X | |||
STM32F2 | X |
- ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
- ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
- ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
- ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
- ESP8266 : Adafruit Huzzah
- ATmega2560 @ 16MHz : Arduino Mega
- ATSAM3X8E : Arduino Due
- ATSAM21D : Arduino Zero, M0 Pro
- ATtiny85 @ 16MHz : Adafruit Trinket 5V
- ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
References¶
- Source Code (submodule, may be patched).
- Adafruit Unified Sensor Driver Component
Adafruit GFX¶
This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions).
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, check license.txt for more information. All text above must be included in any redistribution.
To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h
Place the Adafruit_GFX library folder your
Useful Resources¶
Image2Code This is a handy Java GUI utility to convert a BMP file into the array code necessary to display the image with the drawBitmap function. Check out the code at ehubin’s GitHub repository:
drawXBitmap function You can use the GIMP photo editor to save a .xbm file and use the array saved in the file to draw a bitmap with the drawXBitmap function. See the pull request here for more details:
References¶
Used by¶
- Adafruit ILI9341 Display Library
- Adafruit PCD8544 Display Library
- Adafruit SSD1306 Display Library
- Adafruit ST7735 Display Library
- ILI9163C TFT Display Library
Adafruit ILI9341 Display¶
This is a library for the Adafruit ILI9341 display products
- This library works with the Adafruit 2.8” Touch Shield V2 (SPI)
- —-> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams. These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional).
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ILI9341. Check that the Adafruit_ILI9341 folder contains Adafruit_ILI9341.cpp and Adafruit_ILI9341.
Place the Adafruit_ILI9341 library folder your arduinosketchfolder/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE
Also requires the Adafruit_GFX library for Arduino.
References¶
- Source Code
- Adafruit GFX Component
Used by¶
Adafruit NeoPixel Library¶
This library edited and adapted for Sming project by alonewolfx2 alonewolf07@gmail.com
Arduino library for controlling single-wire-based LED pixels and strip such as the Adafruit 60 LED/meter Digital LED strip, the Adafruit FLORA RGB Smart Pixel, the Adafruit Breadboard-friendly RGB Smart Pixel, the Adafruit NeoPixel Stick, and the Adafruit NeoPixel Shield.
After downloading, rename folder to ‘Adafruit_NeoPixel’ and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch.
Compatibility notes: Port A is not supported on any AVR processors at this time
Supported chipsets¶
We have included code for the following chips - sometimes these break for exciting reasons that we can’t control in which case please open an issue!
- AVR ATmega and ATtiny (any 8-bit) - 8 MHz, 12 MHz and 16 MHz
- Teensy 3.x and LC
- Arduino Due
- Arduino 101
- ATSAMD21 (Arduino Zero/M0 and other SAMD21 boards) @ 48 MHz
- ATSAMD51 @ 120 MHz
- Adafruit STM32 Feather @ 120 MHz
- ESP8266 any speed
- ESP32 any speed
- Nordic nRF52 (Adafruit Feather nRF52), nRF51 (micro:bit)
Check forks for other architectures not listed here!
Roadmap¶
The PRIME DIRECTIVE is to maintain backward compatibility with existing Arduino sketches – many are hosted elsewhere and don’t track changes here, some are in print and can never be changed!
Please don’t reformat code for the sake of reformatting code. The resulting large “visual diff” makes it impossible to untangle actual bug fixes from merely rearranged lines. (Exception for first item in wishlist below.)
Things I’d Like To Do But There’s No Official Timeline So Please Don’t Count On Any Of This Ever Being Canonical:
- For the show() function (with all the delicate pixel timing stuff), break out each architecture into separate source files rather than the current unmaintainable tangle of #ifdef statements!
- Please don’t use updateLength() or updateType() in new code. They should not have been implemented this way (use the C++ ‘new’ operator with the regular constructor instead) and are only sticking around because of the Prime Directive. setPin() is OK for now though, it’s a trick we can use to ‘recycle’ pixel memory across multiple strips.
- In the M0 and M4 code, use the hardware systick counter for bit timing rather than hand-tweaked NOPs (a temporary kludge at the time because I wasn’t reading systick correctly). (As of 1.4.2, systick is used on M4 devices and it appears to be overclock-compatible. Not for M0 yet, which is why this item is still here.)
- As currently written, brightness scaling is still a “destructive” operation – pixel values are altered in RAM and the original value as set can’t be accurately read back, only approximated, which has been confusing and frustrating to users. It was done this way at the time because NeoPixel timing is strict, AVR microcontrollers (all we had at the time) are limited, and assembly language is hard. All the 32-bit architectures should have no problem handling nondestructive brightness scaling – calculating each byte immediately before it’s sent out the wire, maintaining the original set value in RAM – the work just hasn’t been done. There’s a fair chance even the AVR code could manage it with some intense focus. (The DotStar library achieves nondestructive brightness scaling because it doesn’t have to manage data timing so carefully…every architecture, even ATtiny, just takes whatever cycles it needs for the multiply/shift operations.)
References¶
Used by¶
- Basic Neopixel Sample
Adafruit PCD8544 Display¶
This is a library for our Monochrome Nokia 5110 LCD Displays
Pick one up today in the adafruit shop! ——> http://www.adafruit.com/products/338
These displays use SPI to communicate, 4 or 5 pins are required to
interface
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above must be included in any redistribution
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_PCD8544. Check that the Adafruit_PCD8544 folder contains Adafruit_PCD8544.cpp and Adafruit_PCD8544.h
Place the Adafruit_PCD8544 library folder your
You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from https://github.com/adafruit/Adafruit-GFX-Library and download/install that library as well
References¶
- Source Code
- Adafruit GFX Component
Used by¶
- 5110 LCD Screen Sample
Adafruit SSD1306 Display¶
Introduction¶
This is a library for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop! ——> http://www.adafruit.com/category/63_98
These displays use SPI to communicate, 4 or 5 pins are required to
interface
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
Scrolling code contributed by Michael Gregg
BSD license, check license.txt for more information
All text above must be included in any redistribution
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h
Place the Adafruit_SSD1306 library folder your
You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from https://github.com/adafruit/Adafruit-GFX-Library and download/install that library as well
Compatibility¶
MCU | Tested Works | Doesn’t Work | Not Tested | Notes |
---|---|---|---|---|
Atmega328 @ 16MHz | X | |||
Atmega328 @ 12MHz | X | |||
Atmega32u4 @ 16MHz | X | |||
Atmega32u4 @ 8MHz | X | |||
ESP8266 | X | change OLED_RESET to different pin if using default I2C pins D4/D5. | ||
Atmega2560 @ 16MHz | X | |||
ATSAM3X8E | X | |||
ATSAM21D | X | |||
ATtiny85 @ 16MHz | X | |||
ATtiny85 @ 8MHz | X | |||
Intel Curie @ 32MHz | X | |||
STM32F2 | X |
- ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
- ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
- ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
- ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
- ESP8266 : Adafruit Huzzah
- ATmega2560 @ 16MHz : Arduino Mega
- ATSAM3X8E : Arduino Due
- ATSAM21D : Arduino Zero, M0 Pro
- ATtiny85 @ 16MHz : Adafruit Trinket 5V
- ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V
References¶
- Source Code (submodule, may be patched).
- Adafruit GFX Component
Used by¶
- SSD1306 OLED Screen Sample
Adafruit ST7735 Display¶
This is a library for the Adafruit 1.8” SPI display. This library works with the Adafruit 1.8” TFT Breakout w/SD card
- The 1.8” TFT shield
- —-> https://www.adafruit.com/product/802
- The 1.44” TFT breakout
- —-> https://www.adafruit.com/product/2088
- as well as Adafruit raw 1.8” TFT display
- —-> http://www.adafruit.com/products/618
Check out the links above for our tutorials and wiring diagrams. These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional). Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ST7735. Check that the Adafruit_ST7735 folder contains Adafruit_ST7735.cpp and Adafruit_ST7735.
Place the Adafruit_ST7735 library folder your
Also requires the Adafruit_GFX library for Arduino.
References¶
- Source Code (submodule, may be patched).
- Adafruit GFX Component
Used by¶
- ST7735 TFT Screen Sample
Adafruit Unified Sensor Driver¶
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
By reducing all data to a single sensors_event_t ‘type’ and settling on specific, standardised SI units for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
Unified Sensor Drivers¶
The following drivers are based on the Adafruit Unified Sensor Driver:
Accelerometers
Gyroscope
Light
Magnetometers
Barometric Pressure
Humidity & Temperature
Orientation
How Does it Work?¶
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to ‘abstract’ away the sensor details and values:
Sensor Types (sensors_type_t)
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
/** Sensor types */
typedef enum
{
SENSOR_TYPE_ACCELEROMETER = (1),
SENSOR_TYPE_MAGNETIC_FIELD = (2),
SENSOR_TYPE_ORIENTATION = (3),
SENSOR_TYPE_GYROSCOPE = (4),
SENSOR_TYPE_LIGHT = (5),
SENSOR_TYPE_PRESSURE = (6),
SENSOR_TYPE_PROXIMITY = (8),
SENSOR_TYPE_GRAVITY = (9),
SENSOR_TYPE_LINEAR_ACCELERATION = (10),
SENSOR_TYPE_ROTATION_VECTOR = (11),
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
SENSOR_TYPE_VOLTAGE = (15),
SENSOR_TYPE_CURRENT = (16),
SENSOR_TYPE_COLOR = (17)
} sensors_type_t;
Sensor Details (sensor_t)
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
{
char name[12];
int32_t version;
int32_t sensor_id;
int32_t type;
float max_value;
float min_value;
float resolution;
int32_t min_delay;
} sensor_t;
The individual fields are intended to be used as follows:
- name: The sensor name or ID, up to a maximum of twelve characters (ex. “MPL115A2”)
- version: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
- sensor_id: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
- type: The sensor type, based on sensors_type_t in sensors.h
- max_value: The maximum value that this sensor can return (in the appropriate SI unit)
- min_value: The minimum value that this sensor can return (in the appropriate SI unit)
- resolution: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
- min_delay: The minimum delay in microseconds between two sensor events, or ‘0’ if there is no constant sensor rate
Sensor Data/Events (sensors_event_t)
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
{
int32_t version;
int32_t sensor_id;
int32_t type;
int32_t reserved0;
int32_t timestamp;
union
{
float data[4];
sensors_vec_t acceleration;
sensors_vec_t magnetic;
sensors_vec_t orientation;
sensors_vec_t gyro;
float temperature;
float distance;
float light;
float pressure;
float relative_humidity;
float current;
float voltage;
sensors_color_t color;
};
} sensors_event_t;
It includes the following fields:
- version: Contain ‘sizeof(sensors_event_t)’ to identify which version of the API we’re using in case this changes in the future
- sensor_id: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor_id value in the corresponding sensor_t enum above!)
- type: the sensor type, based on sensors_type_t in sensors.h
- timestamp: time in milliseconds when the sensor value was read
- data[4]: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
Required Functions
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
bool getEvent(sensors_event_t*);
Calling this function will populate the supplied sensors_event_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
void getSensor(sensor_t*);
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
Standardised SI values for sensors_event_t
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors_event_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
- acceleration: values are in meter per second per second (m/s^2)
- magnetic: values are in micro-Tesla (uT)
- orientation: values are in degrees
- gyro: values are in rad/s
- temperature: values in degrees centigrade (Celsius)
- distance: values are in centimeters
- light: values are in SI lux units
- pressure: values are in hectopascal (hPa)
- relative_humidity: values are in percent
- current: values are in milliamps (mA)
- voltage: values are in volts (V)
- color: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
The Unified Driver Abstraction Layer in Practice¶
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
Every compliant sensor can now be read using a single, well-known ‘type’ (sensors_event_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor_t).
An example of reading the TSL2561 light sensor can be seen below:
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
...
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
/* Display the results (light is measured in lux) */
if (event.light)
{
Serial.print(event.light); Serial.println(" lux");
}
else
{
/* If event.light = 0 lux the sensor is probably saturated
and no reliable data could be generated! */
Serial.println("Sensor overload");
}
Similarly, we can get the basic technical capabilities of this sensor with the following code:
sensor_t sensor;
sensor_t sensor;
tsl.getSensor(&sensor);
/* Display the sensor details */
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
Serial.println("------------------------------------");
Serial.println("");
References¶
- Source Code (submodule, may be patched).
Used by¶
Adafruit VL53L0X Library .. image:: https://travis-ci.com/adafruit/Adafruit_VL53L0X.svg?branch=master
target: https://travis-ci.com/adafruit/Adafruit_VL53L0X alt: Build Status
This is a library for the Adafruit VL53L0X time-of-flight breakout:
Check out the links above for our tutorials and wiring diagrams. This chip uses I2C to communicate
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution
References¶
- Source Code (submodule, may be patched).
Used by¶
ArduCAM Library¶
Introduction¶
This is a opensource library for taking high resolution still images and short video clip on Arduino based platforms using ArduCAM’s camera moduels.
The camera breakout boards should work with ArduCAM shield before connecting to the Arduino boards.
ArduCAM mini series camera modules like Mini-2MP, Mini-5MP(Plus) can be connected to Arduino boards directly.
In addition to Arduino, the library can be ported to any hardware platforms as long as they have I2C and SPI interface based on this ArduCAM library.
Now Supported Cameras¶
- OV7660 0.3MP
- OV7670 0.3MP
- OV7675 0.3MP
- OV7725 0.3MP
- MT9V111 0.3MP
- MT9M112 1.3MP
- MT9M001 1.3MP
- MT9D111 2MP
- OV2640 2MP JPEG
- MT9T112 3MP
- OV3640 3MP
- OV5642 5MP JPEG
- OV5640 5MP JPEG
Supported MCU Platform¶
- Theoretically support all Arduino families
- Arduino UNO R3 (Tested)
- Arduino MEGA2560 R3 (Tested)
- Arduino Leonardo R3 (Tested)
- Arduino Nano (Tested)
- Arduino DUE (Tested)
- Arduino Genuion 101 (Tested)
- Raspberry Pi (Tested)
- ESP8266-12 (Tested) (http://www.arducam.com/downloads/ESP8266_UNO/package_ArduCAM_index.json)
- Feather M0 (Tested with OV5642)
Note: ArduCAM library for ESP8266 is maintained in another repository ESP8266 using a json board manager script.
Libraries Structure¶
The basic libraries are composed by two sub-libraries one is ArduCAM and the other is UTFT4ArduCAM_SPI. These two libraries should be copied right under the libraries of Arduino directory in order to be recognized by the Arduino IDE.
The ArduCAM library is the core library for ArduCAM shields. It contains supported image sensor drivers and user land API functions which issue capture or image data read commands .There is also an example directory inside the ArduCAM library which illustrates most
function of the ArduCAM shields. The existing examples are plug and play without need to write a single line of code.
The UTFT4ArduCAM_SPI library is modified version of UTFT which is written by Henning Karlsen. We ported it to support ArduCAM
shield with LCD screen. So the UTFT4ArduCAM_SPI library is only needed when using the ArduCAM-LF model.
How to use¶
The libraries should be configured before running any examples, or else you will get a compilation error message.
1. Edit memorysaver.h file¶
Open the memorysaver.h
file in the ArduCAM folder and enable the hardware platform and camera module which matches to your hardware by comment or
uncomment the macro definition in the file. For example, if you got a ArduCAM-Mini-2MP you
should uncomment the line #define OV2640_MINI_2MP
and comment all the other lines. And
if you got a ArduCAM-Shield-V2 and a OV5642 camera module, you should uncomment the line #define ARDUCAM_SHIELD_V2
and the line #define OV5642_CAM
then comment other lines.
2. Choose correct CS pin for your camera¶
Open one of the examples, wiring SPI and I2C interface especially CS pins to ArduCAM shield according to the examples. Hardware and software shuld be consistent to run the examples correctly.
3. Upload the examples¶
In the example folder there are seven sub directories for different ArduCAM models and the host application.
The Mini
folder is for ArduCAM-Mini-2MP and ArduCAM-Mini-5MP modules.
The Mini_5MP_Plus
folder is for ArduCAM-Mini-5MP-Plus (OV5640/OV5642) modules.
The RevC
folder is for ArduCAM-Shield-RevC or ArduCAM-Shield-RevC+ shields.
The Shield_V2
folder is for ArduCAM-Shield-V2 shield.
The host_app
folder is host capture and display application for all of ArduCAM modules.
The RaspberryPi
folder is examples used for Raspberry Pi platform, see more instruction.
The ESP8266
folder is for ArduCAM-ESP8266-UNO board examples for library compatibility. Please try repository ESP8266 using josn board manager script instead.
Selecting correct COM port and Arduino boards then upload the sketches.
Arducam MINI Camera Demo Tutorial for Arduino¶

Arducam Camera Shield V2 Demo Tutorial for Arduino¶

4. How To Connect Bluetooth Module¶
- Using this demo
https://github.com/ArduCAM/Arduino/blob/master/ArduCAM/examples/mini/ArduCAM_Mini_Video_Streaming_Bluetooth/ArduCAM_Mini_Video_Streaming_Bluetooth.ino

5. How to download the Host V2 ?¶
- For ArduCAM_Host_V2.0_Mac.app, please refer to this link: https://www.arducam.com/downloads/app/ArduCAM_Host_V2.0_Mac.app.zip
- For ArduCAM_Mini_V2.0_Linux_x86_64bit, Please refer to this link: https://www.arducam.com/downloads/app/ArduCAM_Mini_V2.0_Linux_x86_64bit.zip
References¶
ArduinoJson Version 5¶
Provided to support existing applications. New projects should use ArduinoJson Version 6.
Attention
Issue with JSON keys (applies to version 5 only)
According to the ArduinoJson docs it should take an internal copy of
char* strings, but it doesn’t! This can occur using the _F()
macro:
root[_F("offset")] = something;
This won’t work. Instead, use the F()
macro:
root[F("offset")] = something;
References¶
Used by¶
- Basic Web Skeleton (LTS) Sample
Submodule: ArduinoJson¶
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
Features¶
- JSON decoding (comments are supported)
- JSON encoding (with optional indentation)
- Elegant API, easy to use
- Fixed memory allocation (zero malloc)
- No data duplication (zero copy)
- Portable (written in C++98, can be used in any C++ project)
- Self-contained (no external dependency)
- Small footprint
- Input and output streams
- 100% code coverage
- Header-only library
- MIT License
- Comprehensive documentation
Compatibility¶
ArduinoJson works on the following hardware:
Arduino boards: Uno, Due, Mini, Micro, Yun…
Espressif chips: ESP8266, ESP32
WeMos boards: D1, D1 mini, …
RedBearLab boards: BLE Nano, BLE Mini, WiFi Micro, LOLIN32…
Teensy boards
Intel boards: Edison, Galileo…
Particle boards: Photon, Electron…
Texas Instruments boards: MSP430…
ArduinoJson compiles with zero warning on the following compilers, IDEs, and platforms:
Quickstart¶
Here is a program that parses a JSON document with ArduinoJson.
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(json);
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
See the tutorial on arduinojson.org
Here is a program that generates a JSON document with ArduinoJson:
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 1351824120;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
root.printTo(Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
See the tutorial on arduinojson.org
Documentation¶
The documentation is available on arduinojson.org, here are some shortcuts:
- The Examples show how to use the library in various situations.
- The API Reference contains the description of each class and function.
- The FAQ has the answer to virtually every question.
- The ArduinoJson Assistant writes programs for you!
Do you like this library? Please star this project on GitHub!
What? You don’t like it but you love it? We don’t take donations anymore, but we sell a book, so you can help and learn at the same time!
ArduinoJson Version 6¶
Current version is 6.12.0.
If you’re upgrading from version 5, some changes will be required to your code. See the Version 6 Migration Guide for details.
Some methods of JsonVariant
have been removed, replacements are:
asString()
-> as<char*>()
or as<const char*>
. Note that as<String>
produces a
serialized version, so you’ll get “null” instead of an empty/invalid result String.
asArray()
-> as<JsonArray>()
asObject()
-> as<JsonObject>()
There are also some useful helper functions available in the Json
namespace. See Libraries/ArduinoJson6/include/ArduinoJson.h
.
Sming definitions¶
JsonObjectStream
References¶
Used by¶
- Yeelight Library
- Basic Web Skeleton Sample
- HttpClient Instapush Sample
- AJAX Http Server Sample
- HttpServer Config Network Sample
- MeteoControl Sample
- RingTone Player Sample
Submodule: ArduinoJson¶
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
Features¶
- JSON decoding (comments are supported)
- JSON encoding (with optional indentation)
- MessagePack
- Elegant API, easy to use
- Fixed memory allocation (zero malloc)
- No data duplication (zero copy)
- Portable (written in C++98, can be used in any C++ project)
- Self-contained (no external dependency)
- Small footprint
- Input and output streams
- 100% code coverage
- Header-only library
- MIT License
- Comprehensive documentation
Compatibility¶
ArduinoJson works on the following hardware:
Arduino boards: Uno, Due, Mini, Micro, Yun…
Espressif chips: ESP8266, ESP32
WeMos boards: D1, D1 mini, …
RedBearLab boards: BLE Nano, BLE Mini, WiFi Micro, LOLIN32…
Teensy boards
Intel boards: Edison, Galileo…
Particle boards: Photon, Electron…
Texas Instruments boards: MSP430…
ArduinoJson compiles with zero warning on the following compilers, IDEs, and platforms:
Quickstart¶
Here is a program that parses a JSON document with ArduinoJson.
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
DynamicJsonDocument doc(1024);
deserializeJson(doc, json);
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
See the tutorial on arduinojson.org
Here is a program that generates a JSON document with ArduinoJson:
DynamicJsonDocument doc(1024);
doc["sensor"] = "gps";
doc["time"] = 1351824120;
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
serializeJson(doc, Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
See the tutorial on arduinojson.org
Documentation¶
The documentation is available on arduinojson.org, here are some shortcuts:
- The Examples show how to use the library in various situations.
- The API Reference contains the description of each class and function.
- The FAQ has the answer to virtually every question.
- The ArduinoJson Assistant writes programs for you!
Do you like this library? Please star this project on GitHub!
What? You don’t like it but you love it? We don’t take donations anymore, but we sell a book, so you can help and learn at the same time!
References¶
- Source Code (submodule, may be patched).
Used by¶
- TensorFlow_HelloWorld Sample
BH1750FVI Light Sensor¶
https://github.com/Genotronex/BH1750FVI_Master.git
Digital Light Sensor BH1750
- /*
This is a simple code to test BH1750FVI Light senosr
communicate using I2C Protocol
this library enable 2 slave device address
Main address 0x23
secondary address 0x5C
connect this sensor as following :
VCC >>> 3.3V
SDA >>> A4
SCL >>> A5
addr >> A3 “Optional and use address 0x23 “
Gnd >>>Gnd
please after download this library unzip and rename it to BH1750FVI and put it in the libraries folder in the arduino path , then restart Arduino IDE
Written By : Mohannad Rawashdeh
26/9/2013
for more information : http://www.instructables.com/id/BH1750-Digital-Light-Sensor/
contact me on my email
*/
References¶
Used by¶
- BH1750 Light Sensor Sample
BME280 Barometric Pressure Sensor¶
BME280 is Barometric Pressure Sensor.
- Datasheet for BME280:
- http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf
Copyright (C) 2012 Love Electronics Ltd (loveelectronics.com).
References¶
BMP180 Pressure/Temperature Sensor¶
Arduino library for BMP180 Bosch pressure/temperature sensor
Copyright (C) 2012 Love Electronics Ltd (loveelectronics.com)
References¶
Used by¶
- MeteoControl MQTT Sample
- BMP180 Pressure Sensor Sample
Bounce library for Arduino¶
Version 1.6
by Thomas Ouellet Fredericks with contributions from: Eric Lowry Jim Schimpf Tom Harkaway
contact: mrtoftrash@gmail.com
See the online documentation here: http://www.arduino.cc/playground/Code/Bounce
References¶
Capacitive Sensor Library¶
CapacitiveSensor lets you create sensors that can detect touch or proximity.
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
http://playground.arduino.cc/Main/CapacitiveSensor
http://www.youtube.com/watch?v=BHQPqQ_5ulc
CapacitiveSensor was originally written by Paul Badger and is now maintained by Paul Stoffregen.

References¶
Used by¶
- Basic Capsense Sample
DFPlayer - A Mini MP3 Player For Arduino¶
DFPlayer - A Mini MP3 Player For Arduino https://www.dfrobot.com/index.php?route=product/product&product_id=1121
This example shows the all the function of library for DFPlayer.
Created 2016-12-07 By Angelo qiao
GNU Lesser General Public License. See http://www.gnu.org/licenses/ for details. All above must be included in any redistribution
Notice and Trouble shooting
1.Connection and Diagram can be found here https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram 2.This code is tested on Arduino Uno, Leonardo, Mega boards.
References¶
- Source Code (submodule, may be patched).
Used by¶
- DFPlayer Mini Sample
DHT ESP Temperature/Humidity Sensors¶
An Arduino library for reading the DHT family of temperature and humidity sensors.
Forked from arduino-DHT
Original written by Mark Ruys, mark@paracas.nl.
Why did I clone this library instead of forking the original repo and push the changes?
When I searched through Github for DHT libraries, I found a lot of them, some of them offers additional functions, some of them only basic temperature and humidity values. I wanted to combine all interesting functions into one library. In addition, none of the DHT libraries I found were written to work without errors on the ESP32. For ESP32 (a multi core/ multi processing SOC) task switching must be disabled while reading data from the sensor.
Another problem I found is that many of the available libraries use the same naming (dht.h, dht.cpp), which easily leads to conflicts if different libraries are used for different platforms.
*According to users, the library works as well with DHT33 and DHT44 sensors. But as I do not own these sensors, I cannot test and confirm it. However, if you want to use this sensors, you can do so by using ``setup(pin, DHTesp::DHT22)`` and it should work. Please give me feedback in the issues if you successfull use these sensors. Thank you_
The library is tested as well on ESP8266 and should work on AVR boards as well.
Changes to the original library:¶
- 2017-12-12: Renamed DHT class to DHTesp and filenames from dht.* to DHTesp.* to avoid conflicts with other libraries - beegee-tokyo, beegee@giesecke.tk.
- 2017-12-12: Updated to work with ESP32 - beegee-tokyo, beegee@giesecke.tk.
- 2017-12-12: Added function computeHeatIndex. Reference: Adafruit DHT library.
- 2017-12-14: Added function computeDewPoint. Reference: idDHTLib.
- 2017-12-14: Added function getComfortRatio. Reference: libDHT. (References about Human Comfort invalid)
- 2017-12-15: Added function computePerception. Reference: WikiPedia Dew point==> Relationship to human comfort - beegee-tokyo, beegee@giesecke.tk.
- 2018-01-02: Added example for multiple sensors usage.
- 2018-01-03: Added function getTempAndHumidity which returns temperature and humidity in one call.
- 2018-01-03: Added retry in case the reading from the sensor fails with a timeout.
- 2018-01-08: Added ESP8266 (and probably AVR) compatibility.
- 2018-03-11: Updated DHT example
- 2018-06-19: Updated DHT example to distinguish between ESP8266 examples and ESP32 examples
- 2018-07-06: Fixed bug in ESP32 example
- 2018-07-17: Use correct field separator in keywords.txt
- 2019-03-07: Added computeAbsoluteHumidity which returns the absolute humidity in g/m³. Reference: How to convert relative humidity to absolute humidity kudos to Wurstnase
- 2019-03-22: Fixed auto detection problem
- 2019-07-31: Make getPin() public, Updated ESP8266 example
- 2019-10-01: Using noInterrupts() & interrupts() instead of cli and sei
- 2019-10-05: Reduce CPU usage and add decimal part for DHT11 (thanks to Swiftyhu)
- 2019-10-06: Back to working version by removing the last commit
Features¶
- Support for DHT11 and DHT22, AM2302, RHT03
- Auto detect sensor model
- Determine heat index
- Determine dewpoint
- Determine thermal comfort:
- Empiric comfort function based on comfort profiles(parametric lines)
- Multiple comfort profiles possible. Default based on http://epb.apogee.net/res/refcomf.asp (References invalid)
- Determine if it’s too cold, hot, humid, dry, based on current comfort profile
- More info at Determining Thermal Comfort Using a Humidity and Temperature Sensor
- Determine human perception based on humidity, temperature and dew point according to Horstmeyer, Steve (2006-08-15). Relative Humidity….Relative to What? The Dew Point Temperature…a better approach
Functions¶
**``void setup(uint8_t pin, DHT_MODEL_t model=AUTO_DETECT);``*_
- Call to initialize the interface, define the GPIO pin to which the sensor is connected and define the sensor type. Valid sensor types are:
- AUTO_DETECT Try to detect which sensor is connected (default if 2nd parameter is not used)
- DHT11
- DHT22
- AM2302 Packaged DHT22
- RHT03 Equivalent to DHT22
**``void resetTimer();``*_
- Reset last time the sensor was read
**``float getTemperature();``*_
- Get the temperature in degree Centigrade from the sensor
Either one of *getTemperature()
* or *getHumidity()
* or *getTempAndHumidity()
* initiates reading a value from the sensor if the last reading was older than the minimal refresh time of the sensor.
See example _`DHT_ESP32.ino`_ or _`DHT_Test.ino`_
**``float getHumidity();``*_
- Get the humidity from the sensor
Either one of *getTemperature()
* or *getHumidity()
* or *getTempAndHumidity()
* initiates reading a value from the sensor if the last reading was older than the minimal refresh time of the sensor.
See example _`DHT_ESP32.ino`_ or _`DHT_Test.ino`_
**``TempAndHumidity getTempAndHumidity();``*_
- Get the temperature and humidity from the sensor
Either one of *getTemperature()
* or *getHumidity()
* or *getTempAndHumidity()
* initiates reading a value from the sensor if the last reading was older than the minimal refresh time of the sensor.
Return value is a struct of type *TempAndHumidity
* with temperature and humidity as float values. See example _`DHT_Multi.ino`_
**``DHT_ERROR_t getStatus();``*_
- Get last error if reading from the sensor failed. Possible values are:
- ERROR_NONE no error occured
- ERROR_TIMEOUT timeout reading from the sensor
- ERROR_CHECKSUM checksum of received values doesn’t match
*`const char* getStatusString();`_
- Get last error as a char *
**``DHT_MODEL_t getModel()``*_
- Get detected (or defined) sensor type
**``int getMinimumSamplingPeriod();``*_
- Get minimmum possible sampling period. For DHT11 this is 1000ms, for other sensors it is 2000ms
**``int8_t getNumberOfDecimalsTemperature();``*_
- Get number of decimals in the temperature value. For DHT11 this is 0, for other sensors it is 1
**``int8_t getLowerBoundTemperature();``*_
- Get lower temperature range of the sensor. For DHT11 this is 0 degree Centigrade, for other sensors this is -40 degree Centrigrade
**``int8_t getUpperBoundTemperature();``*_
- Get upper temperature range of the sensor. For DHT11 this is 50 degree Centigrade, for other sensors this is 125 degree Centrigrade
**``int8_t getNumberOfDecimalsHumidity();``*_
- Get number of decimals in the humidity value. This is always 0.
**``int8_t getLowerBoundHumidity();``*_
- Get lower humidity range of the sensor. For DHT11 this is 20 percent, for other sensors this is 0 percent
**``int8_t getUpperBoundHumidity();``*_
- Get upper temperature range of the sensor. For DHT11 this is 90 percent, for other sensors this is 100 percent
**``static float toFahrenheit(float fromCelcius);``*_
- Convert Centrigrade value to Fahrenheit value
**``static float toCelsius(float fromFahrenheit) { return (fromFahrenheit - 32.0) / 1.8; };``*_
- Convert Fahrenheit value to Centigrade value
**``float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=false);``*_
- Compute the heat index. Default temperature is in Centrigrade.
**``float computeDewPoint(float temperature, float percentHumidity, bool isFahrenheit=false);``*_
- Compute the dew point. Default temperature is in Centrigrade.
**``float computeAbsoluteHumidity(float temperature, float percentHumidity, bool isFahrenheit=false);``*_
- Compute the absolute humidity in g/m³. Default temperature is in Centrigrade.
**``float getComfortRatio(ComfortState& destComfStatus, float temperature, float percentHumidity, bool isFahrenheit=false);``*_
- Compute the comfort ratio. Default temperature is in Centrigrade. Return values:
0 -> OK
1 -> Too Hot
2 -> Too cold
4 -> Too dry
8 -> Too humid
9 -> Hot and humid
5 -> Hot and dry
10 -> Cold and humid
6 -> Cold and dry
**``byte computePerception(float temperature, float percentHumidity, bool isFahrenheit=false);``*_
- Compute the human perception. Default temperature is in Centrigrade. Return values:
0 -> Dry
1 -> Very comfortable
2 -> Comfortable
3 -> Ok
4 -> Uncomfortable
5 -> Quite uncomfortable
6 -> Very uncomfortable
7 -> Severe uncomfortable
**``uint8_t getPin(void);``*_
- Returns the assigned GPIO for this instance. Usefull when connecting multiple sensors
Installation¶
In Arduino IDE open Sketch->Include Library->Manage Libraries then search for *DHT ESP:raw-html-m2r:`<br>`
In PlatformIO open PlatformIO Home, switch to libraries and search for ***DHT ESP32*. Or install the library in the terminal with **platformio lib install 2029
**_
For manual installation download the archive, unzip it and place the DHTesp folder into the library directory.
In Arduino IDE this is usually **``<arduinosketchfolder>/libraries/``*:raw-html-m2r:`<br>`
In PlatformIO this is usually **<user/.platformio/lib>
**_
References¶
- Source Code (submodule, may be patched).
Used by¶
- DHT22 Humidity Sensor Sample
- MeteoControl Sample
DS18S20 Temperature Sensor¶
This library provides access to DS18S20 temperature sensors connected via 1-Wire bus to a single GPIO The DS18S20 can run in several modes, with varying degrees of resolution. The highest resolution is 12-bit which provides 0.0625C resolution. 12-bit measurement takes 750ms. With 4 sensors connected, measurement will take 3s.
Created on: 01-09-2015 Author: flexiti and Anakod
References¶
- Source Code
- OneWire for Arduino Component
Used by¶
- DS1820 Temperature Sensor Sample
Arduino DS3232RTC Library v1.0¶
https://github.com/JChristensen/DS3232RTC
ReadMe file
Jack Christensen Mar 2013

Introduction¶
DS3232RTC is an Arduino library that supports the Maxim Integrated DS3232 and DS3231 Real-Time Clocks. This library is intended to be used with the Arduino Time library.
The DS3232RTC library is a drop-in replacement for the DS1307RTC.h library by Michael Margolis that is supplied with the Arduino Time library above. To change from using a DS1307 RTC to an DS323x RTC, it is only necessary to use #include <DS3232RTC.h>
instead of #include <DS1307RTC.h>
.
This library is **not** a drop-in replacement for PJRC’s newer version of the DS1307RTC library.
DS3232RTC also implements functions to support the additional features of the DS3232 and DS3231. The DS3231 has the same features as the DS3232 except: (1) Battery-backed SRAM, (2) Battery-backed 32kHz output (BB32kHz bit in Control/Status register 0x0F), and (3) Adjustable temperature sensor sample rate (CRATE1:0 bits in the Control/Status register).
“Arduino DS3232RTC Library” by Jack Christensen is licensed under CC BY-SA 4.0.
Installation¶
To use the DS3232RTC library:
- Go to https://github.com/JChristensen/DS3232RTC, click the Download ZIP button and save the ZIP file to a convenient location on your PC.
- Uncompress the downloaded file. This will result in a folder containing all the files for the library, that has a name that includes the branch name, usually DS3232RTC-master.
- Rename the folder to just DS3232RTC.
- Copy the renamed folder to the Arduino sketchbooklibraries folder.
Examples¶
The following example sketches are included with the DS3232RTC library:
- SetSerial: Set the RTC’s date and time from the Arduino serial monitor. Displays date, time and temperature.
- TimeRTC: Same as the example of the same name provided with the Time library, demonstrating the interchangeability of the DS3232RTC library with the DS1307RTC library.
- tiny3232_KnockBang: Demonstrates interfacing an ATtiny45/85 to a DS3231 or DS3232 RTC.
Usage notes¶
When using the DS3232RTC library, the user is responsible for ensuring that reads and writes do not exceed the device’s address space (0x00-0x12 for DS3231, 0x00-0xFF for DS3232); no bounds checking is done by the library.
Similar to the DS1307RTC library, the DS3232RTC library instantiates an RTC object; the user does not need to do this.
To use the DS3232RTC library, the Time and Wire libraries must also be included. For brevity, these includes are not repeated in the examples below:
#include <DS3232RTC.h> //http://github.com/JChristensen/DS3232RTC
#include <Time.h> //http://www.arduino.cc/playground/Code/Time
#include <Wire.h> //http://arduino.cc/en/Reference/Wire (included with Arduino IDE)
Enumerations¶
SQWAVE_FREQS_t¶
Symbolic names used with the squareWave() method (described below).
- SQWAVE_NONE
- SQWAVE_1_HZ
- SQWAVE_1024_HZ
- SQWAVE_4096_HZ
- SQWAVE_8192_HZ
ALARM_TYPES_t¶
Symbolic names used with the setAlarm() method (described below).
- ALM1_EVERY_SECOND – causes an alarm once per second.
- ALM1_MATCH_SECONDS – causes an alarm when the seconds match (i.e. once per minute).
- ALM1_MATCH_MINUTES – causes an alarm when the minutes and seconds match.
- ALM1_MATCH_HOURS – causes an alarm when the hours and minutes and seconds match.
- ALM1_MATCH_DATE – causes an alarm when the date of the month and hours and minutes and seconds match.
- ALM1_MATCH_DAY – causes an alarm when the day of the week and hours and minutes and seconds match.
- ALM2_EVERY_MINUTE – causes an alarm once per minute.
- ALM2_MATCH_MINUTES – causes an alarm when the minutes match (i.e. once per hour).
- ALM2_MATCH_HOURS – causes an alarm when the hours and minutes match.
- ALM2_MATCH_DATE – causes an alarm when the date of the month and hours and minutes match.
- ALM2_MATCH_DAY – causes an alarm when the day of the week and hours and minutes match.
Methods for setting and reading the time¶
get(void)¶
Reads the current date and time from the RTC and returns it as a time_t value. Returns zero if an I2C error occurs (RTC not present, etc.).
RTC.get();
None.
Current date and time (time_t)
time_t myTime;
myTime = RTC.get();
set(time_t t)¶
Sets the RTC date and time to the given time_t value. Clears the oscillator stop flag (OSF) bit in the control/status register. See the oscStopped()
function and also the DS323x datasheet for more information on the OSF bit.
RTC.set(t);
t: The date and time to set the RTC to (time_t)
I2C status (byte). Returns zero if successful.
//this example first sets the system time (maintained by the Time library) to
//a hard-coded date and time, and then sets the RTC from the system time.
//the setTime() function is part of the Time library.
setTime(23, 31, 30, 13, 2, 2009); //set the system time to 23h31m30s on 13Feb2009
RTC.set(now()); //set the RTC from the system time
read(tmElements_t &tm)¶
Reads the current date and time from the RTC and returns it as a tmElements_t structure. See the Arduino Time library for details on the tmElements_t structure.
RTC.read(tm);
tm: Address of a tmElements_t structure to which the date and time are returned.
I2C status (byte). Returns zero if successful. The date and time read from the RTC are returned to the tm parameter.
tmElements_t tm;
RTC.read(tm);
Serial.print(tm.Hour, DEC);
Serial.print(':');
Serial.print(tm.Minute,DEC);
Serial.print(':');
Serial.println(tm.Second,DEC);
write(tmElements_t &tm)¶
Sets the RTC to the date and time given by a tmElements_t structure. Clears the oscillator stop flag (OSF) bit in the control/status register. See the oscStopped()
function and also the DS323x datasheet for more information on the OSF bit.
RTC.write(tm);
tm: Address of a tmElements_t structure used to set the date and time.
I2C status (byte). Returns zero if successful.
tmElements_t tm;
tm.Hour = 23; //set the tm structure to 23h31m30s on 13Feb2009
tm.Minute = 31;
tm.Minute = 30;
tm.Day = 13;
tm.Month = 2;
tm.Year = 2009 - 1970; //tmElements_t.Year is the offset from 1970
RTC.write(tm); //set the RTC from the tm structure
Methods for reading and writing RTC registers or static RAM (SRAM) for the DS3232¶
The DS3232RTC.h file defines symbolic names for the timekeeping, alarm, status and control registers. These can be used for the addr argument in the functions below.
writeRTC(byte addr, byte *values, byte nBytes)¶
Write one or more bytes to RTC memory.
RTC.writeRTC(addr, values, nbytes);
addr: First SRAM address to write (byte). The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library.
values: An array of values to write (*byte)
nBytes: Number of bytes to write (byte). Must be between 1 and 31 (Wire library limitation) but is not checked by the library.
I2C status (byte). Returns zero if successful.
//write 1, 2, ..., 8 to the first eight DS3232 SRAM locations
byte buf[8] = {1, 2, 3, 4, 5, 6, 7, 8};
RTC.sramWrite(0x14, buf, 8);
writeRTC(byte addr, byte value)¶
Write a single byte to RTC memory.
RTC.writeRTC(addr, value);
addr: SRAM address to write (byte). The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library. value: Value to write (byte)
I2C status (byte). Returns zero if successful.
RTC.writeRTC(3, 14); //write the value 14 to SRAM address 3
readRTC(byte addr, byte *values, byte nBytes)¶
Read one or more bytes from RTC RAM.
RTC.readRTC(addr, values, nbytes);
addr: First SRAM address to read (byte). The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library.
values: An array to receive the values read (*byte)
nBytes: Number of bytes to read (byte). Must be between 1 and 32 (Wire library limitation) but is not checked by the library.
I2C status (byte). Returns zero if successful.
//read the last eight locations of SRAM into buf
byte buf[8];
RTC.sramRead(248, buf, 8);
readRTC(byte addr)¶
Reads a single byte from RTC RAM.
RTC.readRTC(addr);
addr: SRAM address to read (byte). The valid address range is 0x00-0x12 for DS3231, 0x00-0xFF for DS3232. The general-purpose SRAM for the DS3232 begins at address 0x14. Address is not checked for validity by the library.
Value read from the RTC (byte)
byte val;
val = RTC.readRTC(3); //read the value from SRAM location 3
Alarm methods¶
The DS3232 and DS3231 have two alarms. Alarm1 can be set to seconds precision; Alarm2 can only be set to minutes precision.
setAlarm(ALARM_TYPES_t alarmType, byte seconds, byte minutes, byte hours, byte daydate)¶
Set an alarm time. Sets the alarm registers only. To cause the INT pin to be asserted on alarm match, use alarmInterrupt(). This method can set either Alarm 1 or Alarm 2, depending on the value of alarmType (use the ALARM_TYPES_t enumeration above). When setting Alarm 2, the seconds value must be supplied but is ignored, recommend using zero. (Alarm 2 has no seconds register.)
RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate);
alarmType: A value from the ALARM_TYPES_t enumeration, above. (ALARM_TYPES_t)
seconds: The seconds value to set the alarm to. (byte)
minutes: The minutes value to set the alarm to. (byte)
hours: The hours value to set the alarm to. (byte)
dayOrDate: The day of the week or the date of the month. For day of the week, use a value from the Time library timeDayOfWeek_t enumeration, i.e. dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday. (byte)
None.
//Set Alarm1 for 12:34:56 on Sunday
RTC.setAlarm(ALM1_MATCH_DAY, 56, 34, 12, dowSunday);
setAlarm(ALARM_TYPES_t alarmType, byte minutes, byte hours, byte daydate)¶
Set an alarm time. Sets the alarm registers only. To cause the INT pin to be asserted on alarm match, use alarmInterrupt(). This method can set either Alarm 1 or Alarm 2, depending on the value of alarmType (use the ALARM_TYPES_t enumeration above). However, when using this method to set Alarm 1, the seconds value is set to zero. (Alarm 2 has no seconds register.)
RTC.setAlarm(alarmType, minutes, hours, dayOrDate);
alarmType: A value from the ALARM_TYPES_t enumeration, above. (ALARM_TYPES_t)
minutes: The minutes value to set the alarm to. (byte)
hours: The hours value to set the alarm to. (byte)
dayOrDate: The day of the week or the date of the month. For day of the week, use a value from the Time library timeDayOfWeek_t enumeration, i.e. dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday. (byte)
None.
//Set Alarm2 for 12:34 on the 4th day of the month
RTC.setAlarm(ALM1_MATCH_DATE, 34, 12, 4);
alarmInterrupt(byte alarmNumber, boolean alarmEnabled)¶
Enable or disable an alarm “interrupt”. Note that this “interrupt” causes the RTC’s INT pin to be asserted. To use this signal as an actual interrupt to a microcontroller, it will need to be connected properly and programmed in the application firmware. on the RTC.
RTC.alarmInterrupt(alarmNumber, enable);
alarmNumber: The number of the alarm to enable or disable, ALARM_1 or ALARM_2 (byte)
alarmEnabled: true or false (boolean)
None.
RTC.alarmInterrupt(ALARM_1, true); //assert the INT pin when Alarm1 occurs.
RTC.alarmInterrupt(ALARM_2, false); //disable Alarm2
alarm(byte alarmNumber)¶
Tests whether an alarm has been triggered. If the alarm was triggered, returns true and resets the alarm flag in the RTC, else returns false.
RTC.alarm(alarmNumber);
alarmNumber: The number of the alarm to test, ALARM_1 or ALARM_2 (byte)
Description (type)
if ( RTC.alarm(ALARM_1) ) { //has Alarm1 triggered?
//yes, act on the alarm
}
else {
//no alarm
}
Other methods¶
temperature(void)¶
Returns the RTC temperature.
RTC.temperature();
None.
RTC temperature as degrees Celsius times four. (int)
int t = RTC.temperature();
float celsius = t / 4.0;
float fahrenheit = celsius * 9.0 / 5.0 + 32.0;
squareWave(SQWAVE_FREQS_t freq)¶
Enables or disables the square wave output.
RTC.squareWave(freq);
freq: a value from the SQWAVE_FREQS_t enumeration above. (SQWAVE_FREQS_t)
None.
RTC.squareWave(SQWAVE_1_HZ); //1 Hz square wave
RTC.squareWave(SQWAVE_NONE); //no square wave
oscStopped(bool clearOSF)¶
Returns the value of the oscillator stop flag (OSF) bit in the control/status register which indicates that the oscillator is or was stopped, and that the timekeeping data may be invalid. Optionally clears the OSF bit depending on the argument passed. If the clearOSF
argument is omitted, the OSF bit is cleared by default. Calls to set()
and write()
also clear the OSF bit.
RTC.oscStopped(clearOSF);
clearOSF: an optional true or false value to indicate whether the OSF bit should be cleared (reset). If not supplied, a default value of true is used, resetting the OSF bit. (bool)
True or false (bool)
if ( RTC.oscStopped(false) ) { //check the oscillator
//may be trouble
}
else {
//all is well
}
References¶
Used by¶
- DS3232RTC NTP Setter Sample
HMC5883L Compass¶
https://github.com/jrowberg/i2cdevlib.git
References¶
- Source Code
- I2C Device Class Component
Used by¶
- HMC5883L Compass Sample
I2C Device Class¶
This is a generic class which abstracts bit and byte I2C R/W functions. It is part of The I2C Device Library.
There are examples in many of the classes that demonstrate basic usage patterns. The I2Cdev class is built to be used statically, reducing the memory requirement if you have multiple I2C devices in your project. Only one instance of the I2Cdev class is required.
https://github.com/jrowberg/i2cdevlib.git
References¶
Used by¶
- HMC5883L Compass Library
- HMC5883L Compass Sample
IRremoteESP8266 Library¶
This library enables you to send *and* receive infra-red signals on an ESP8266 or an ESP32 using the Arduino framework using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* demodulators etc.
v2.7.7 Now Available¶
Version 2.7.7 of the library is now available. You can view the Release Notes for all the significant changes.
Upgrading from pre-v2.0¶
Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our Upgrade to v2.0 page.
Upgrading from pre-v2.5¶
The library has changed from using constants declared as #define
to
const with
the appropriate naming per the
C++ style guide.
This may potentially cause old programs to not compile.
The most likely externally used #define
s have been aliased for limited
backward compatibility for projects using the old style. Going forward, only the
new kConstantName
style will be supported for new protocol additions.
In the unlikely case, it does break your code, then you may have been referencing
something you likely should not have. You should be able to quickly determine
the new name from the old. e.g. CONSTANT_NAME
to kConstantName
.
Use common sense or examining the library’s code if this does affect code.
Troubleshooting¶
Before reporting an issue or asking for help, please try to follow our Troubleshooting Guide first.
Frequently Asked Questions¶
Some common answers to common questions and problems are on our F.A.Q. wiki page.
Library API Documentation¶
This library uses Doxygen to automatically document the library’s API. You can find it here.
Installation¶
- Click the “Sketch” -> “Include Library” -> “Manage Libraries…” Menu items.
- Enter
IRremoteESP8266
into the “Filter your search…” top right search box. - Click on the IRremoteESP8266 result of the search.
- Select the version you wish to install and click “Install”.
- Click on “Clone or Download” button, then “`Download ZIP <https://github.com/crankyoldgit/IRremoteESP8266/archive->master.zip>`_” on the page.
- Extract the contents of the downloaded zip file.
- Rename the extracted folder to “IRremoteESP8266”.
- Move this folder to your libraries directory. (under windows:
C:\Users\YOURNAME\Documents\Arduino\libraries\
) - Restart your Arduino IDE.
- Check out the examples.
cd ~/Arduino/libraries
git clone https://github.com/crankyoldgit/IRremoteESP8266.git
cd ~/Arduino/libraries/IRremoteESP8266 && git pull
Contributing¶
If you want to contribute to this project, consider:
- Reporting bugs and errors
- Ask for enhancements
- Improve our documentation
- Creating issues and pull requests
- Tell other people about this library
Library History¶
This library was originally based on Ken Shirriff’s work (https://github.com/shirriff/Arduino-IRremote/)
Mark Szabo has updated the IRsend class to work on ESP8266 and Sebastien Warin the receiving & decoding part (IRrecv class).
As of v2.0, the library was almost entirely re-written with the ESP8266’s resources in mind.
References¶
- Source Code (submodule, may be patched).
- Embedded RingBufCPP Component
Used by¶
- IR Library Sample
Nextion Serial Displays¶
Introduction¶
Nextion Arduino library provides an easy-to-use way to manipulate Nextion serial displays. Users can use the libarry freely, either in commerical projects or open-source prjects, without any additional condiitons.
To get your Nextion display, please visit iMall.
To discuss the project? Request new features? Report a BUG? please visit the Forums
Download Source Code¶
Latest version is unstable and a mass of change may be applied in a short time without any notification for users. Commonly, it is for developers of this library.
Release version is recommanded for you, unless you are one of developers of this library.
Release notes is at https://github.com/itead/ITEADLIB_Arduino_Nextion/blob/master/release_notes.md.
Latest(unstable)¶
Latest source code(master branch) can be downloaded: https://github.com/itead/ITEADLIB_Arduino_Nextion/archive/master.zip.
You can also clone it via git:
git clone https://github.com/itead/ITEADLIB_Arduino_Nextion
Releases(stable)¶
- https://github.com/itead/ITEADLIB_Arduino_Nextion/archive/v0.7.0.zip
- https://github.com/itead/ITEADLIB_Arduino_Nextion/archive/v0.7.0.tar.gz
All releases can be available from: https://github.com/itead/ITEADLIB_Arduino_Nextion/releases.
Documentation¶
Offline Documentation’s entry doc/Documentation/index.html
shiped
with source code can be open in your browser such as Chrome, Firefox or
any one you like.
Suppported Mainboards¶
All boards, which has one or more hardware serial, can be supported.
For example:
- Iteaduino MEGA2560
- Iteaduino UNO
- Arduino MEGA2560
- Arduino UNO
Configuration¶
In configuration file NexConfig.h, you can find two macros below:
- dbSerial: Debug Serial (baudrate:9600), needed by beginners for debug your nextion applications or sketches. If your complete your work, it will be a wise choice to disable Debug Serial.
- nexSerial: Nextion Serial, the bridge of Nextion and your mainboard.
Note: the default configuration is for MEGA2560.
Redirect dbSerial and nexSerial¶
If you want to change the default serial to debug or communicate with Nextion , you need to modify the line in configuration file:
#define dbSerial Serial ---> #define dbSerial Serialxxx
#define nexSerial Serial2 ---> #define nexSeria Serialxxx
Disable Debug Serial¶
If you want to disable the debug information,you need to modify the line in configuration file:
#define DEBUG_SERIAL_ENABLE ---> //#define DEBUG_SERIAL_ENABLE
UNO-like Mainboards¶
If your board has only one hardware serial, such as UNO, you should
disable dbSerial and redirect nexSerial to Serial(Refer to
section:Serial configuration
).
License¶
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
References¶
- Source Code (submodule, may be patched).
Used by¶
- Nextion Button Sample
Liquid Crystal¶
Introduction¶

Welcome to the LCD Library for Arduino and Chipkit. It is a derivate of the original LiquidCrystal Library as sourced in the Arduino SDK. It has been developed to be compatible with the current LiquidCrystal library, its performance is almost 5 times faster and fully extendable if need be.
It supports most Hitachi HD44780
based LCDs, or compatible, connected to any project using: 4, 8
wire parallel interface, I2C IO port expander (native I2C and bit bang) and Shift Regiter.
It currently supports 4 types of connections:
- 4 bit parallel LCD interface
- 8 bit parallel LCD interface
- I2C IO bus expansion board with the PCF8574* I2C IO expander ASIC such as I2C LCD extra IO.
- ShiftRegister adaptor board as described Shift Register project home or in the HW configuration described below, 2 and 3 wire configurations supported.
- ShiftRegister 3 wire latch adaptor board as described ShiftRegister 3 Wire Home
- Support for 1 wire shift register ShiftRegister 1 Wire
- I2C bus expansion using general purpose IO lines.
Contributors¶
The library has had the invaluable contribution of:
- piccaso - Florian Fida - Flo, thanks for testing and improving the SR library, initial version of the 1 wire interface and speed improvements.
- Perry - bperrybap@opensource.billsworld.billandterrie.com, with his thoughtful contribution, speed improvements and development support for the SR2W library.
- Adrian Piccioli, with his contribution to the i2c GPIO support.
- todbot Tod E. Kurt for the softwarei2cmaster library.
- felias-fogg - Bernhard for the softwarei2cmaster fast
- Writing tests
- Code review
- Help out with bug fixing
- Setup a project logo
- Write new drivers to support more LCDs.
Who do I talk to?¶
- Repo owner or admin
- For SoftI2CMaster latest versions, updates and support, please refer to SoftI2CMaster
References¶
Used by¶
- Liquid Crystal 44780 Sample
- MeteoControl Sample
MCP23008 Port Expander¶
Library for communicating with MCP23008 8-bit port expander. Created by Garrett Blanton January, 24, 2014. Released into the public domain.
References¶
MCP23017 I2C Port Expander¶
https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library.git
This is a library for the MCP23017 I2c Port Expander
These chips use I2C to communicate, 2 pins required to interface
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above must be included in any redistribution
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_MCP23017. Check that the Adafruit_MCP23017 folder contains Adafruit_MCP23017.cpp and Adafruit_MCP23017.h
Place the Adafruit_MCP23017 library folder your
References¶
Used by¶
- MCP23017 I2C Port Expander Sample
MCP23S17 SPI Port Expander¶
https://github.com/n0mjs710/MCP23S17.git
Arduino Driver for Microchip MCP23S17
MCP23S17 Class for Arduino
Introduction:
This class is written to simplify using the Microchip MCP23S17 general purpose I/O expander IC in the Arduino environment. Some understanding of the MCP23S17 is required, so if you are not familiar with it, download the datasheet for it and have a look. The rest of this description will assume a basic understanding of the chip.
Implementation:
The goal of this implementation is to provide a software interface that mimics the existing Arduino I/O functions:
- pinMode(pin, mode)
- digitalWrite(pin, value)
- digitalRead(pin)
The class does include several more methods that can be used to simplify configuration in the same “Arduino-ish” way, methods for writing/reading 8-bit registers (configuration and I/O ports) at once, as well as writing/reading consecutive registers (allowing all 16 bits to be read or written with one method call). The interrupt features of the chip are not directly supported with method for specifically configuring them, however, the byte and word read/write methods may be used to configure and use the interrupt features. These features can get somewhat complicated, and any user prepared to use them will likely prefer the more generic methods for controlling them.
Upon initialization of an MCP23S17 as an object, ALL MCP23S17s on the SPI bus (sharing the same slave select) will be placed into hardware addressing mode. This allows up to 8 MCP23S17s to be used with a single slave select.
**Methods:**
MCP()
Description
Instantiate an MCP23S17 device as an object.
Syntax
MCP object_name(address, slave_select)
Parameters
object_name: any arbitrary name given to create the object
address: address (0-7) of the device configured with address (pins A0, A1, A2)
slave_select: a valid *Arduino* pin number.
Returns
none
Example
MCP onechip(1, 10); // create an object at address 1 called "onechip", using pin 10 as slave select
MCP twochip(2, 10); // create an object at address 2 called "twochip", using pin 10 as slave select
pinMode()
Description
Configure pin(s) as either input or output on the selected object (device specified by an address)
Syntax
object.name.pinMode(pin, mode);
or
object.name.pinMode(mode);
Parameters
object_name: the name given when this object was created
pin: the pin number (1-16) on which to set as input or output
mode: if a pin is specified, either a "HIGH" (1) for input (default) or a "LOW" (0) for output. If a pin is not specified, mode should be a word indicating the mode of each of the 16 I/O pins on the chip.
Returns
none
Example
void setup() {
onechip.pinMode(4, HIGH); // sets pin 4 as an input
onechip.pinMode(16, LOW); // sets pin 16 as an output
twochip.pinMode(0B0000111100001111); // sets pins 1-4 and 9-12 as input, 5-8 and 13-16 as output
}
pullupMode()
Description
Configure the weak pull-up resistors on pins defined as inputs
This has no effect on pins that are configured as outputs.
Syntax
object_name.pullupMode(pin, mode);
or
object_name.pullupMode(mode);
Parameters
object_name: the name given when this object was created
pin: the pin number (1-16) on which to enable or disable the internal weak pull-up resistor
mode: if a pin is specified, either "HIGH" (1) to enable or "LOW" (0) to disable (default) the weak pull-up resistor on the specified pin. If a pin is not specified, mode should be a word indicating the pull-up mode of each of the 16 pins on the chip. Configuring pull-up has no effect on pins while they are configured as output.
Returns
none
Example
void setup() {
onechip.pullupMode(4, HIGH); // enable the pull-up on pin 4
twochip.pullupMode(0B0000111100000000); // enable the pull-ups on pins 9-12
}
inputInvert()
Description
Configure inversion on pins configured as inputs.
This will cause an inverted input pin to read as “LOW” (0) when it is actually in a high state, or as “HIGH” (1) when it is actually in a low state. This has no effect on pins that are configured as outputs.
Syntax
object_name.inputInvert(pin, inversion);
or
object_name.inputInvert(inversion);
Parameters
object_name: the name given when this object was created
pin: the pin number (1-16) on which to set or clear inversion
inversion: if a pin is specified, either "HIGH" (1) is specified to enable, or "LOW" (0) to disable (default) inversion on the specified pin. If a pin is not specified, mode should be a word indicating the inversion state of each of the 16 pins on the chip. Configuring inversion has no effect on pins while they are configured as output.
Returns
none
Example
void setup() {
onechip.inputInvert(4, LOW); // disable inversion on pin 4
twochip.inputInvert(0B0000000000001111); // enable inversion on pins 1-4
}
digitalWrite()
Description
Write a “HIGH” or “LOW” value to a digital I/O pin(s)
Syntax
object_name.digitalWrite(pin, value);
or
object_name.digitalWrite(value);
Parameters
object_name: the name given when this object was created
pin: the pin number (1-16) who's value will be set
value: if a pin is specified, either a "HIGH" (1) or a "LOW" (0) value may be set on the specified pin. If a pin is not specified, value should be a word indicating the output state of all 16 pins on the device. Writing pins configured as inputs has no effect.
Returns
none
Example
void loop() {
onechip.digitalWrite(16, HIGH); // set pin 16 to "HIGH"
twochip.digitalWrite(0B1100000000110000); // Set 5, 6, 15 & 16 to high, 7,8, 13 & 14 to low - inputs ignored
}
digitalRead()
Description
Reads the value of input pin(s), either “HIGH” (“1”) or “LOW” (“0)
Syntax
object_name.digitalRead(pin);
or
object_name.digitalRead();
Parameters
object_name: the name given when this object was created
pin: the pin number (1-16) who's value will be read. If no pin number is supplied, a word will be read containing the input state of all pins. The values for pins configured as output should be disregarded if the "word-mode" version is used.
Returns
"HIGH" (1) or "LOW" (0) if a pin is supplied. a word (16 bits) is returned if no pin argument is given
Example
void loop() {
int onevalue;
int twovalue;
onevalue = onechip.digitalRead(4); // assigns the value of pin4 to onevalue
twovalue = twochip.digitalRead(); // assigns the value of all 16 I/O pins to twovalue
}
wordWrite()
Description:
This is an advanced method to write a register pair in the MCP23S17. This class operates the MCP23S17 in “BANK=0” mode. The intention is that a registers for both ports may be written by supplying a single word as an argument. The low byte is written to the register address supplied, and the high byte to the next higher register address.
Syntax”
object_name.wordWrite(base register, value);
Parameters:
object_name: the name given when this object was created
base register: the beginning register address to write, for example, if 0x02 is given, the low byte of "value" will be written to 0x02 and the high byte of "value" to the register at 0x03
value: a word (unsigned int) that will be broken into two bytes and written to two consecutive registers, starting with the "base register" address
Returns:
none
Example
void loop() {
onechip.wordWrite(0x12, 0xFF00); // Set GPIOA to 0x00 and GPIOB to OxFF
}
byteWrite()
Description:
This is an advanced method to write any single register in the MCP23S17.
Syntax:
object_name.byteWrite(register, value);
Parameters:
object_name: the name given when this object was created
register: the register address to write
value: a byte (unsigned char) that will be written to the specified registers
Returns:
none
Example:
void loop() {
twochip.byteWrite(0x13, 0xF0); // Set GPIOB (portB) to 0xF0 (0B11110000)
}
byteRead()
Description:
This is an advanced method to read any single register in the MCP23S17.
Syntax:
object_name.byteRead(register);
Parameters:
object_name: the name given when this object was created
register: the register address to be read
Returns:
unsigned char (uint8_t)
Example:
void loop() {
int twovalue;
twovalue = twochip.byteRead(0x12); // Read GPIOA (portA)
}
Full Example:
MCP onechip(1, 10); // create an object at address 1 called "onechip", using pin 10 as slave select
MCP twochip(2, 10); // create an object at address 2 called "twochip", using pin 10 as slave select
void setup() {
onechip.pinMode(4, HIGH); // sets pin 4 as an input
onechip.pinMode(16, LOW); // sets pin 16 as an output
twochip.pinMode(0B0000111100001111); // sets pins 1-4 and 9-12 as input, 5-8 and 13-16 as output
onechip.pullupMode(4, HIGH); // enable the pull-up on pin 4
twochip.pullupMode(0B0000111100000000); // enable the pull-ups on pins 9-1
onechip.inputInvert(4, LOW); // disable inversion on pin 4
twochip.inputInvert(0B0000000000001111); // enable inversion on pins 1-4
}
void loop() {
int onevalue;
int twovalue;
onechip.digitalWrite(16, HIGH); // set pin 16 to "HIGH"
twochip.digitalWrite(0B1100000000110000); // Set 5, 6, 15 & 16 to high, 7,8, 13 & 14 to low - inputs ignored
onevalue = onechip.digitalRead(4); // assigns the value of pin4 to onevalue
twovalue = twochip.digitalRead(); // assigns the value of all 16 I/O pins to twovalue
/* These are for context only - use them only if you really know what you're doing
onechip.wordWrite(0x12, 0xFF00); // Set GPIOA to 0x00 and GPIOB to OxFF
twochip.byteWrite(0x13, 0xF0); // Set GPIOB (portB) to 0xF0 (0B11110000)
twovalue = twochip.byteRead(0x12); // Read GPIOA (portA)
*/
}
References¶
Used by¶
- MCP23S17 SPI Port Expander Sample
MCP_CAN Library for Arduino¶
MCP_CAN library v1.5 This library is compatible with any shield or board that uses the MCP2515 or MCP25625 CAN protocol controller.
This version supports setting the ID filter mode of the protocol controller, the BAUD rate with clock speed with the begin() function. Baudrates 5k, 10k, 20k, 50k, 100k, 125k, 250k, 500k, & 1000k using 16MHz clock on the MCP2515 are confirmed to work using a Peak-System PCAN-USB dongle as a reference. Baudrates for 8MHz and 20MHz crystals are yet to be confirmed but were calculated appropiately.
The readMsgBuf() functions bring in the message ID. The getCanId() function is obsolete and no longer exists, don’t use it.
The readMsgBuf(*ID, *DLC, *DATA) function will return the ID type (extended or standard) and it will bring back the remote request status bit.
If the ID AND 0x80000000 EQUALS 0x80000000, the ID is of the Extended type, otherwise it is standard.
If the ID AND 0x40000000 EQUALS 0x40000000, the message is a remote request.
The readMsgBuf(*ID, *EXT, *DLC, *DATA) function will return the ID unaltered and doesn’t inform us of a remote request.
If EXT is true, the ID is extended.
The sendMsgBuf(ID, DLC, DATA) function can send extended or standard IDs.
To mark an ID as extended, OR the ID with 0x80000000.
To send a remote request, OR the ID with 0x40000000.
The sendMsgBuf(ID, EXT, DLC, DATA) has not changed other than fixing return values.
Using the setMode() function the sketch can now put the protocol controller into sleep, loop-back, or listen-only modes as well as normal operation. Right now the code defaults to loop-back mode after the begin() function runs. I have found this to increase the stability of filtering when the controller is initialized while connected to an active bus.
User can enable and disable (default) One-Shot transmission mode from the sketch using enOneShotTX() or disOneShotTX() respectively.
Installation¶
Copy this into the “[…/MySketches/]libraries/” folder and restart the Arduino editor.
NOTE: If an older version of the library exists (e.g. CAN_BUS_Shield) be sure to remove it from the libraries folder or replace the files with those in this library to avoid conflicts.
Help and Support¶
This is primarily for non-bug related issues: Please start a new thread in an appropriate area at Seeedstudio forums or Arduino.cc forums and then send me (coryjfowler) a link through the PM system, my user name is the same as it is here. I will receive an email about the PM and generally get to it with-in a week or less. Keep in mind, I do this in my spare time.
Happy Coding!
References¶
- Source Code (submodule, may be patched).
MFRC522 RFID Module¶
Note
This is a copy of the readme from 12/6/19, however the code in this library was last updated 23/3/2017.
Arduino library for MFRC522 and other RFID RC522 based modules.
Read and write different types of Radio-Frequency IDentification (RFID) cards on your Arduino using a RC522 based reader connected via the Serial Peripheral Interface (SPI) interface.
Development¶
The development by owner miguelbalboa has ended.
Feature status: complete freeze; no function or API change
Code status: paritial freeze; just fixes/typos or documentation updates; no extentions for other boards; no new examples
Maintenance status: sporadically
Why no further development? This library has a long history and is used in many projects. This projects often do not document what version they use. Commiting changes maybe brake those old project and lead to bad experience (for beginners) and support request. For those reasons the library is in freeze mode. You can still commit typo, documentation or bug fixes.
Before buy¶
Please notice that there are many sellers (ebay, aliexpress, ..) who sell mfrc522 boards. The quality of these boards are extremely different. Some are soldered with wrong/low quality capacitors or fake/defect mfrc522.
Please consider buying several devices from different suppliers. So the chance of getting a working device is higher.
If you got a bad board and you can tell us how to detect those boards (silk, chip description, ..), please share your knowledge.
What works and not?¶
- Works
- Communication (Crypto1) with MIFARE Classic (1k, 4k, Mini).
- Communication (Crypto1) with MIFARE Classic compatible PICCs.
- Firmware self check of MFRC522.
- Set the UID, write to sector 0, and unbrick Chinese UID changeable MIFARE cards.
- Manage the SPI chip select pin (aka SS, SDA)
- Works partially
- Communication with MIFARE Ultralight.
- Other PICCs (Ntag216).
- More than 2 modules, require a multiplexer #191.
- Doesn’t work
- MIFARE DESFire, MIFARE DESFire EV1/EV2, not supported by software.
- Communication with 3DES or AES, not supported by software.
- Peer-to-peer (ISO/IEC 18092), not supported by hardware.
- Communication with smart phone, not supported by hardware.
- Card emulation, not supported by hardware.
- Use of IRQ pin. But there is a proof-of-concept example.
- With Arduino Yun see #111, not supported by software.
- With Intel Galileo (Gen2) see #310, not supported by software.
- Power reduction modes #269, not supported by software.
- I2C instead of SPI #240, not supported by software.
- UART instead of SPI #281, not supported by software.
- Need more?
- If software: code it and make a pull request.
- If hardware: buy a more expensive like PN532 (supports NFC and many more, but costs about $15 and not usable with this library).
Compatible IDE¶
This library works with Arduino IDE 1.6, older versions are not supported and will cause compiler errors. The built-in library manager is supported.
If you use your own compiler, you have to enable c++11
-support.
Compatible boards¶
!!!Only for advanced users!!!
This library is compatible with the Teensy and ESP8266 if you use the board plugin of the Arduino IDE. Not all examples are available for every board. You also have to change pins. See pin layout.
Some user made some patches/suggestions/ports for other boards:
- Linux: https://github.com/miguelbalboa/rfid/pull/216
- chipKIT: https://github.com/miguelbalboa/rfid/pull/230
- ESP8266 (native): https://github.com/miguelbalboa/rfid/pull/235
- LPCOPen (in C): https://github.com/miguelbalboa/rfid/pull/258
Note that the main target/support of library is still Arduino.
Support/issue¶
- First checkout what works and not and troubleshooting .
- It seems to be a hardware issue or you need support to program your project?
- Please ask in the official Arduino forum, where you would get a much faster answer than on Github.
- It seems to be a software issue?
- Open an issue on Github.
Code style¶
Please use fixed integers
, see stdint.h. Why? This library is compatible with different boards which use different architectures (16bit and 32bit.) Unfixed int
variables have different sizes in different environments and may cause unpredictable behaviour.
Pin Layout¶
The following table shows the typical pin layout used:
PCD MFRC522 |
Arduino Uno / 101 |
Teensy Mega |
Nano v3 | Leonardo / Micro | Pro Micro | 2.0 | ++ 2.0 | 3.1 | |
---|---|---|---|---|---|---|---|---|---|
Signal | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin | Pin |
RST/Reset | RST | 9 [1] | 5 [1] | D9 | RESET / ICSP-5 | RST | 7 | 4 | 9 |
SPI SS | SDA [3] | 10 [2] | 53 [2] | D10 | 10 | 10 | 0 | 20 | 10 |
SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 | 2 | 22 | 11 |
SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 | 3 | 23 | 12 |
SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 | 1 | 21 | 13 |
ESP8266 Wemos D1 mini |
|
---|---|
Signal | Pin |
RST/Reset | D3 |
SPI SS | D8 |
SPI MOSI | D7 |
SPI MISO | D6 |
SPI SCK | D5 |
[1] | (1, 2) Configurable, typically defined as RST_PIN in sketch/program. |
[2] | (1, 2) Configurable, typically defined as SS_PIN in sketch/program. |
[3] | The SDA pin might be labeled SS on some/older MFRC522 boards. |
Hardware¶
There are three hardware components involved:
- Micro Controller:
- An Arduino or compatible executing the Sketch using this library.
- Prices vary from USD 7 for clones, to USD 75 for “starter kits” (which might be a good choice if this is your first exposure to Arduino; check if such kit already includes the Arduino, Reader, and some Tags).
- Proximity Coupling Device (PCD):
- The PCD is the actual RFID Reader based on the NXP MFRC522 Contactless Reader Integrated Circuit.
- Readers can be found on eBay for around USD 5: search for “rc522”.
- You can also find them on several web stores. They are often included in “starter kits”, so check your favourite electronics provider as well.
- Proximity Integrated Circuit Card (PICC):
- The PICC is the RFID Card or Tag using the ISO/IEC 14443A interface, for example Mifare or NTAG203.
- One or two might be included with the Reader or “starter kit” already.
Protocols¶
- The micro controller and the reader use SPI for communication.
- The protocol is described in the NXP MFRC522 datasheet.
- See the Pin Layout section for details on connecting the pins.
- The reader and the tags communicate using a 13.56 MHz electromagnetic field.
- The protocol is defined in ISO/IEC 14443-3:2011 Part 3 Type A.
- Details are found in chapter 6 “Type A – Initialization and anticollision”.
- See http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf for a free version of the final draft (which might be outdated in some areas).
- The reader does not support ISO/IEC 14443-3 Type B.
Security¶
- The UID of a card can not be used as an unique identification for security related projects. Some Chinese cards allow to change the UID which means you can easily clone a card. For projects like access control, door opener or payment systems you must implement an additional security mechanism like a password or normal key.
- This library only supports crypto1-encrypted communication. Crypto1 has been known as broken for a few years, so it does NOT offer ANY security, it is virtually unencrypted communication. Do not use it for any security related applications!
- This library does not offer 3DES or AES authentication used by cards like the Mifare DESFire, it may be possible to be implemented because the datasheet says there is support. We hope for pull requests :).
Troubleshooting¶
- I don’t get input from reader or WARNING: Communication failure, is the MFRC522 properly connected?
- Check your physical connection, see Pin Layout .
- Check your pin settings/variables in the code, see Pin Layout .
- Check your pin header soldering. Maybe you have cold solder joints.
- Check voltage. Most breakouts work with 3.3V.
- SPI only works with 3.3V, most breakouts seem 5V tollerant, but try a level shifter.
- SPI does not like long connections. Try shorter connections.
- SPI does not like prototyping boards. Try soldered connections.
- According to reports #101, #126 and #131, there may be a problem with the soldering on the MFRC522 breakout. You could fix this on your own.
- Firmware Version: 0x12 = (unknown) or other random values
- The exact reason of this behaviour is unknown.
- Some boards need more time after PCD_Init() to be ready. As workaround add a delay(4) directly after PCD_Init() to give the PCD more time.
- If this sometimes appears, a bad connection or power source is the reason.
- If the firmware version is reported permanent, it is very likely that the hardware is a fake or has a defect. Contact your supplier.
- Sometimes I get timeouts or sometimes tag/card does not work.
- Try the other side of the antenna.
- Try to decrease the distance between the MFRC522 and your tag.
- Increase the antenna gain per firmware:
mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
- Use better power supply.
- Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller.
- My tag/card doesn’t work.
- Distance between antenna and token too large (>1cm).
- You got the wrong type PICC. Is it really 13.56 MHz? Is it really a Mifare Type A?
- NFC tokens are not supported. Some may work.
- Animal RFID tags are not supported. They use a different frequency (125 kHz).
- Hardware may be corrupted, most products are from china and sometimes the quality is really poor. Contact your seller.
- Newer versions of Mifare cards like DESFire/Ultralight maybe not work according to missing authentication, see security or different protocol.
- Some boards bought from Chinese manufactures do not use the best components and this can affect the detection of different types of tag/card. In some of these boards, the L1 and L2 inductors do not have a high enough current so the signal generated is not enough to get Ultralight C and NTAG203 tags to work, replacing those with same inductance (2.2uH) but higher operating current inductors should make things work smoothly. Also, in some of those boards the harmonic and matching circuit needs to be tuned, for this replace C4 and C5 with 33pf capacitors and you are all set. (Source: Mikro Elektronika)
- My mobile phone doesn’t recognize the MFRC522 or my MFRC522 can’t read data from other MFRC522
- Card simulation is not supported.
- Communication with mobile phones is not supported.
- Peer to peer communication is not supported.
- I can only read the card UID.
- Maybe the AccessBits have been accidentally set and now an unknown password is set. This can not be reverted.
- Probably the card is encrypted. Especially official cards like public transport, university or library cards. There is no way to get access with this library.
- I need more features.
- If software: code it and make a pull request.
- If hardware: buy a more expensive chip like the PN532 (supports NFC and many more, but costs about $15)
License¶
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to https://unlicense.org/
Dependency¶
- Arduino.h
- From: Arduino IDE / target specific
- License: (target: Arduino) GNU Lesser General Public License 2.1
- SPI.h
- From: Arduino IDE / target specific
- License: (target: Arduino) GNU Lesser General Public License 2.1
- stdint.h
- From: Arduino IDE / Compiler and target specific
- License: different
History¶
The MFRC522 library was first created in Jan 2012 by Miguel Balboa (from http://circuitito.com) based on code by Dr. Leong (from http://B2CQSHOP.com) for “Arduino RFID module Kit 13.56 Mhz with Tags SPI W and R By COOQRobot”.
It was translated into English and rewritten/refactored in the fall of 2013 by Søren Thing Andersen (from http://access.thing.dk).
It has been extended with functionality to alter sector 0 on Chinese UID changeable MIFARE card in Oct 2014 by Tom Clement (from http://tomclement.nl).
Maintained by miguelbalboa until 2016. Maintained by Rotzbua from 2016 until 2018.
References¶
MMA-7455 Accelerometer¶
Library for the MMA-7455 3-axis accelerometer
References¶
Used by¶
- MMA7455 Accelerometer Sample
ModbusMaster RTU Library¶
This library handles Modbus master RTU communication. The library supports callbacks for pre- and post-transmission, receive and transmit logging.
-
MB_RESPONSE_TIMEOUT
¶ The patch provides changeable response timeout using
MB_RESPONSE_TIMEOUT
(in milliseconds).
The original author of the library is 4-20ma: https://github.com/4-20ma/ModbusMaster/
The one included in Sming is nomis’ fork: https://github.com/nomis/ModbusMaster (see branch fixes-2.0.1) that isn’t yet merged to the original repository.
References¶
Used by¶
Environment Variables¶
Submodule: ModbusMaster¶
ModbusMaster¶
` .. image:: https://img.shields.io/github/release/4-20ma/ModbusMaster.svg?maxAge=3600
target: https://img.shields.io/github/release/4-20ma/ModbusMaster.svg?maxAge=3600 alt: GitHub release
` .. image:: https://img.shields.io/travis/4-20ma/ModbusMaster.svg?maxAge=3600
` .. image:: https://img.shields.io/github/license/4-20ma/ModbusMaster.svg?maxAge=3600
target: https://img.shields.io/github/license/4-20ma/ModbusMaster.svg?maxAge=3600 alt: license <LICENSE>`_
` .. image:: https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?maxAge=3600
target: https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?maxAge=3600 alt: code of conduct <CODE_OF_CONDUCT.md>`_
This is an Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
The following Modbus functions are available:
Discrete Coils/Flags
- 0x01 - Read Coils
- 0x02 - Read Discrete Inputs
- 0x05 - Write Single Coil
- 0x0F - Write Multiple Coils
Registers
- 0x03 - Read Holding Registers
- 0x04 - Read Input Registers
- 0x06 - Write Single Register
- 0x10 - Write Multiple Registers
- 0x16 - Mask Write Register
- 0x17 - Read Write Multiple Registers
Both full-duplex and half-duplex RS232/485 transceivers are supported. Callback functions are provided to toggle Data Enable (DE) and Receiver Enable (/RE) pins.
Install the library into your Arduino IDE using the Library Manager (available from IDE version 1.6.2). Open the IDE and click Sketch > Include Library > Manage Libraries…
Scroll or search for ModbusMaster
, then select the version of the library you want to install. Quit/re-launch the IDE to refresh the list; new versions are automatically added to the list, once released on GitHub.
Refer to Arduino Tutorials > Libraries Using the Library Manager.
Refer to Arduino Tutorials > Libraries Importing a .zip Library.
Refer to Arduino Tutorials > Libraries Manual Installation.
This library has been tested with an Arduino Duemilanove, PHOENIX CONTACT nanoLine controller, connected via RS485 using a Maxim MAX488EPA transceiver.
Conforms to Arduino IDE 1.5 Library Specification v2.1 which requires Arduino IDE >= 1.5.
Arduinos prior to the Mega have one serial port which must be connected to USB (FTDI) for uploading sketches and to the RS232/485 device/network for running sketches. You will need to disconnect pin 0 (RX) while uploading sketches. After a successful upload, you can reconnect pin 0.
Please submit an issue for all questions, bug reports, and feature requests. Email requests will be politely redirected to the issue tracker so others may contribute to the discussion and requestors get a more timely response.
The library contains a few sketches that demonstrate use of the ModbusMaster
library. You can find these in the examples folder.
/*
Basic.pde - example using ModbusMaster library
Library:: ModbusMaster
Author:: Doc Walker <4-20ma@wvfans.net>
Copyright:: 2009-2016 Doc Walker
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <ModbusMaster.h>
// instantiate ModbusMaster object
ModbusMaster node;
void setup()
{
// use Serial (port 0); initialize Modbus communication baud rate
Serial.begin(19200);
// communicate with Modbus slave ID 2 over Serial (port 0)
node.begin(2, Serial);
}
void loop()
{
static uint32_t i;
uint8_t j, result;
uint16_t data[6];
i++;
// set word 0 of TX buffer to least-significant word of counter (bits 15..0)
node.setTransmitBuffer(0, lowWord(i));
// set word 1 of TX buffer to most-significant word of counter (bits 31..16)
node.setTransmitBuffer(1, highWord(i));
// slave: write TX buffer to (2) 16-bit registers starting at register 0
result = node.writeMultipleRegisters(0, 2);
// slave: read (6) 16-bit registers starting at register 2 to RX buffer
result = node.readHoldingRegisters(2, 6);
// do something with data if read is successful
if (result == node.ku8MBSuccess)
{
for (j = 0; j < 6; j++)
{
data[j] = node.getResponseBuffer(j);
}
}
}
Project inspired by `Arduino Modbus Master <http://sites.google.com/site/jpmzometa/arduino-mbrt/arduino-modbus-master>`_.
- Author:: Doc Walker (4-20ma@wvfans.net)
- Author:: Ag Primatic (agprimatic@gmail.com)
- Author:: Marius Kintel (marius@kintel.net)
Copyright:: 2009-2016 Doc Walker
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Multipart Parser¶
Component to manage processing of multipart form data according to RFC7578, mostly used to support file uploads via HTTP/POST.
Usage¶
While setting up your web server, register the body parser provided by the library:
#include <MultipartParser.h>
HttpServer server;
...
server.setBodyParser(MIME_FORM_MULTIPART, formMultipartParser);
Now add a HttpMultipartResource
for the path to receive the multipart data:
void fileUploadMapper(HttpFiles& files)
{
files["file"] = <writable_stream_to_process_file>;
}
int onUpload(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response)
{
// `file` points to the stream from `fileUploadMapper`.
auto* file = request.files["file"];
// TODO: use methods of `file` to check if data was processed successfully
// TODO: setup HTTP response
return 0;
}
...
server.paths.set("/upload", new HttpMultipartResource(fileUploadMapper, onUpload));
See HttpServer Firmware Upload for further details.
Upgrade Notes¶
The functionality provided by this lirbary was previously controlled by the config option ENABLE_HTTP_SERVER_MULTIPART.
To upgrade, you have to replace:
ENABLE_HTTP_SERVER_MULTIPART := 1
by:
ARDUINO_LIBRARIES += MultipartParser
in your component.mk. In addition, body parser registration must now be done explicitly by application (see above).
API Documentation¶
MultipartParser API¶
-
size_t
formMultipartParser
(HttpRequest &request, const char *at, int length)¶ Body parser for content-type
form-data/multipart
Must be added to the web server’s list of body parsers explicitly:
#include <MultipartParser.h> ... HttpServer server; ... server.setBodyParser(MIME_FORM_MULTIPART, formMultipartParser);
-
class
HttpMultipartResource
: public HttpResource¶ HttpResource that allows handling of HTTP file upload.
Public Functions
-
HttpMultipartResource
(const HttpFilesMapper &mapper, HttpResourceDelegate complete)¶ Create and configure a HttpResource for handling file upload.
On a normal computer the file uploads are usually using temporary space on the hard disk or in memory to store the incoming data. On an embedded device that is a luxury that we can hardly afford. Therefore we should define a
map
that specifies explicitly where every form field will be stored. If a field is not specified then its content will be discarded.- Parameters
mapper
: callback that provides information where the desired upload fields will be stored.complete
: callback that will be called after the request has completed.
-
virtual int
setFileMap
(HttpServerConnection &connection, HttpRequest &request, HttpResponse &response)¶ Callback implementation for HttpResource::onHeadersComplete. Not to be used by application code.
-
void
shutdown
(HttpServerConnection &connection)¶ Takes care to cleanup the connection.
Public Members
-
HttpServerConnectionBodyDelegate
onBody
= nullptr¶ resource wants to process the raw body data
-
HttpResourceDelegate
onHeadersComplete
= nullptr¶ headers are ready
-
HttpResourceDelegate
onRequestComplete
= nullptr¶ request is complete OR upgraded
-
HttpServerConnectionUpgradeDelegate
onUpgrade
= nullptr¶ request is upgraded and raw data is passed to it
-
References¶
Used by¶
- HttpServer Firmware Upload Sample
Submodule: multipart-parser¶
Multipart form data parser¶
- No dependencies
- Works with chunks of a data - no need to buffer the whole request
- Almost no internal buffering. Buffer size doesn’t exceed the size of the boundary (~60-70 bytes)
Tested as part of Cosmonaut HTTP server.
Implementation based on node-formidable by Felix Geisendörfer.
Inspired by http-parser by Ryan Dahl.
This parser library works with several callbacks, which the user may set up at application initialization time.
multipart_parser_settings callbacks;
memset(&callbacks, 0, sizeof(multipart_parser_settings));
callbacks.on_header_field = read_header_name;
callbacks.on_header_value = read_header_value;
These functions must match the signatures defined in the multipart-parser header file. For this simple example, we’ll just use two of the available callbacks to print all headers the library finds in multipart messages.
Returning a value other than 0 from the callbacks will abort message processing.
int read_header_name(multipart_parser* p, const char *at, size_t length)
{
printf("%.*s: ", length, at);
return 0;
}
int read_header_value(multipart_parser* p, const char *at, size_t length)
{
printf("%.*s\n", length, at);
return 0;
}
When a message arrives, callers must parse the multipart boundary from the Content-Type header (see the RFC for more information and examples), and then execute the parser.
multipart_parser* parser = multipart_parser_init(boundary, &callbacks);
multipart_parser_execute(parser, body, length);
multipart_parser_free(parser);
In C++, when the callbacks are static member functions it may be helpful to pass the instantiated multipart consumer along as context. The following (abbreviated) class called MultipartConsumer
shows how to pass this
to callback functions in order to access non-static member data.
class MultipartConsumer
{
public:
MultipartConsumer(const std::string& boundary)
{
memset(&m_callbacks, 0, sizeof(multipart_parser_settings));
m_callbacks.on_header_field = ReadHeaderName;
m_callbacks.on_header_value = ReadHeaderValue;
m_parser = multipart_parser_init(boundary.c_str(), &m_callbacks);
multipart_parser_set_data(m_parser, this);
}
~MultipartConsumer()
{
multipart_parser_free(m_parser);
}
int CountHeaders(const std::string& body)
{
multipart_parser_execute(m_parser, body.c_str(), body.size());
return m_headers;
}
private:
static int ReadHeaderName(multipart_parser* p, const char *at, size_t length)
{
MultipartConsumer* me = (MultipartConsumer*)multipart_parser_get_data(p);
me->m_headers++;
}
multipart_parser* m_parser;
multipart_parser_settings m_callbacks;
int m_headers;
};
OneWire for Arduino¶
https://github.com/PaulStoffregen/OneWire.git
References¶
Used by¶
- DS18S20 Temperature Sensor Library
- Basic Web Skeleton (LTS) Sample
Over-the-Air Firmware Upgrade¶
This library offers a writable stream that decodes and applies [Over-the-Air] firmware upgrade files, as well as a small python utility to generate those upgrade files as part of Sming’s build process. It may be combined with any transport mechanism that is compatible with Sming’s stream classes. Check out the HttpServer Firmware Upload example, which demonstrates how the integrated HTTP server can be used to provide a web form for uploading new firmware images from the browser.
Prerequisites¶
Every in-system firmware upgrade mechanism for ESP-based devices requires partitioning the flash into two slots: One slot holds the currently running firmware, while the other slot receives the upgrade. As a consequence only half of the available flash memory can be used for the firmware. (Actually a bit less because a few sectors are reserved for the bootloader and various parameter blobs.)
In most cases, it is sufficient to set RBOOT_ROM1_ADDR
to the offset address of the second slot.
See the rBoot documentation for further options and considerations.
If your partitioning choice results in two ROM images being created, they are transparently combined such that there
is always a single OTA upgrade file. During the upgrade, the OTA code will automatically select the right image and
ignore the one for the other slot.
Attention
Make sure that the ROM slots do not overlap with each other or with areas of the flash allocated to other purposes (file system, RF calibration parameters, etc.). Sming will not detect a misconfigured flash layout.
Security features leverage libsodium, which is automatically pulled in as a dependency when signing and/or
encryption is enabled. You also have to install libsodium bindings for python on your development computer, either
using python -m pip install PyNaCl
(recommended for Windows users) or, if your are on Linux, preferably via your
distribution’s package manager (search for a package named ‘python-nacl’).
Usage¶
The OtaUpgradeStream
class¶
The library provides the class OtaUpgradeStream
(actually, an alias for either
OtaUpgrade::BasicStream
or OtaUpgrade::EncryptedStream
, depending on
ENABLE_OTA_ENCRYPTION
.), which derives from ReadWriteStream
, but, despite its base class, is only
a writable stream.
At construction time, the address and size of the slot to receive the new firmware is automatically determined from the
rBoot configuration. No further setup is required. Just feed the OTA upgrade file into the
OtaUpgradeStream::write
method in arbitrarily sized chunks. The flash
memory is updated on the fly as data arrives and upon successful validation, the updated slot is activated in the rRoot
configuration.
Once the file is complete, call OtaUpgradeStream::hasError
to check for
any errors that might have occurred during the upgrade process. The actual error, if any, is stored in the public member
OtaUpgradeStream::errorCode
and can be converted to an error message
using OtaUpgradeStream::errorToString
.
In addition, you may also examine the return value of the
OtaUpgradeStream::write
method, which will be equal to the given chunk
size, unless there is an error with the file or the upgrade process.
Building¶
The library is fully integrated into the Sming build process. Just run:
make
and find the OTA upgrade file in out/<arch>/<config>/firmware/firmware.ota
.
If security features are enabled but no secret key file does exist yet, a new one is generated during the first build.
You may change it later by modifying OTA_KEY
or using the Key/Settings rollover process.
Now install the OTA-enabled firmware once via USB/Serial cable and you are all set to do future upgrades wirelessly over your chosen communication channel.
A convenience target:
make ota-upload OTA_UPGRADE_URL=http://<your-ip>/upgrade
is provided for the not too uncommon use case of uploading the OTA file as a HTTP/POST request (but obviously is of no value for other transport mechanisms). The URL is cached and can be omitted from subsequent invocations.
Configuration and Security features¶
-
ENABLE_OTA_SIGNING
¶ Default: 1 (enabled)
If set to 1 (highly recommended), OTA upgrade files are protected against unauthorized modification by a digital signature. This is implemented using libsodium’s crypto_verify_… API, which encapsulates a public key algorithm: A secret (or ‘private’) signing key never leaves the development computer, while a non-secret (‘public’) verification key is embedded into the firmware. Public key algorithms cannot be broken even if an attacker gains physical access to one of your devices and extracts the verification key from flash memory, because only someone in possession of the secret signing key (see
OTA_KEY
) is able to create upgrade files with a valid signature.Note
You may disable signing in order to save some program memory if your communication channel already establishes a comparable level of trust, e.g. TLS with a pinned certificate.
-
OTA_ENABLE_ENCRYPTION
¶ Default: 0 (disabled)
Set to 1 to enable encryption of the upgrade file using libsodium’s crypto_secretstream_… API, in order to protect confidential data embedded in your firmware (WiFi credentials, server certificates, etc.).
It is generally unnecessary to sign encrypted upgrade files, as encryption is also authenticating, i.e. only someone in possession of the secret encryption key can generate upgrade files that decrypt successfully. There is, however, one catch: Unlike signing, encryption can be broken if an attacker is able to extract the decryption key (which is identical to the encryption key) from flash memory, in which case all current and future files encrypted with the same key are compromised. Moreover, the attacker will be able to generate new valid upgrade files modified to his or her agenda. Hence, you should only ever rely on encryption if it is impossible for an attacker to gain physical access to your device(s). But otherwise, you shouldn’t have stored confidential data on such device(s) in the first place. Conversely, you should not encrypt upgrade files that do not contain confidential data, to avoid the risk of accidentally exposing a key you might want to reuse later. For this reason, encryption is disabled by default.
Note: To mitigate a catastrophic security breach when the encryption key is revealed involuntarily, encryption and signing can be enabled at the same time. This way, an attacker (who probably has access to your WiFi by now) will at least be unable to take over more devices wirelessly. But keep in mind: it is still not a good idea to store confidential data on an unsecured device.
Note also that the described weakness is not a property of the selected encryption algorithm, but a rather general one. It can only be overcome by encrypting the communication channel instead of the upgrade file, e.g. with TLS, which uses a key exchange protocol to negotiate a temporary encryption key that is never written to flash memory. But even then, it is still unwise to embed confidential data into the firmware of a device that is physically accessible to an attacker - now you have been warned!
-
OTA_KEY
¶ Path to the secret encryption/signing key. The default is
ota.key
in the root directory of your project. If the key file does not exist, it will be generated during the first build. It can also be (re-)generated manually using the following command (usually as part of a Key/Settings rollover process):make ota-genkey
The key file must be kept secret for obvious reasons. In particular, set up your .gitignore (or equivalent VCS mechanism) carefully to avoid accidentally pushing the key file to a public repository.
By pointing
OTA_KEY
to a shared location, the same key file can be used for multiple projects, even if their security settings differ, since the key file format is independent of the security settings. (In fact, it is just a string of random numbers, from which the actual algorithm keys are derived.)
-
ENABLE_OTA_DOWNGRADE
¶ Default: 0 (disabled)
By default,
OtaUpgradeStream
refuses to downgrade to an older firmware version, in order to prevent an attacker from restoring already patched security vulnerabilities. This is implemented by comparing timestamps embedded in the firmware and the upgrade file. To disable downgrade protection, set ENABLE_OTA_DOWNGRADE to 1.Downgrade protection must be combined with encryption or signing to be effective. A warning is issued by the build system otherwise.
-
OTA_UPLOAD_URL
¶ URL used by the
make ota-upload
command.
-
OTA_UPLOAD_NAME
¶ Field name for the upgrade file in the HTTP/POST request issued by
make ota-upload
, corresponding to thename
attribute of the HTML input element:<input type="file" name="firmware" />
The default is “firmware”.
Key/Settings rollover process¶
There might be occasions where you want to change the encryption/signing key and or other OTA security settings (e.g. switch from signing to encryption or vice versa). While you could always install the new settings via USB/serial cable, you can also follow the steps below to achieve the same goal wirelessly:
Before modifying any security-related settings, start the rollover process by issuing:
make ota-rollover
Now modify security settings as desired, e.g. generate a new key using
make ota-genkey
.Run
make
to build a rollover upgrade file. The firmware image(s) contained in this file use the new security settings, while the upgrade file itself is created with the old settings (saved by the command in step 1) and thus is still compatible with the firmware currently running on your device(s).Upgrade wirelessly using the rollover file created in step 3. The new security settings are now installed.
Finalize the rollover process using the command:
make ota-rollover-done
This will delete temporary files created by step 1.
OTA upgrade file format¶
Basic file format¶
The following layout is used for unencrypted upgrade files, as well as for the data inside the encrypted container (see next paragraph). All fields are stored in little-endian byte order.
Field size (bytes) | Field description |
---|---|
4 | Magic number for file format identification:
0xf01af02a for signed images0xf01af020 for images without signature |
8 | OTA upgrade file timestamp in milliseconds since 1900/01/01 (used for downgrade protection) |
1 | Number of ROM images (1 or 2) |
3 | reserved, always zero |
variable | ROM images, see below |
64 (signed)
16 (otherwise)
|
With signature: Digital signature over the whole file up to this point.
Otherwise: MD5 HASH over the whole file up to this point. This is
not a security measure but merely protects the integrity of the file. MD5
was selected, because it already available in the ESP8266’s on-chip ROM.
|
Each ROM image has the following format:
Field size (bytes) | Field description |
---|---|
4 | Start address in flash memory (i.e. RBOOT_ROM0_ADDR for first ROM) |
4 | Size of ROM in bytes |
variable (see previous field) | ROM image content |
More content may be added in a future version (e.g. SPIFFS images, bootloader image, RF calibration data blob). The reserved bytes in the file header are intended to announce such additional content.
Encryption Container format¶
Encrypted files are stored in chunks suitable for consumption by libsodium’s crypto_secretstream_… API.
The first chunk is always 24 bytes and is fed into crypto_secretstream_pull_init
to initialize the decryption
algorithm.
Subsequent chunks are composed of:
- A 2 byte header indicating the length of the chunk minus 1. The default chunk size used by otatool.py is 2 kB.
- The data of the chunk, which is fed into
crypto_secretstream_pull
.
For further information on the data stored in the header and the chunks, refer to libsodium’s documentation and/or source code.
API Documentation¶
OTA Upgrade Stream classes¶
-
typedef
OtaUpgradeStream
¶ Alias for either
OtaUpgrade::BasicStream
orOtaUpgrade::EncryptedStream
, depending on encryption settings.Application code should use this alias to avoid source code modifications when changing OTA upgrade security settings.
-
class
BasicStream
: public ReadWriteStream¶ A write-only stream to parse and apply firmware unencrypted upgrade files generated by otatool.py.
The class fully automates the firmware upgrade process without any manual configuration. At construction time, the rBoot configuration is read to determine the unused ROM slot which should receive the upgrade. Just feed the upgrade file content into the
write()
method in arbitrarily sized chunks. The relevant portion(s) of the Flash memory (currently only the application rom) are updated on the fly as data arrives. When the file is complete and signature validation (if enabled) was successful, the updated slot is activated in the rBoot configuration. CallhasError()
and/or check the publicerrorCode
member to determine if everything went smoothly.For further information on configuration options and the file format, refer to the library’s documentation.
- See
EncryptedStream
for encryption support.
Subclassed by OtaUpgrade::EncryptedStream
Print an integral number to output stream
- Parameters
num
: Number to printbase
: The base for output (Default: Decimal (base 10))
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(unsigned long num, int base = DEC)¶
-
size_t
print
(const unsigned long long &num, int base = DEC)¶
-
size_t
print
(long, int base = DEC)¶
-
size_t
print
(const long long&, int base = DEC)¶
-
size_t
print
(unsigned int num, int base = DEC)¶
-
size_t
print
(unsigned char num, int base = DEC)¶
-
size_t
print
(int num, int base = DEC)¶
Print an integral number to output stream, appending newline
- Parameters
num
: Number to printbase
: The base for output (Default: Decimal (base 10))
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(unsigned char num, int base = DEC)¶
-
size_t
println
(unsigned int num, int base = DEC)¶
-
size_t
println
(unsigned long num, int base = DEC)¶
-
size_t
println
(const unsigned long long &num, int base = DEC)¶
-
size_t
println
(int num, int base = DEC)¶
-
size_t
println
(long num, int base = DEC)¶
-
size_t
println
(const long long &num, int base = DEC)¶
Public Types
-
enum
Error
¶ Error code values.
Values:
-
None
¶ No error occured thus far (default value of
errorCode
ifhasError()
returns false)
-
InvalidFormat
¶ Invalid/unsupported upgrade file format.
-
UnsupportedData
¶ Some content of the upgrade file is not supported by this version of OtaUpgradeStream.
-
DecryptionFailed
¶ Decryption failed. Probably wrong decryption key.
-
NoRomFound
¶ The file did not contain a ROM image suitable for the start address of the slot to upgrade.
-
RomTooLarge
¶ The contained ROM image does not fit into the application firmware slot.
-
DowngradeNotAllowed
¶ Attempt to downgrade to older firmware version.
-
VerificationFailed
¶ Signature/checksum verification failed - updated ROM not activated.
-
FlashWriteFailed
¶ Error while writing to Flash memory.
-
RomActivationFailed
¶ Error while activating updated ROM slot.
-
OutOfMemory
¶ Dynamic memory allocation failed.
-
Internal
¶ An unexpected error occured.
-
Public Functions
-
BasicStream
()¶
-
size_t
write
(const uint8_t *data, size_t size)¶ Process chunk of upgrade file.
- Return
- If less than size, an error occured. Check
errorCode
for more details. - Note
- Even if
write()
never returns less than size it is not guaranteed that the upgrade was successful. Always usehasError()
to determine success. - Parameters
data
: Pointer to chunk of data.size
: Size of chunk pointed to by data in bytes.
-
bool
hasError
() const¶ Returns true if an error happened during the upgrade process.
- See
errorCode
-
uint16_t
readMemoryBlock
(char *data, int bufSize)¶ Read a block of memory.
- Parameters
data
: Pointer to the data to be readbufSize
: Quantity of chars to read
- Return Value
uint16_t
: Quantity of chars read
-
virtual int
available
()¶ Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
bool
isFinished
()¶ Check if all data has been read.
- Return Value
bool
: True on success.
-
size_t
write
(uint8_t charToWrite)¶ Write a single character to the stream.
- Parameters
charToWrite
:
- Return Value
size_t
: Number of chars written (1 on success, 0 on failure)
-
size_t
write
(const char *str)¶ Writes a c-string to output stream.
- Parameters
str
: Pointer to c-string
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
write
(const char *buffer, size_t size)¶ Writes characters from a buffer to output stream.
- Parameters
buffer
: Pointer to character buffersize
: Quantity of characters to write
- Return Value
size_t
: Quantity of characters written to stream
-
virtual size_t
copyFrom
(IDataSourceStream *source, size_t size)¶ Copy data from a source stream.
- Parameters
source
: Stream to read data fromsize
: Quantity of chars to write, determines size of intermediate buffer to use
- Return Value
size_t
: Quantity of chars actually written, may be less than requested
-
virtual StreamType
getStreamType
() const¶ Get the stream type.
- Return Value
StreamType
: The stream type.
-
virtual bool
isValid
() const¶ Determine if the stream object contains valid data.
- Note
- Where inherited classes are initialised by constructor this method indicates whether that was successful or not (e.g. FileStream)
- Return Value
bool
: true if valid, false if invalid
-
int
read
()¶ Read one character and moves the stream pointer.
- Return Value
The
: character that was read or -1 if none is available
-
int
peek
()¶ Read a character without advancing the stream pointer.
- Return Value
int
: The character that was read or -1 if none is available
-
virtual int
seekFrom
(int offset, unsigned origin)¶ Change position in stream.
- Note
- This method is implemented by streams which support random seeking, such as files and memory streams.
- Parameters
offset
:origin
: SEEK_SET, SEEK_CUR, SEEK_END
- Return Value
New
: position, < 0 on error
-
virtual bool
seek
(int len)¶ Move read cursor.
- Parameters
len
: Relative cursor adjustment
- Return Value
bool
: True on success.
-
int
length
()¶ Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
void
flush
()¶
-
virtual String
id
() const¶ Returns unique id of the resource.
- Return Value
String
: the unique id of the stream.
-
virtual String
getName
() const¶ Returns name of the resource.
- Note
- Commonly used to obtain name of file
- Return Value
-
String
readString
(size_t maxLen = UINT16_MAX)¶ Overrides Stream method for more efficient reading.
- Note
- Content is read using
readMemoryBlock()
so read position (for seekable streams) is not changed
-
void
setTimeout
(unsigned long timeout)¶
-
bool
find
(char *target)¶
-
bool
find
(char *target, size_t length)¶
-
bool
findUntil
(char *target, char *terminator)¶
-
bool
findUntil
(char *target, size_t targetLen, char *terminate, size_t termLen)¶
-
long
parseInt
()¶
-
float
parseFloat
()¶
-
size_t
readBytes
(char *buffer, size_t length)¶
-
size_t
readBytesUntil
(char terminator, char *buffer, size_t length)¶
-
virtual int
indexOf
(char c)¶
-
int
getWriteError
()¶ Gets last error.
- Return Value
int
: Error number of last write error
-
void
clearWriteError
()¶ Clears the last write error.
-
size_t
print
(char c)¶ Prints a single character to output stream.
- Parameters
c
: Character to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const char str[])¶ Prints a c-string to output stream.
- Parameters
str
: c-string to print
- Return Value
size_t
: Quantity of characters written to output stream
-
size_t
print
(double num, int digits = 2)¶ Print a floating-point number to output stream.
- Parameters
num
: Number to printdigits
: The decimal places to print (Default: 2, e.g. 21.35)
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const Printable &p)¶ Prints a Printable object to output stream.
- Parameters
p
: Object to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const String &s)¶ Prints a String to output stream.
- Parameters
s
: String to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
()¶ Prints a newline to output stream.
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const char str[])¶ Prints a c-string to output stream, appending newline.
- Parameters
str
: c-string to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(char c)¶ Prints a single character to output stream, appending newline.
- Parameters
c
: Character to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(double num, int digits = 2)¶ Print a floating-point number to output stream, appending newline.
- Parameters
num
: Number to printdigits
: The decimal places to print (Default: 2, e.g. 21.35)
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const Printable &p)¶ Prints a Printable object to output stream, appending newline.
- Parameters
p
: Object to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const String &s)¶ Prints a String to output stream, appending newline.
- Parameters
s
: String to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
printf
(const char *fmt, ...)¶ Prints a formatted c-string to output stream.
- Note
- Use standard printf placeholders, e.g. d for integer, s for c-string, etc.
- Parameters
fmt
: Pointer to formated c-string to print...
: Parameters for placeholders within formated string
- Return Value
size_t
: Quantity of characters written to stream
-
class
EncryptedStream
: public OtaUpgrade::BasicStream¶ Encryption wrapper for BasicStream.
The class processes encrypted firmware upgrade files created by otatool.py. A buffer is allocated dynamically to fit the largest chunk of the encryption container (2kB unless otatool.py was modified). The actual processing of the decrypted data is defered to BasicStream.
Print an integral number to output stream
- Parameters
num
: Number to printbase
: The base for output (Default: Decimal (base 10))
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(unsigned long num, int base = DEC)
-
size_t
print
(const unsigned long long &num, int base = DEC)
-
size_t
print
(long, int base = DEC)
-
size_t
print
(const long long&, int base = DEC)
-
size_t
print
(unsigned int num, int base = DEC)
-
size_t
print
(unsigned char num, int base = DEC)
-
size_t
print
(int num, int base = DEC)
Print an integral number to output stream, appending newline
- Parameters
num
: Number to printbase
: The base for output (Default: Decimal (base 10))
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(unsigned char num, int base = DEC)
-
size_t
println
(unsigned int num, int base = DEC)
-
size_t
println
(unsigned long num, int base = DEC)
-
size_t
println
(const unsigned long long &num, int base = DEC)
-
size_t
println
(int num, int base = DEC)
-
size_t
println
(long num, int base = DEC)
-
size_t
println
(const long long &num, int base = DEC)
Public Types
-
enum
Error
¶ Error code values.
Values:
-
None
¶ No error occured thus far (default value of
errorCode
ifhasError()
returns false)
-
InvalidFormat
¶ Invalid/unsupported upgrade file format.
-
UnsupportedData
¶ Some content of the upgrade file is not supported by this version of OtaUpgradeStream.
-
DecryptionFailed
¶ Decryption failed. Probably wrong decryption key.
-
NoRomFound
¶ The file did not contain a ROM image suitable for the start address of the slot to upgrade.
-
RomTooLarge
¶ The contained ROM image does not fit into the application firmware slot.
-
DowngradeNotAllowed
¶ Attempt to downgrade to older firmware version.
-
VerificationFailed
¶ Signature/checksum verification failed - updated ROM not activated.
-
FlashWriteFailed
¶ Error while writing to Flash memory.
-
RomActivationFailed
¶ Error while activating updated ROM slot.
-
OutOfMemory
¶ Dynamic memory allocation failed.
-
Internal
¶ An unexpected error occured.
-
Public Functions
-
EncryptedStream
()¶
-
~EncryptedStream
()¶
-
size_t
write
(const uint8_t *data, size_t size)¶ Process an arbitrarily sized chunk of an encrypted OTA upgrade file.
- Return
- If less than size, an error occured. Check for more details.
- Note
- size does not have to match the chunk size used by otatool.py
- Parameters
data
: Pointer to chunk of data.size
: Size of chunk pointed to by data in bytes.
-
size_t
write
(uint8_t charToWrite) Write a single character to the stream.
- Parameters
charToWrite
:
- Return Value
size_t
: Number of chars written (1 on success, 0 on failure)
-
size_t
write
(const char *str) Writes a c-string to output stream.
- Parameters
str
: Pointer to c-string
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
write
(const char *buffer, size_t size) Writes characters from a buffer to output stream.
- Parameters
buffer
: Pointer to character buffersize
: Quantity of characters to write
- Return Value
size_t
: Quantity of characters written to stream
-
bool
hasError
() const Returns true if an error happened during the upgrade process.
- See
errorCode
-
uint16_t
readMemoryBlock
(char *data, int bufSize) Read a block of memory.
- Parameters
data
: Pointer to the data to be readbufSize
: Quantity of chars to read
- Return Value
uint16_t
: Quantity of chars read
-
virtual int
available
() Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
bool
isFinished
() Check if all data has been read.
- Return Value
bool
: True on success.
-
virtual size_t
copyFrom
(IDataSourceStream *source, size_t size) Copy data from a source stream.
- Parameters
source
: Stream to read data fromsize
: Quantity of chars to write, determines size of intermediate buffer to use
- Return Value
size_t
: Quantity of chars actually written, may be less than requested
-
virtual StreamType
getStreamType
() const Get the stream type.
- Return Value
StreamType
: The stream type.
-
virtual bool
isValid
() const Determine if the stream object contains valid data.
- Note
- Where inherited classes are initialised by constructor this method indicates whether that was successful or not (e.g. FileStream)
- Return Value
bool
: true if valid, false if invalid
-
int
read
() Read one character and moves the stream pointer.
- Return Value
The
: character that was read or -1 if none is available
-
int
peek
() Read a character without advancing the stream pointer.
- Return Value
int
: The character that was read or -1 if none is available
-
virtual int
seekFrom
(int offset, unsigned origin) Change position in stream.
- Note
- This method is implemented by streams which support random seeking, such as files and memory streams.
- Parameters
offset
:origin
: SEEK_SET, SEEK_CUR, SEEK_END
- Return Value
New
: position, < 0 on error
-
virtual bool
seek
(int len) Move read cursor.
- Parameters
len
: Relative cursor adjustment
- Return Value
bool
: True on success.
-
int
length
() Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
void
flush
()
-
virtual String
id
() const Returns unique id of the resource.
- Return Value
String
: the unique id of the stream.
-
virtual String
getName
() const Returns name of the resource.
- Note
- Commonly used to obtain name of file
- Return Value
-
String
readString
(size_t maxLen = UINT16_MAX) Overrides Stream method for more efficient reading.
- Note
- Content is read using
readMemoryBlock()
so read position (for seekable streams) is not changed
-
String
readString
()
-
void
setTimeout
(unsigned long timeout)
-
bool
find
(char *target)
-
bool
find
(char *target, size_t length)
-
bool
findUntil
(char *target, char *terminator)
-
bool
findUntil
(char *target, size_t targetLen, char *terminate, size_t termLen)
-
long
parseInt
()
-
float
parseFloat
()
-
size_t
readBytes
(char *buffer, size_t length)
-
size_t
readBytesUntil
(char terminator, char *buffer, size_t length)
-
String
readStringUntil
(char terminator)
-
virtual int
indexOf
(char c)
-
int
getWriteError
() Gets last error.
- Return Value
int
: Error number of last write error
-
void
clearWriteError
() Clears the last write error.
-
size_t
print
(char c) Prints a single character to output stream.
- Parameters
c
: Character to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const char str[]) Prints a c-string to output stream.
- Parameters
str
: c-string to print
- Return Value
size_t
: Quantity of characters written to output stream
-
size_t
print
(double num, int digits = 2) Print a floating-point number to output stream.
- Parameters
num
: Number to printdigits
: The decimal places to print (Default: 2, e.g. 21.35)
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const Printable &p) Prints a Printable object to output stream.
- Parameters
p
: Object to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
print
(const String &s) Prints a String to output stream.
- Parameters
s
: String to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
() Prints a newline to output stream.
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const char str[]) Prints a c-string to output stream, appending newline.
- Parameters
str
: c-string to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(char c) Prints a single character to output stream, appending newline.
- Parameters
c
: Character to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(double num, int digits = 2) Print a floating-point number to output stream, appending newline.
- Parameters
num
: Number to printdigits
: The decimal places to print (Default: 2, e.g. 21.35)
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const Printable &p) Prints a Printable object to output stream, appending newline.
- Parameters
p
: Object to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
println
(const String &s) Prints a String to output stream, appending newline.
- Parameters
s
: String to print
- Return Value
size_t
: Quantity of characters written to stream
-
size_t
printf
(const char *fmt, ...) Prints a formatted c-string to output stream.
- Note
- Use standard printf placeholders, e.g. d for integer, s for c-string, etc.
- Parameters
fmt
: Pointer to formated c-string to print...
: Parameters for placeholders within formated string
- Return Value
size_t
: Quantity of characters written to stream
References¶
- Source Code
- libsodium Component
Used by¶
- HttpServer Firmware Upload Sample
Environment Variables¶
ENABLE_OTA_DOWNGRADE
ENABLE_OTA_ENCRYPTION
ENABLE_OTA_SIGNING
OTA_KEY
OTA_UPLOAD_NAME
OTA_UPLOAD_URL
rc-switch¶
Use your Arduino or Raspberry Pi to operate remote radio controlled devices
Info¶
Send RC codes¶
Use your Arduino or Raspberry Pi to operate remote radio controlled devices. This will most likely work with all popular low cost power outlet sockets. If yours doesn’t work, you might need to adjust the pulse length.
All you need is a Arduino or Raspberry Pi, a 315/433MHz AM transmitter and one or more devices with one of the supported chipsets:
- SC5262 / SC5272
- HX2262 / HX2272
- PT2262 / PT2272
- EV1527 / RT1527 / FP1527 / HS1527
- Intertechno outlets
Receive and decode RC codes¶
Find out what codes your remote is sending. Use your remote to control your Arduino.
All you need is an Arduino, a 315/433MHz AM receiver (altough there is no instruction yet, yes it is possible to hack an existing device) and a remote hand set.
For the Raspberry Pi, clone the https://github.com/ninjablocks/433Utils project to compile a sniffer tool and transmission commands.
References¶
Used by¶
- RCSwitch Library Sample
Arduino driver for nRF24L01 2.4GHz Wireless Transceiver¶
Design Goals: This library is designed to be…
- Maximally compliant with the intended operation of the chip
- Easy for beginners to use
- Consumed with a public interface that’s similiar to other Arduino standard libraries
- Built against the standard SPI library.
Please refer to:
This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or the SPI hardware will go into ‘slave’ mode.
References¶
Used by¶
- nRF24L01 Radio Sample
Embedded RingBufCPP¶
This is a simple ring (FIFO) buffer queuing library for embedded platforms, such as Arduino’s. This library is based on a previous one I wrote, only now in C++ instead of C. It uses C++’s templating, so no more weird pointer casting, and deep copies of objects are supported. It has concurrency protection built in, so feel free to do operations on the buffer inside of ISR’s. All memory is statically allocated at compile time, so no heap memory is used. It can buffer any fixed size object (ints, floats, structs, objects, etc…).
FAQ’s¶
- I only have a C compiler for my platform
- No worries, try the vanilla C version of the library.
Use Cases¶
A ring buffer is used when passing asynchronous io between two threads. In the case of the Arduino, it is very useful for buffering data in an interrupt routine that is later processed in your void loop()
.
Supported Platforms¶
The library currently supports:
- AVR
- ESP8266
- Any other platform (just implement the
RB_ATOMIC_START
andRB_ATOMIC_END
macros)
Install¶
This library is now available in the Arduino Library Manager, directly in the IDE. Go to Sketch > Include Library > Manage Libraries
and search for RingBufCPP
. Then #include <RingBufCPP.h>
in your sketch.
To manually install this library, download this file as a zip, and extract the resulting folder into your Arduino Libraries folder. Installing an Arduino Library.
Examples¶
Look at the examples folder for several examples.
Contributing¶
If you find this Arduino library helpful, click the Star button, and you will make my day.
Feel free to improve this library. Fork it, make your changes, then submit a pull request!
API¶
Constructor¶
RingBufCPP<typename Type, size_t MaxElements>();
Creates a new RingBuf object that can buffer up to MaxElements of type Type.
Methods¶
add()¶
bool add(Type &obj);
Append an element to the buffer. Return true on success, false on a full buffer.
peek()¶
Type *peek(uint16_t num);
Peek at the num’th element in the buffer. Returns a pointer to the location of the num’th element. If num is out of bounds or the num’th element is empty, a NULL pointer is returned. Note that this gives you direct memory access to the location of the num’th element in the buffer, allowing you to directly edit elements in the buffer. Note that while all of RingBuf’s public methods are atomic (including this one), directly using the pointer returned from this method is not safe. If there is a possibility an interrupt could fire and remove/modify the item pointed to by the returned pointer, disable interrupts first with noInterrupts()
, do whatever you need to do with the pointer, then you can reenable interrupts by calling interrupts()
.
pull()¶
bool pull(Type *dest);
Pull the first element out of the buffer. The first element is copied into the location pointed to by dest. Returns false if the buffer is empty, otherwise returns true on success.
License¶
This library is open-source, and licensed under the MIT license. Do whatever you like with it, but contributions are appreciated.
References¶
- Source Code (submodule, may be patched).
Used by¶
- IRremoteESP8266 Library Library
RingTone¶
This library provides support for parsing and playing tunes in RTTTL format.
RTTTL conversion code based on https://github.com/end2endzone/NonBlockingRTTTL.
The parser is stream-based and allows random seeking where the stream supports it.
An RTTTL writer is also included to assist with editing/creation of RTTTL files.
References¶
Used by¶
- RingTone Player Sample
SI7020/SI7021 Environmental Sensors¶
Arduino library for SI7020 and SI7021 environmental sensors
Examples:
References¶
Used by¶
- SI7021 Humidity Sensor Sample
- MeteoControl MQTT Sample

Source: SERV-03-MI (Micro Servo)
Servo RC PWM Control¶
Library to control RC servos with PWM signals.
Change History¶
This library was revised for Sming version 4.0. These are the main changes:
- Interrupts remain enabled during updates
- ServoChannel value now specifies actual pulse duration in microseconds,
such that
minValue <= value <= maxValue
. Previously it was0 <= value <= (maxValue - minValue)
. - Max channels increased to 5.
See Pull Request #1870 for further details.
Brief introduction¶
There are generally two types of servo actuator (digital and analogue) and this library supports only the analogue variety.
Servo actuators have a logic-level control signal to set the position using an active-high pulse of around 1 - 2 ms. This pulse must be repeated every 20ms or so to ensure the position is maintained
Servos are generally insensitive to the exact period provided it’s no more than about 25ms. It’s the duration of the pulse which is critical.
For most servos 1.5ms is the default/centre position, however the min/max values will vary between models depending on the exact type and range of motion. These values are therefore configurable for each channel.
Physical connection¶
Servos typically use a 5V logic-level input but are usually fine with the 3.3v output from the ESP8266.
Warning
Like relays a servo is an electro-mechanical device, but it also has integrated control circuitry so doesn’t require flyback diodes, etc. to protect from current spikes.
However, remember to always insert a protection resistor of at least 200 ohms between the GPIO and the servo. This limits the current to <10mA if 5V is present on the line. For 12V servos a 1K resistor will peform the same function.
Technical Explanation¶
Each servo actuator is connected to a GPIO pin, which is toggled by an ISR driven from the Hardware Timer. The ServoChannel class represents this connection, and defines the current value (in microseconds) plus the range (minimum and maximum values) to which the value is constrained.
The hardware timer interrupt is managed by a single instance of the Servo class. All channels are updated sequentially at the start of each frame period (20ms in duration):
The first channel is set ON, then after the required time it is set OFF and the next channel set ON. The final interrupt turns the active channel OFF. This requires (NumChannels + 1) interrupts per frame, and the process repeats continuously whilst there is at least one active channel.
Channel updates (via calls to ServoChannel::setValue()) are not handled immediately, but deferred using a 10ms software timer (half the frame period). This allows more efficient updating and ensures the positions of all affected servos are changed at the same time.
A double-buffering technique is used for updates to avoid disabling interrupts, which allows use of the non-maskable timer interrupts for best timing accuracy and eliminates glitches in the output.
Updates involve re-calculating the list of active pins and timer intervals, which is stored into a second frame buffer. This is made active by the ISR when the current frame has completed.
If the ISR hasn’t yet processed a previous update, it will be retried after a further 10ms.
References¶
Used by¶
- Basic Servo Sample
Signal Generator¶
This Component provides the SignalGenerator class which can be used to synthesise a wide range of analogue signals.
Ported from https://www.codeproject.com/Articles/30180/Simple-Signal-Generator
Simple Signal Generator¶
29 Oct 2008 CPOL. Tefik Becirovic
Useful software equivalent for a real, simple signal generator device
Introduction¶
The Simple Signal Generator is a C# class designed to generate four simple periodic waveforms including sine, square, triangle, and sawtooth. The class is provided for testing software and hardware components during the development of measurement applications. A generated signal varies across time domains, and by default, is normalized by the amplitude A € [-1,1] and period T € [0,1]. It is possible to set an arbitrary amplitude, frequency, DC-offset, and phase shift, and to invert the signal.
Background Display¶
There are a couple of articles on The Code Project that describe in detail about developing different user defined components for dynamically changing single values or signal shapes such as bars, graphs, charts, gauges, and a diversity of other instruments.
For testing those components, functions like y=F(x) are very often used. These functions are typically periodical, mostly sine, and their variable x will be modified in a loop with constant steps across an interval [x0,xn].
Hardware developers use a totally different technique. For analyzing and troubleshooting electronic systems, they use an additional external device called signal or function or waveform generator. The signal generator is an important piece of electronic test equipment, and should not be missed in any electronics laboratory.
On the device, we can select a built-in periodical function like y=F(t); the variable t represents real time, and we can change some parameters like frequency, amplitude, and the DC-offset. Typically, there are four basic signal types.
After customization, the desired output signal can be wired on to the input of the component that should be tested, and we monitor their response function in the time domain using an oscilloscope.

Displayed here is a typical low-cost signal generator that has on its front panel, a radio-button with four positions to choose signal types and three potentiometers to adjust frequency, amplitude, and DC-offset. It is no big problem for hardware dudes to make something such as this, especially with tips from the book [1].
Of course, there are much better and more expensive devices on the market with more functions, more parameters to choose, better range and a finer scale for these parameters, integrated display to show selected settings, user-defined functions, on-board memory, better stability, and two or more independent channels.
Note that, there are two very significant differences between the hardware and the software approach. Hardware developers use an external device, and a test signal is in the time domain, which implies that the test signal varies totally independent from the assembly that will be tested.`
The class presented offers a software equivalent for the above described real, simple signal generator device.
Using the Code¶
For using the class, we have a public function in the form y=F(t). The parameter t is the real time here:
float GetValue();
After a lot of consideration, I added another overload of the function in the form y=F(x). The Parameter x is explicitly given as a time here:
float GetValue(float time);
This should be used publicly only for DEBUG purposes, eventually during tests by adding new signal types!
All signals have a normalized period T € [0,1] in cycles, and not the usual T € [0,2Pi] in radian. In this case, a value 1 corresponds to a full cycle. The basis for this is an easier deal with normalized values, for example, for scaling operations by fitting in a window.
The signal generator is given as a class, but it is quite easy to transform it to a non-visual, or yet to a visual component, or maybe to a form like a front panel.
For generating all the given signals, very simple functions are used, but they are not the simplest. Some functions can be made simpler, but a development goal of this project was to generate signals exactly like the following example on Wikipedia:
Sine, square, triangle, and sawtooth waveforms By Omegatron - Own work, CC BY-SA 3.0
[1] | Delton T. Horn, Build Your Own Low-Cost Signal Generator, McGraw-Hill/TAB Electronics, 1994, ISBN 0070304289 |
[2] | R.A. Penfold, How to Use Oscilloscopes and Other Test Equipment, Bernard Babani Publishing, 1989, ISBN 0859342123 |
[3] | Introduction to the Function Generator |
[4] | Using a Basic Function Generator |
References¶
Used by¶
- Basic Audio Sample
SmingTest¶
An extensible test framework for Sming, with integrated profiling and scheduling support.
- A test module contains all code related to testing a specific Component, Library or framework module
- If a module contains more than one file then place all files in a sub-directory
- Each module must have a registration function
- Use the REGISTER_TEST macro to name the function
- Add an entry to the modules.h file
- Each module contains one or more test groups
- Each group is a class inheriting from TestGroup
- Add a call to registerGroup<> to the registration function for each test class
- Keep each group brief. Use multiple, simpler groups if necessary.
- The group execute() method is called to run the tests. On return the group is considered to have been successfully completed and destroyed.
- Call TEST_ASSERT() at appropriate points; passing false will fail the test and abort the process, displaying the source location of the failure.
- If a test fails then additional details may be shown before calling TEST_ASSERT(false).
- For asynchronous testing calling pending() before returning. When the tests have been completed call complete(). (See test-timers for an example.)
The following macros are added for ease of importing tests from other frameworks:
- TEST_CASE()
- REQUIRE()
What happens¶
The registerGroup<> function creates a factory function which is added to the groupFactories list.
The test runner creates, executes and destroys each group in turn, and deals with scheduling.
Getting started¶
A Sample test skeleton project is provided which you can copy to provide a starting point.
See the Sming HostTests test application for how to create your own test applications.
Notes¶
Tests are run with DEBUG_VERBOSE_LEVEL at WARNING level, so debug_i statements will not normally be shown. Tests can use other debug_X functions as required, or Serial print methods.
Tests should compile and run for all architectures.
References¶
- Source Code (submodule, may be patched).
- malloc_count Component
Solar Calculator¶
Arduino library to support calculation of sunrise / sunset times
See SystemClock NTP for example usage.
This is straight port of the code used by https://www.esrl.noaa.gov/gmd/grad/solcalc/
Javascript reference: https://www.esrl.noaa.gov/gmd/grad/solcalc/main.js
References¶
Used by¶
- SystemClock NTP Sample
SparkFun APDS9960 RGB and Gesture Sensor Arduino Library¶

*Avago APDS-9960 Breakout Board (SEN-12787)*
Getting Started¶
- Download the Git repository as a ZIP (“Download ZIP” button)
- Unzip
- Copy the entire library directory (APDS-9960_RGB_and_Gesture_Sensor_Arduino_Library ) to <Arduino installation directory>/libraries
- Open the Arduino program
- Select File -> Examples -> SparkFun_APDS9960 -> GestureTest
- Plug in your Arduino and APDS-9960 with the following connections
-OR-
- Use the library manager
Arduino Pin | APDS-9960 Board | Function |
---|---|---|
3.3V | VCC | Power |
GND | GND | Ground |
A4 | SDA | I2C Data |
A5 | SCL | I2C Clock |
2 | INT | Interrupt |
- Go to Tools -> Board and select your Arduino board
- Go to Tools -> Serial Port and select the COM port of your Arduino board
- Click “Upload”
- Go to Tools -> Serial Monitor
- Ensure the baud rate is set at 9600 baud
- Swipe your hand over the sensor in various directions!
Repository Contents¶
- /examples - Example sketches for the library (.ino). Run these from the Arduino IDE.
- /src - Source files for the library (.cpp, .h).
- library.properties - General library properties for the Arduino package manager.
Documentation¶
- **Installing an Arduino Library Guide** - Basic information on how to install an Arduino library.
- **Product Repository** - Main repository (including hardware files) for the SparkFun_APDS9960 RGB and Gesture Sensor.
- **Hookup Guide** - Basic hookup guide for the sensor.
Version History¶
- V_1.4.1 - Removing blank files, updating library.properties file.
- V_1.4.0 - Updated to new library structure
- V_1.3.0 - Implemented disableProximitySensor(). Thanks to jmg5150 for catching that!
- V_1.2.0 - Added pinMode line to GestureTest demo to fix interrupt bug with some Arduinos
- V_1.1.0 - Updated GestureTest demo to not freeze with fast swipes
- V_1.0.0: Initial release
- Ambient and RGB light sensing implemented
- Ambient light interrupts working
- Proximity sensing implemented
- Proximity interrupts working
- Gesture (UP, DOWN, LEFT, RIGHT, NEAR, FAR) sensing implemented
License Information¶
This product is *open source_!
The code is beerware; if you see me (or any other SparkFun employee) at the local, and you’ve found our code helpful, please buy us a round!
Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license.
Distributed as-is; no warranty is given.
- Your friends at SparkFun.
References¶
Used by¶
- APDS-9660 Gesture Sample
ILI9163C TFT Display¶
ILI9163C- A fast SPI driver for TFT that use Ilitek ILI9163C.

Link to a video:
https://www.youtube.com/watch?v=y5f-VNBxgEk&feature=youtu.be
Features:
- Very FAST!, expecially with Teensy 3.x where uses DMA SPI.
- It uses just 4 or 5 wires.
- Compatible at command level with Adafruit display series so it's easy to adapt existing code.
- It uses the standard Adafruit_GFX Library (you need to install).
Pay Attention to connections!!!!:
- This display has logic at 3V3 volt so YOU NEED A VOLTAGE CONVERTER if you plan to use with arduino.
If you try to connect directly you can burn it very fast so PAY ATTENTION!
- My display works at 3V3 volt for logic but LED background has resistor for 5V. Your can be different
so carefully check out before connect it.
- My library works only in SPI mode by using MOSI,SCLK and a CS pin plus an additional pin for DC (or RS).
I've used also the reset pin but you can save it by connect it at 3V3 volt and use the constructor without
the reset pin. The initialization routine will automatically use the software reset.
- People using Teensy3 should remember that have to choose for CS and DC a pin that satisfy:
if (pin == 2 || pin == 6 || pin == 9) return true;
if (pin == 10 || pin == 15) return true;
if (pin >= 20 && pin <= 23) return true;
Background:
I got one of those displays from a chinese ebay seller but unfortunatly I cannot get
any working library so I decided to hack it. ILI9163C looks pretty similar to other
display driver but it uses it's own commands so it's tricky to work with it unlsess you
carefully fight with his gigantic and not so clever datasheet.
My display it's a 1.44"", 128x128 that suppose to substitute Nokia 5110 LCD and here's the
first confusion! Many sellers claim that it's compatible with Nokia 5110 (that use a philips
controller) but the only similarity it's the pin names since that this one it's color and
have totally different controller that's not compatible. Altrough I discovered that it's not
128x128 but 128x160 (!??)... Check links below to see if it's similar to yours.
http://www.elecrow.com/144-128x-128-tft-lcd-with-spi-interface-p-855.html
Pay attention that ILI9163C can drive different resolutions and your display can be
160*128 or whatever, also there's a strain of this display with a black PCB that a friend of mine
got some weeks ago and need some small changes in library to get working.
If you look at TFT_ILI9163C.h file you can add your modifications and let me know so I
can include for future versions.
Code Optimizations:
The purpose of this library it's SPEED. I have tried to use hardware optimized calls
where was possible and results are quite good for most applications.
Of course it can be improved so feel free to add suggestions.
Copyright (c) 2014, .S.U.M.O.T.O.Y., coded by Max MC Costa.
TFT_ILI9163C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
TFT_ILI9163C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
This file needs the following Libraries:
*Adafruit_GFX by Adafruit:
https://github.com/adafruit/Adafruit-GFX-Library
Remember to update GFX library often to have more features with this library!
*From this version I'm using my version of Adafruit_GFX library:
https://github.com/sumotoy/Adafruit-GFX-Library
It has faster char rendering and some small little optimizations but you can
choose one of the two freely since are both fully compatible.
Special Thanks:
Thanks Adafruit for his Adafruit_GFX!
Thanks to Paul Stoffregen for his beautiful Teensy3 and DMA SPI.
Version:
0.1a1: First release, compile correctly. Altrough not fully working!
0.1a3: Some bugfix, still some addressing problems, partial rotation solved.
0.1b1: Beta version! Fully working but still not tested with Arduino and DUE (altrough it compile)
0.2b2: Code cleaned and added support for 2.2" RED PCB displays.
0.2b4: Bug fixes and added color space support.
BugList of the current version:
- Beta version fully working!
References¶
- Source Code
- Adafruit GFX Component
Used by¶
- nRF24L01 Radio Sample
- ILI9163C TFT Screen Sample
TM1637 LED Driver¶
Description¶
An Arduino library for 7-segment display modules based on the TM1637 chip, such as Seeed Studio’s Grove 4 digit display. The TM1637 chip also has keyboard input capability, but it’s not implemented in this library.
Hardware Connection¶
The display modules has two signal connection (and two power connections) which are CLK and DIO. These pins can be connected to any pair of digital pins on the Arduino. When an object is created, the pins should be configured. There is no limitation on the number of instances used concurrently (as long as each instance has a pin pair of its own)
Installation¶
The library is installed as any Arduino library, by copying the files into a directory on the library search path of the Arduino IDE
Usage¶
The library provides a single class named TM1637Display. An instance of this class provides the following functions:
setSegments
- Set the raw value of the segments of each digitshowNumberDec
- Display a decimal numbershowNumberDecEx
- Display a decimal number with decimal points or colonsetBrightness
- Sets the brightness of the display
The information given above is only a summary. Please refer to TM1637Display.h for more information. An example is included, demonstrating the operation of most of the functions.
References¶
- Source Code (submodule, may be patched).
Used by¶
- TM1637 Display Sample
Timezone¶
Arduino library to support local/UTC time conversions using rules
See SystemClock NTP for example usage.
Port of https://github.com/JChristensen/Timezone for Sming.
References¶
Used by¶
- SystemClock NTP Sample
Tone Generator¶
Uses the I2S module to synthesize tones using a minimal amount of Flash memory, RAM and CPU time.
Audio is output via the I2S_TX_DATA pin using Delta-Sigma modulation. This is a high-frequency bitstream which requires low-pass filtering and suitable amplification for driving speaker/headphones.
Warning
Do not connect the output directly to a loudspeaker or headphone as you may damage the GPIO. Always buffer the signal using a transistor, op-amp, etc.
See Esp8266 Drivers for further information about I2S.
As the output pin is normally used as UART0 RX, the alternate UART pin configuration is used:
GPIO | Alternate | NodeMCU | Notes |
---|---|---|---|
3 | I2S_TX_DATA | D9 | Audio output |
13 | RXD2 | D7 | Debug serial input |
15 | TXD2 | D8 | Debug serial output |
GPIO3 is still required for programming so you’ll need to make sure the audio buffer is disconnected, or has a reasonably high impedance load. You’ll also need an additional USB-serial converter connected to GPIO13 & 15 for terminal operation.
References¶
Used by¶
- RingTone Player Sample
Ultrasonic¶
Tested on modules:
- HC-SR04 - ranges: 2-400cm, power: 5v, levels: TTL, for work with 3.3v need voltage divider on ECHO pin
- US-100 - power: 3.3v-5v, temp. compensation
References¶
Used by¶
- HCSR04 Ultrasonic Transducer Sample
WS2812 Neopixel¶
http://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
References¶
Used by¶
- WS2812 LEDs Sample
WebCam¶
Introduction¶
This component provides a webcamera(aka webcam) stream and camera drivers that can help you stream your webcam images as video stream through the embedded web server.
References¶
Used by¶
- WebcamServer sample Sample
Yeelight¶
Library to control Yeelight devices via JSON
See https://www.yeelight.com/en_US/activity
Specification: https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf
References¶
- Source Code
- ArduinoJson Version 6 Component
Used by¶
- Yeelight LED bulbs Sample
libsodium¶
From its documentation: Sodium is a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more.
Usage¶
This component integrates libsodium v1.0.18 into Sming. To use it, simply add ARDUINO_LIBRARIES += libsodium
to your application’s component.mk and #include <sodium.h>
(or one of the more specific headers in sodium/*).
For further information, see libsodiums documentation.
Build Details¶
To build the library, Sming’s standard component build process is used in favor of libsodium’s original autotools based build process, which is not compatible with the xtensa-lx106-elf architecture. The list of source files, as well as compiler definitions, are hard-coded in component.mk according to the outcomes of (a hacked version of) the configure script.
All optimizations leveraging x86/ARM architecture-specific assembly intructions are disabled and only C reference implementations are used instead. This is true even when compiling for the “Host” architecture.
As a side effect, there is no need to invoke ``sodium_init()`` on application startup (which would otherwise detect available CPU features and select optimal implementations accordingly).
Notes on Random Number Generation¶
By default, the randombytes_...
family of functions is hooked up to the ESP8266 hardware random number generator via os_[get_]random
, which is also available in the Host emulator. However, due to the lack of documentation, it is unclear if the hardware random number generator provides sufficiently high quality random numbers for cryptographic purposes. Some additional information can be found here. Also note that the host emulator may not use a high-quality random number source and therefore should not be trusted with generating private keys and other sensitive data.
Alternatively, libsodium offers the possibility to install a custom random number generator implementation via randombytes_set_implementation()
, which is fully controllable by the user.
References¶
- Source Code
- Cryptographic Support Component
Used by¶
- Over-the-Air Firmware Upgrade Library
Submodule: libsodium¶

Sodium is a new, easy-to-use software library for encryption, decryption, signatures, password hashing and more.
It is a portable, cross-compilable, installable, packageable fork of NaCl, with a compatible API, and an extended API to improve usability even further.
Its goal is to provide all of the core operations needed to build higher-level cryptographic tools.
Sodium supports a variety of compilers and operating systems, including Windows (with MingW or Visual Studio, x86 and x64), iOS, Android, as well as Javascript and Webassembly.
Documentation¶
The documentation is available on Gitbook and built from the libsodium-doc repository:
- libsodium documentation - online, requires Javascript.
- offline documentation in PDF format.
Integrity Checking¶
The integrity checking instructions (including the signing key for libsodium) are available in the installation section of the documentation.
Community¶
A mailing-list is available to discuss libsodium.
In order to join, just send a random mail to sodium-subscribe
{at}
pureftpd
{dot} org
.
License¶
modbusino RTU Library (modbus slave)¶
modbusino is lightweight RTU Modbus slave library that supports ‘read holding registers’ and ‘write multiple registers’ functions. Please note that prior to commit 02dff3c (branch Sming, port URL https://github.com/kmihaylov/modbusino) a delay may occur after sending a message (more information can be found in the PR thread #2043, https://github.com/SmingHub/Sming/pull/2043#issuecomment-615945823).
Configuration variables¶
-
RS485_RE_PIN
¶ Default: 15
GPIO pin number for RE (Receive-Enable) output.
-
RS485_TX_LEVEL
¶ Default: HIGH.
Active level for RE pin during transmission.
References¶
Used by¶
- Modbusino RTU generic sample Sample
Environment Variables¶
Submodule: modbusino¶
Modbusino¶
Modbusino is a ISC licensed library to handle Modbus requests on Arduino (slave).
To keep it simple and to reduce memory consumption, only the two following Modbus functions are supported:
- read holding registers (0x03)
- write multiple registers (0x10)
#include <Modbusino.h>
/* Initialize the slave with the ID 1 */
ModbusinoSlave modbusino_slave(1);
/* Allocate a mapping of 10 values */
uint16_t tab_reg[10];
void setup() {
/* The transfer speed is set to 115200 bauds */
modbusino_slave.setup(115200);
}
void loop() {
/* Initialize the first register to have a value to read */
tab_reg[0] = 0x1234;
/* Launch Modbus slave loop with:
- pointer to the mapping
- max values of mapping */
modbusino_slave.loop(tab_reg, 10);
}
I want to keep this library very basic and small so if you want to contribute:
- Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
- Fork the repository on Github to start making your changes on another branch.
- Send a pull request (of your small and atomic changes).
- Bug the maintainer if he’s too busy to answer :)
Si4432 RF Transceiver¶
SI4432 library for Arduino - v0.1
Please note that Library uses standard SS pin for NSEL pin on the chip. This is 53 for Mega, 10 for Uno.
made by Ahmet (theGanymedes) Ipkin (2014)
https://github.com/ADiea/si4432.git
References¶
Used by¶
- SI443 Radio Sample
API Documentation¶
This is a separate section built using DOXYGEN, which will replace this file when built.
Information¶
Sming build system¶
Introduction¶
This guide is provided to assist with understanding, developing and modifying the build system.
A Sming project is built from a set of static libraries (object archives). Typically the application code is one library, built from the user’s source code, whilst the other libraries are common to all projects and stored in a separate, shared location.
Until recently Sming itself has always been built as one large library, but this is now broken into a number of discrete Component libraries. The concept is borrowed from Espressif’s ESP-IDF build system and whilst there are some similarities the two systems are completely independent.
Building applications¶
Setup¶
These are the main variables you need to be aware of:
-
SMING_HOME
¶ must be set to the full path of the
Sming
directory.
-
SMING_ARCH
¶ Defines the target architecture
- Esp8266 The default if not specified.
ESP_HOME
must also be provided to locate SDK & tools. - Esp32 {todo}
- Host builds a version of the library for native host debugging on Linux or Windows
- Esp8266 The default if not specified.
-
SMING_CPP_STD
¶ The build standard applied for the framework.
This defaults to C++17 if the toolchain supports it (GCC 5+), C++11 otherwise. You can override to use other standards, such as
c++2a
for experimental C++20 support.
These variables are available for application use:
-
PROJECT_DIR
¶ Path to the project’s root source directory, without trailing path separator. This variable is available within makefiles, but is also provided as a #defined C string to allow references to source files within application code, such as with the
IMPORT_FSTR
macro.
COMPONENT_PATH
As for PROJECT_DIR, but provides the path to the
current component’s root source directory.
Converting existing projects¶
Instead of Makefile-user.mk
a project should provide a component.mk
. To convert to the new style:
- Copy
Makefile
andcomponent.mk
from theBasic_Blink
sample project - Copy any customisations from
Makefile-user.mk
intocomponent.mk
file. (Or, renameMakefile-user.mk
tocomponent.mk
then edit it.) - Delete
Makefile-user.mk
- If the project uses any Arduino libraries, set the
ARDUINO_LIBRARIES
variable
Targets You can add your own targets to component.mk as usual. It’s a good idea to add a comment for the target, like this:
##@Building
.PHONY: mytarget
mytarget: ##This is my target
When you type make help
it will appear in the list.
If you need a target to be added as a dependency to the main application
build, add it to CUSTOM_TARGETS
- the Basic Serial sample
contains a simple example of this.
-
ARDUINO_LIBRARIES
¶ If your project uses any Arduino libraries, you must set this value appropriately.
Source files Use COMPONENT_SRCDIRS
instead of MODULES
. Use
COMPONENT_SRCFILES
to add individual files.
Include paths Use COMPONENT_INCDIRS
instead of EXTRA_INCDIR
,
unless the paths are only required to build this Component.
See component.mk for a full list of variables.
Building¶
You should normally work from the project directory. Examples:
- Type
make
to build the project and any required Components. To speed things up, use parallel building, e.g.make -j5
will build using a maximum of 5 concurrent jobs. The optimum value for this is usually (CPU CORES + 1). Usingmake -j
will use unlimited jobs, but can cause problems in virtual environments. - Type
make help
from the project directory to get a list of available build targets.
To switch to a different build architecture, for example:
- Type
make SMING_ARCH=Host
to build the project for the host emulator - Type
make flash
to copy any SPIFFS image (if enabled) to the virtual flash, and run the application. (Note that you don’t need to set SMING_ARCH again, the value is cached.)
To inspect the current build configuration, type make list-config
.
Configuration variables¶
Configuration variables should be set in the project’s component.mk file. If appropriate, they can also be set as environment variables.
During development, the easiest way to change variables is on the
make
command line. These are cached so persist between make
sessions, and will override any values set in your project’s
component.mk
file. For example:
- Type
make SPIFF_BIN=test-rom
to build the project and (if enabled) create a SPIFFS image file calledtest-rom.bin
- Type
make flash COM_PORT=COM4 SPI_MODE=dio SPI_SIZE=4M
to flash the project andtest-rom
SPIFFS image using the provided flash memory settings - Next time you type
make flash
, the same settings will be used, no need to type them again
A separate cache is maintained for each build type (arch + release/debug). For example:
- Type
make SMING_RELASE=1 list-config
to switch to release build and display the active configuration
Type make config-clean
to clear all caches and revert to defaults.
For reference, a copy of all build variables are stored in a file with each firmware image created in the ‘firmware’ directory.
Component repositories¶
Placing Components in a common location allows them to be used by
multiple projects. To set up your own Component repository, create a
directory in a suitable location which will contain your Components and
set COMPONENT_SEARCH_DIRS
to the full path of that directory. For
example:
|_ opt/
|_ shared/
|_ Components/ The repository
|_ MyComponent/
|_ AnotherComponent/
|_ spiffs/ Will be used instead of Sming version
User repositories are searched first, which allows replacement of any
Component for a project. In this example, our spiffs
component will
be selected instead of the one provided with Sming.
Directory layout¶
The main Sming repo. is laid out like this:
|_ sming/
|_ .appveyor.yml CI testing (Windows)
|_ .travis.yml CI testing (Linux)
|_ .appveyor/ CI scripts (Windows)
|_ .travis CI scripts (Linux)
|_ docs/ Sming documentation
|_ samples/ Samples to demonstrate specific Sming features or libraries
|_ Sming/
| |_ Makefile Builds documentation, performs global actions on the framework
| |_ project.mk Main makefile to build a project
| |_ build.mk Defines the build environment
| |_ component.mk Sming Component definition file
| |_ component-wrapper.mk Used to build each Component using a separate make instance
| |_ Arch/ Architecture-specific makefiles and code
| | |_ Esp8266/
| | | |_ sming.mk Defines architecture-specific Components and libraries
| | | |_ app.mk Link the project, create output binaries
| | | | and perform architecture-specific actions
| | | |_ build.mk Architecture-specific build definitions, such as compiler paths
| | | |_ Compiler/
| | | |_ Components/
| | | |_ Core/
| | | |_ Platform/
| | | |_ System/
| | | |_ Tools/ Pre-compiled or scripted tools
| | |_ Esp32/
| | | |_ ...
| | |_ Host/
| | |_ ...
| |_ Components/ Framework support code, not to be used directly by applications
| |_ Core/ Main framework core
| |_ Libraries/ Arduino Libraries
| | |_ ...
| |_ out/ All generated shared files are written here
| | |_ Esp8266/ The Arch
| | | |_ debug/ The build type
| | | |_ build/ Intermediate object files
| | | | |_ Lib/ Generated libraries
| | | | |_ tools/ Generated tools
| | | |_ release/
| | | |_ ...
| | |_ Host/
| | |_ ...
| |_ Platform/ System-level classes
| | |_ ...
| |_ Services/ Modules not considered as part of Core
| | |_ ...
| |_ System/ Common framework low-level system code
| | |_ include/
| |_ Wiring/
| |_ ...
|_ tests/ Integration test applications
|_ ...
A typical Project looks like this:
|_ Basic_Blink/
|_ Makefile Just includes project.mk
|_ component.mk Project-specific definitions
|_ app/ Default application source directory
|_ include/ Default application include directory
|_ out/ All generated shared files are written here
|_ Esp8266/ The Architecture
| |_ debug/ The build type
| | |_ build/ Intermediate object files
| | |_ firmware/ Target output files
| | |_ lib/ Generated libraries
| | |_ tools/ Generated tools
| |_ release/
| |_ ...
|_ Host
|_ ...
Component¶
The purpose of a Component is to encapsulate related elements for selective inclusion in a project, for easy sharing and re-use:
- Shared Library with associated header files
- App Code Source files to be compiled directly into the user’s project
- Header files without any associated source or library
- Build targets to perform specific actions, such as flashing binary data to hardware
By default, a Component is built into a shared library using any source
files found in the base or src
directories. All Arduino Libraries
are built as Components. Note that the application is also built as a
Component library, but the source directory defaults to app
instead
of src
.
Components are referred to simply by name, defined by the directory in
which it is stored. The Component itself is located by looking in all
the directories listed by COMPONENT_SEARCH_DIRS
, which contains a
list of repositories. (Every sub-directory of a repository is considered
to be a Component.) If there are Components with the same name in
different search directories, the first one found will be used.
Components are customised by providing an optional component.mk
file.
You can see details of all Components used in a project using
make list-components
. Add V=1
to get more details.
Note that the application itself is also built as a Component, and may be configured in a similar way to any other Component.
Library variants¶
Libraries can often be built using different option settings, so a mechanism is required to ensure that libraries (including the application) are rebuilt if those settings change. This is handled using variants, which modifies the library name using a hash of the settings values. Each variant gets its own build sub-directory so incremental building works as usual.
There are several types of config variable:
Variable type | Cached? | Rebuild Component? | Rebuild application ? | Relink application |
---|---|---|---|---|
COMPONENT | Y | Y | Y | Y |
CONFIG | Y | N | Y | Y |
RELINK | Y | N | N | Y |
CACHE | Y | N | N | N |
DEBUG | N | N | N | N |
Variables are usually defined in the context of a Component, in the component.mk file. All Components see the full configuration during building, not just their own variables.
The type of a configuration variable is defined by adding its name to one of the following lists:
-
CONFIG_VARS
¶ The Application library derives its variant from these variables. Use this type if the Component doesn’t require a rebuild, but the application does.
-
COMPONENT_VARS
¶ A Component library derives its variant from these variables. Any variable which requires a rebuild of the Component library itself must be listed. For example, the
esp-open-lwip
Component defines this asENABLE_LWIPDEBUG ENABLE_ESPCONN
. The default values for these producesENABLE_LWIPDEBUG=0 ENABLE_ESPCONN=0
, which is hashed (using MD5) to producea46d8c208ee44b1ee06f8e69cfa06773
, which is appended to the library name.All dependent Components (which list this one in
COMPONENT_DEPENDS
) will also have a variant created.
-
COMPONENT_RELINK_VARS
¶ Behaves just like
COMPONENT_VARS
except dependent Components are not rebuilt. This is appropriate where the public interface (header files) are not affected by the variable setting, but the library implementation still requires a variant.
-
RELINK_VARS
¶ Code isn’t re-compiled, but libraries are re-linked and firmware images re-generated if any of these variables are changed. For example,
make RBOOT_ROM_0=new-rom-file
rewrites the firmware image using the given filename. (Also, as the value is cached, if you then domake flashapp
that same iamge gets flashed.)
-
CACHE_VARS
¶ These variables have no effect on building, but are cached. Variables such as
COM_SPEED_ESPTOOL
fall into this category.
-
DEBUG_VARS
¶ These are generally for information only, and are not cached (except for
SMING_ARCH
andSMING_RELEASE
).
Note that the lists not prefixed COMPONENT_xx
are global and so should only
be appended, never assigned.
Dependencies¶
COMPONENT_DEPENDS
identifies a list of Components upon which this
one depends. These are established as pre-requisites so will trigger a
rebuild. In addition, all dependent COMPONENT_VARS
are (recursively)
used in creation of the library hash.
For example, the axtls-8266
Component declares SSL_DEBUG
as a
COMPONENT_VAR
. Because Sming
depends on sming-arch
, which in
turn depends on axtls-8266
, all of these Components get rebuilt as
different variants when SSL_DEBUG
changes values. The project code
(App
Component) also gets rebuilt as it implicitly depends on Sming
.
GIT Submodules¶
Sming uses source code from other repositories. Instead of including local copies, these are handled using GIT submodules. Where changes are required, patches may be provided as a diff .patch file and/or set of files to be added/replaced. Only those submodules necessary for a build are pulled in, as follows:
- The submodule is fetched from its remote repository
- If a .patch file exists, it is applied
- Any additional files are copied into the submodule directory
- An empty
.submodule
file is created to tells the build system that the submodule is present and correct.
The patch file must have the same name as the submodule, with a .patch extension. It can be located in the submodule’s parent directory:
|_ Components/
|_ heap/
|_ .component.mk Component definition
|_ umm_malloc.patch Diff patch file
|_ umm_malloc/ Submodule directory
|_ .submodule Created after successful patching
...
However, if the Component is itself a submodule, then patch files must
be placed in a ../.patches
directory:
|_ Libraries/
|_ .patches/
| |_ Adafruit_SSD1306.patch Diff patch file
| |_ Adafruit_SSD1306/
| |_ component.mk This file is added to submodule
|_ Adafruit_SSD1306/ The submodule directory
|_ .submodule Created after successful patching
...
This example includes additional files for the submodule. There are some advantages to this approach:
- Don’t need to modify or create .patch
- Changes to the file are easier to follow than in a .patch
- IMPORTANT Adding a component.mk file in this manner allows the build system to resolve dependencies before any submodules are fetched.
In the above example, the component.mk
file defines a dependency on
the Adafruit_GFX
library, so that will automatically get pulled in
as well.
Component configuration¶
The component.mk
is parsed twice, first from the top-level makefile
and the second time from the sub-make which does the actual building. A
number of variables are used to define behaviour.
These values are for reference only and should not be modified.
-
COMPONENT_NAME
¶ Name of the Component
-
COMPONENT_PATH
¶ Base directory path for Component, no trailing path separator
-
COMPONENT_BUILD_DIR
¶ The current directory.
This should be used if the Component provides any application code or targets to ensure it is built in the correct directory (but not by this makefile).
-
COMPONENT_LIBDIR
¶ Location to store created Component (shared) libraries
-
COMPONENT_VARIANT
¶ Name of the library to build
-
COMPONENT_LIBPATH
¶ Full path to the library to be built
These values may be used to customise Component behaviour and may be changed as required.
-
COMPONENT_LIBNAME
¶ By default, the library has the same name as the Component but can be changed if required. Note that this will be used as the stem for any variants.
Set
COMPONENT_LIBNAME :=
if the Component doesn’t create a library. If you don’t do this, a default library will be built but will be empty if no source files are found.
-
COMPONENT_TARGETS
¶ Set this to any additional targets to be built as part of the Component, prefixed with
$(COMPONENT_RULE)
.If targets should be built for each application, use
CUSTOM_TARGETS
instead. See SPIFFS for Sming for an example.
-
COMPONENT_RULE
¶ This is a special value used to prefix any custom targets which are to be built as part of the Component. The target must be prefixed by
$(COMPONENT_RULE)
without any space between it and the target. This ensures the rule only gets invoked during a component build, and is ignored by the top-level make.
-
COMPONENT_SUBMODULES
¶ Relative paths to dependent submodule directories for this Component. These will be fetched/patched automatically before building.
-
COMPONENT_SRCDIRS
¶ Locations for source code relative to COMPONENT_PATH (defaults to “. src”)
-
COMPONENT_INCDIRS
¶ Default: “include”.
Include directories available when building ALL Components (not just this one). Paths may be relative or absolute
-
EXTRA_INCDIR
¶ Include directories for just this Component. Paths may be relative or absolute
-
INCDIR
¶ The resultant set of include directories used to build this Component. Will contain include directories specified by all other Components in the build. May be overridden if required.
-
COMPONENT_APPCODE
¶ List of directories containing source code to be compiled directly with the application. (Ignore in the project.mk file - use
COMPONENT_SRCDIRS
instead).
-
CUSTOM_BUILD
¶ Set to 1 if providing an alternative build method. See Custom building section.
-
EXTRA_OBJ
¶ Absolute paths to any additional binary object files to be added to the Component archive library.
-
COMPONENT_DEPENDS
¶ Set to the name(s) of any dependent Components.
-
EXTRA_LIBS
¶ Set to names of any additional libraries to be linked.
-
EXTRA_LDFLAGS
¶ Set to any additional flags to be used when linking.
-
COMPONENT_PYTHON_REQUIREMENTS
¶ If the component requires uncommon Python modules (e. g. as part of a custom build step), set this variable to one or more requirements.txt files. This allows installation of all python requirements of the project by invoking:
make python-requirements [PIP_ARGS=...]
Note
A requirements.txt file in the root directory of the Component is detected automatically without setting this variable. To prevent autodetection (e.g. if the python requirements depend on another configuration variable) you must set this variable to an empty value.
These values are global so must only be appended to (with +=
) ,
never overwritten.
-
CUSTOM_TARGETS
¶ Identifies targets to be built along with the application. These will be invoked directly by the top-level make.
-
GLOBAL_CFLAGS
¶ Use only if you need to provide additional compiler flags to be included when building all Components (including Application) and custom targets.
-
APP_CFLAGS
¶ Used when building application and custom targets.
-
COMPONENT_CFLAGS
¶ Will be visible ONLY to C code within the component.
-
COMPONENT_CXXFLAGS
¶ Will be visible ONLY to C++ code within the component.
Important
During initial parsing, many of these variables (specifically, the
COMPONENT_xxx
ones) do not keep their values. For this reason it
is usually best to use simple variable assignment using :=
.
For example, in Esp8266/Components/gdbstub
we define
GDB_CMDLINE
. It may be tempting to do this:
GDB_CMDLINE = trap '' INT; $(GDB) -x $(COMPONENT_PATH)/gdbcmds -b $(COM_SPEED_GDB) -ex "target remote $(COM_PORT_GDB)"
That won’t work! By the time GDB_CMDLINE
gets expanded,
COMPONENT_PATH
could contain anything. We need GDB_CMDLINE
to be
expanded only when used, so the solution is to take a simple copy of
COMPONENT_PATH
and use it instead, like this:
GDBSTUB_DIR := $(COMPONENT_PATH)
GDB_CMDLINE = trap '' INT; $(GDB) -x $(GDBSTUB_DIR)/gdbcmds -b $(COM_SPEED_GDB) -ex "target remote $(COM_PORT_GDB)"
These values are global and should be used ONLY in the Sming/Arch/*/build.mk
files to tune the architecture compilation flags.
These values must only be appended to (with +=
), never overwritten.
-
CPPFLAGS
¶ Used to provide both C and C++ flags that are applied globally.
-
CFLAGS
¶ Used to provide ONLY C flags that are applied globally.
-
CXXFLAGS
¶ Used to provide ONLY C++ flags that are applied globally.
-
SMING_C_STD
¶ Used to provide the C language standard. The default is
c11
.
Important
Do NOT set CPPFLAGS
, CFLAGS
and CXXFLAGS
outside of the Sming/Arch/*/build.mk
files.
Building¶
For faster builds use make with the -j
(jobs) feature of make. It is
usually necessary to specify a limit for the number of jobs, especially
on virtual machines. There is usually no point in using a figure greater
than (CPU cores + 1). The CI builds use -j3
.
Note that Makefile-app.mk
enforces sequential building to ensure
submodules are fetched and patched correctly. This also ensures that
only one Component is built at a time which keeps the build logs quite
clean and easy to follow.
Components can be rebuilt and cleaned individually. For example:
make spiffs-build
runs the Component ‘make’ for spiffs, which contains the spiffs library and spiffy tool.make spiffs-clean
removes all intermediate build files for the Componentmake spiffs-rebuild
cleans and then re-builds the Component
By default, a regular make
performs an incremental build on the
application, which invokes a separate (recursive) make for the App
Component. All other Components only get built if any of their targets
don’t exist (e.g. variant library not yet built). This makes application
building faster and less ‘busy’, which is generally preferable for
regular application development. For Component development this
behaviour can be changed using the FULL_COMPONENT_BUILD
variable
(which is cached). Examples:
make FULL_COMPONENT_BUILD=lwip
will perform an incremental build on thelwip
Componentmake FULL_COMPONENT_BUILD=1
will incrementally build all Components
Custom Building¶
To use an external makefile or other build system (such as CMake) to
create the Component library, or to add additional shared libraries or
other targets, customise the component.mk
file as follows:
- Set
CUSTOM_BUILD=1
- Define the custom rule, prefixed with
$(COMPONENT_RULE)
. Note that Components are built using a separate make instance with the current directory set to the build output directory, not the source directory.
It is important that the rule uses the provided values for
COMPONENT_LIBNAME
, COMPONENT_LIBPATH
and COMPONENT_LIBDIR
so
that variant building, cleaning, etc. work correctly. See below under
‘Building’, and the Host lwip
Component for an example.
Components are built using a make instance with the current directory set to the build output directory, not the source directory. If any custom building is done then these variables must be obeyed to ensure variants, etc. work as expected:
COMPONENT_LIBNAME
as provided by component.mk, defaults to component
name, e.g. Sming
COMPONENT_LIBHASH
hash of the component
variables used to create unique library names,
e.g. 13cd2ddef79fda79dae1644a33bf48bb
COMPONENT_VARIANT
name
of the library to be built, including hash.
e.g. Sming-13cd2ddef79fda79dae1644a33bf48bb
COMPONENT_LIBDIR
directory where any generated libraries must be output,
e.g. /home/user/sming/Sming/out/Esp8266/debug/lib/
COMPONENT_LIBPATH
full path to the library to be created,
e.g. /home/user/sming/Sming/out/Esp8266/debug/lib/clib-Sming-13cd2ddef79fda79dae1644a33bf48bb.a
COMPONENT_BUILDDIR
where to write intermediate object files,
e.g. /home/user/sming/Sming/out/Esp8266/debug/build/Sming/Sming-13cd2ddef79fda79dae1644a33bf48bb
Porting existing libraries¶
to be completed
Known Issues¶
Cleaning Components are not cleaned unless defined.
e.g. make axtls-8266-clean
will fail unless you also specify
ENABLE_SSL=1
.
Empty libraries Components without any source code produce an empty library. This is because, for simplicity, we don’t want to add a component.mk to every Arduino library.
Empty Component directories Every sub-directory in the
COMPONENT_SEARCH_DIRS
is interpreted as a Component. For example,
spiffs
was moved out of Arch/Esp8266/Components but if an empty
directory called ‘spiffs’ still remains then it will be picked up
instead of the main one. These sorts of issues can be checked using
make list-components
to ensure the correct Component path has been
selected.
Components as submodules All component.mk files must be available for parsing. For submodules, it can be provided in a .patch/ sub-directory.
Multitasking¶
Pre-emptive Multitasking¶
Modern computers have evolved so that you can write a program and it will (mostly) run without interfering with anything else that is also running.
With multiple CPUs tasks can actually run at the same time (concurrently), but as there are always many more threads (tasks) these have to be shared. This is especially true on older systems which only have a single CPU.
The OS does this using a mechanism called Pre-emptive Multitasking. As far as your program is concerned, it just runs without any apparent interruptions, but in reality it only gets a little ‘slice’ of time before the operating system forceably switches to a different program and lets it run for another ‘slice’ of time. (Hence the term, time slicing.)
With pre-emptive multitasking the operating system has to maintain state for every single task that is active. This requires additional RAM.
There is also the overhead of switching between tasks. Each task also requires its own stack space so there is usually more restriction on how it is used.
FreeRTOS is perhaps the most well-known example of a pre-emptive embedded OS.
Co-operative Multitasking¶
By constrast, Co-operative Multitasking, requires applications to ‘play fair’ and not hog the CPU. This means that whenever you get called to do some work, you must release control back to the system in a timely manner.
This technique is well-suited to resource-limited systems such as the Esp8266.
The Esp8266 has only a single CPU, and relatively limited RAM; about 50KBytes is available for application use. The heap grows from the bottom of RAM, and the stack starts at the top.
Sming uses the ESP8266 Non-OS SDK, which manages much of the low-level system control including the WiFi stack. It contains the main control loop, which in pseudo-code goes something like this:
for(;;) {
ServiceWifi();
ServiceTimers();
ServiceTasks();
FeedWatchdog();
}
Application code gets called from there in response to a network request, or a timer that you’ve set up, and you must deal with the request and return promptly to allow things to continue.
If you don’t do this, the system will very likely behave erratically and suffer from dropped WiFi connections and poor responsiveness. In extreme cases, the system will reset as a self-defence mechanism via Watchdog Timer; If it didn’t do this, the device would remain unresponsive until physically reset, which is generally a bad thing for an embedded device!
Attention
Although there are functions available to manually reset watchdog timers, you should endeavour to avoid doing this from application code unless absolutely necessary.
Events¶
Introduction¶
The Sming framework has an event-driven architecture. In other words, we need to think of our application as performing some action in response to an event, input or stimulus.
Software events¶
Let’s look at the Basic Blink sample. We define a couple of global variables:
Timer procTimer;
bool state = true;
The one to note is procTimer, which is a software timer (see Timers and Clocks).
The startup entry point for a Sming application is the init()
function:
void init()
{
pinMode(LED_PIN, OUTPUT);
procTimer.initializeMs(1000, blink).start();
}
This sets up a repeating timer, so that every 1000ms the blink function gets called:
void blink()
{
digitalWrite(LED_PIN, state);
state = !state;
}
Note that what we don’t do is sit in a loop waiting for something to happen.
Interrupt events¶
The Basic Interrupts sample can be summarised as follows:
We have a button connected to GPIO0 as an input
Button pressed - Hardware interrupt on GPIO0
- Change output state of LED via GPIO2
There are two ways we can determine when the state of our GPIO0 pin changes:
- Polling
- We read the input very quickly and compare the current value with the previous value, which we keep a note of. Our event occurs when the value changes, or if the input goes HIGH, or LOW, etc.
- Interrupt
- If we need to catch fast pulses then polling may not work as the CPU might be doing something else and we’ll miss it. So instead, we’ll get the hardware to monitor the input for us and generate an event when it changes.
Both techniques have advantages and disadvantages, and interrupts are certainly not appropriate in all situations.
Bear in mind that every time an interrupt occurs the CPU has to stop executing your regular program, save any critical registers then jump to the interrupt service routine to run your code. All this takes time, so if the input changes very fast and very frequently then it can consume a lot of CPU and make the system very sluggish (or even crash it).
Callbacks¶
In Sming, we generally register a callback function to be invoked when an event occurs, such as if a timer expires.
This can be a regular ‘C’ callback function, which you should use for handling interrupts.
For regular application code, a Delegate
provides more flexbility and allows you to create
simpler, cleaner code. See Delegation
for a bit of background.
The Basic Delegates sample shows how to use various types of callback.
One common requirement is to use a class method as a callback, which is easily done using Delegates.
This flexibility comes at a cost, however:
- Speed. They are slower than their regular C-function counterparts
- Memory. Some calls may use the heap in the background.
These are the main reasons why you should not use Delegates in an interrupt context.
See Pull Request #1734 for some further details about the relative speeds.
Memory¶
Memory Types¶
The ESP8266 has several types of memory, and it is important to have a basic apprecation of what they are and how they’re used.
DRAM¶
Data RAM where variables, etc. are stored. Contains the stack (which starts at the top of RAM) and the heap (which starts near the bottom, after any static data).
IRAM¶
Instruction RAM. All code executes from here, but there’s not much of it so so only parts of your application are loaded at any one time. This caching happens in the background by mapping certain memory address ranges into physical flash locations.
If a location is accessed which is already in the cache (a ‘hit’) then the access runs at full RAM speed. If it’s not in the cache (a ‘miss’) then an interrupt (exception) is generated internally which performs the flash read operation.
This is why interrupt service routines must not access PROGMEM directly, and must
be marked using IRAM_ATTR
to ensure it’s always available.
You may get a performance improvement using IRAM_ATTR
, but as frequently-used
code will be cached anyway it won’t necessarily run faster.
If the code is timing critical it may benefit from pre-caching. See Esp8266 SPI Flash Support.
Flash¶
Main storage for your application, libraries, the Espressif SDK code, etc. Flash memory is accessed via external serial bus and is relatively slow. For the ESP8266, it’s approximately 12x slower, though this only applies on cache misses.
See Flash memory for further details.
ROM¶
Fixed code stored in the Esp8266 itself containing very low-level support code which is factory-programmed and cannot be changed.
Initialisation¶
At startup, only the non-volatile Flash and ROM memories contain anything useful, whilst DRAM and IRAM will probably just contain garbage. The Arduino platform was initially designed to work with much simpler hardware, where the program was executed directly from Flash memory on hardware reset.
BIOS¶
The ESP8266 and ESP32 are far more complex, and most of the low-level initialisation happens in the ROM code. The ROM essentially contains the systems BIOS, with various low-level routines which may be used instead of accessing hardware directly. It is also responsible for setting up memory caching.
Runtime libraries¶
Control is passed to runtime libraries provided by Espressif, stored in Flash memory. Both ROM and runtime code are closed-source and not generally available for inspection, though disassemblies do exist.
Boot loader¶
The first point we really see what’s going on is in the bootloader (rBoot). The bootloader identifies the correct program image (as there can be more than one), loads the starting portion into IRAM and jumps there. It also configures the caching mechanism so that the correct program image is loaded. You can find more details about this in the rBoot documentation.
Memory initialisation¶
Code is copied from flash into IRAM, and const data copied into DRAM. Also static and global variable values are initialised from tables stored in flash. Static and global variables without an initialised value are initialised to 0.
Sming initialisation¶
{todo}.
ESP8266 flash memory sizes vary from 512Kbytes on the ESP-01 up to 4Mbytes on the ESP12F. Up to 16MBytes are supported for custom designs.
You can find general details for the memory layout in the ESP8266 Wiki.
This is the layout for Sming with a 4MByte flash device:
Address | Config variable | Size | Source filename | Description |
---|---|---|---|---|
(hex) | (if any) | (KB) | (if applicable) | |
000000 | 1 | rboot.bin | Boot loader | |
001000 | 4 | rBoot configuration | ||
002000 | ROM_0_ADDR | rom0.bin | First ROM image | |
100000 | RBOOT_SPIFFS_0 | |||
202000 | ROM_1_ADDR | rom1.bin | Second ROM image | |
300000 | RBOOT_SPIFFS_1 | |||
3FB000 | 4 | blank.bin | RF Calibration data (Initialised to FFh) | |
3FC000 | 4 | esp_init_data_default.bin | PHY configuration data | |
3FD000 | 12 | blank.bin | System parameter area |
{ todo }
Whilst SDK version 3 requires a partition table, previous versions do not but this can be added so that we can use it as a common reference for all the above locations.
Flash memory on the ESP8266 is accessed via an external SPI bus, so reading it takes about 12x longer than reading from internal RAM. To mitigate this, some of the internal RAM is used to cache data. Part of this is managed in hardware, which means if the data required is already in the cache then there is no difference in speed. In general, then, frequently accessed data is read as if it were already in RAM.
Bear in mind that every time new data is read via the cache, something else will get thrown away
and have to be re-read. Therefore, if you have large blocks of infrequently accessed data then
it’s a good idea to read it directly using flashmem_read()
. You can get the address for a
memory location using flashmem_get_address()
.
See Program Space for details of how to store data in flash, and access it.
Strings¶
Sming provides three classes to deal with string content:
- Wiring String for flexible RAM string handling
- CStringArray for handling small strings lists
- Flash Strings for storing and handling strings stored in flash memory
Interrupts¶
Rules¶
Normal code runs in a Task context, that is to say there are no particular restrictions on what functions can be called. Sming is a single-threaded framework, so all tasks execute sequentially.
However, there are some rules you need to follow when writing code which runs in an interrupt context:
- Use
IRAM_ATTR
attribute on the interrupt handler - Don’t call any code which isn’t in IRAM, or marked with
__forceinline
. Note:inline
by itself is just a compiler ‘hint’ and there is no guarantee the code will actually be inlined. - Keep the code as brief as possible
- Don’t use the heap (malloc, free, new, etc.). Buffers, etc. must be pre-allocated in task context.
- Put processing code into a separate function and add to the task queue
SystemClass::queueCallback()
, or use aSimpleTimer
orTimer
. - Be wary if using
Delegate
callbacks as the compiler may need to use the heap, if parameter lists do not match. For this reason, avoid capturing lambdas and method callbacks. If in doubt, stick with regular ‘C’ function pointers as defined by theInterruptCallback
type.
Contact bounce¶
If you use a jumper wire to ground the input pin (or even a proper switch) then it will bounce around as contact is made and then broken. This means you’ll get multiple outputs instead of a clean signal, which will cause havoc with interrupt handlers.
One solution is to use a ‘debounce circuit’, which can be as simple as this:
3v3
_|_
___ 100nF
|
|
INPUT >--------------> GPIO PIN
Provided pull-ups are enabled on the GPIO, this is sufficient to slow the input.
An alternative solution is to poll the input instead. See Tasks.
Tasks¶
Introduction¶
If you need to perform any kind of background processing task, then you will need to consider how to break it up so it executes in small slices to allow other system functions to continue normally.
You can use callback timers to schedule periodic tasks, but if you simply need to run the task as soon as possible you should use the Task Queue.
Task Schedulers¶
At present Sming doesn’t provide any structured (class-based) support for task scheduling, however there are various scheduling libraries available for Arduino.
These are quite simple and generic:
This one is rather more complex:
Using a scheduler is a powerful technique which allows the programmer to focus on the task at hand, rather than how to get it to run.
Debugging¶
Debugging is a powerful technique allowing you to interactively run your code and be able to see much more information about the things that went wrong.
Architectures¶
Debugging on the supported architectures requires the installation and initial setup of different debugging tools. The links below will give you more information and step-by-step instructions.
Debugging on Host¶
A GNU C/C++ debugger is the only requirement for the Host architecture. Make sure that you have the following executable in your PATH:
gdb
No additional hardware is required.
In order to debug applications based on Sming Framework make sure that you are using Sming version 3.8.0 or newer.
If you want to debug your application and the Sming Framework code make sure to
(re)compile it with ENABLE_GDB
=1 directive:
cd $SMING_HOME/../samples/LiveDebug
make dist-clean
make ENABLE_GDB=1
The commands above will re-compile Sming with debug symbols and optimizations for debugging. These commands need to be executed once.
You can recompile Sming with the following directives to debug better Sming and the LWIP TCP/IP stack
cd $SMING_HOME/../samples/LiveDebug
make Sming-build all ENABLE_GDB=1 ENABLE_LWIPDEBUG=1
To use, (re)compile your application with the ENABLE_GDB option and flash it to the board. For this example we will use the Live Debug sample application:
cd $SMING_HOME/../samples/LiveDebug
make clean
make ENABLE_GDB=1 # -- recompiles your application with debugging support
The next step is to start the debugger. This can be done with the command below:
make gdb
After that a new interactive debugging session will be started:
Welcome to SMING!
Type 'r' to run application
To start the execution of the application type r or run:
(gdb) r
Starting program: /x/Sming/samples/LiveDebug/out/Host/debug/firmware/app --flashfile=out/Host/debug/firmware/flash.bin --flashsize=4M --pause
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
[New Thread 0xf7bdcb40 (LWP 16428)]
Welcome to the Sming Host emulator
host_flashmem_init: Created blank "out/Host/debug/firmware/flash.bin", 4194304 bytes
...
main: >> Starting Sming <<
You can pause the program execution by pressing Ctrl-C. And work further using some further GDB commands. The next paragraph describes some of them.
There are multiple commands supported in GDB and we will mention only some of them.
One possibility is to see the source code of the current line where the
execution has stopped. To achieve this you should type list
in the gdb
console:
(gdb) list
102 }
103 }
104
105 int main(int argc, char* argv[])
106 {
107 trap_exceptions();
108
109 host_printf("\nWelcome to the Sming Host emulator\n\n");
110
111 static struct {
This command will pause the debugger once it reaches a specific function
or line in the code. This is called breakpoint
and can be set like this:
(gdb) break blink
Breakpoint 1 at 0x40105d4c: file app/application.cpp, line 66.
To continue the execution of the application we can use the continue
command:
(gdb) continue
Continuing.
Breakpoint 1, blink () at app/application.cpp:66
66 {
(gdb)
Because we have set already a breakpoint for the blink
function the
execution will be paused when the blink
function is reached and from
here you can go to the next line or see the current values of the
variables.
A good visualization helps us understand things faster. What we can do is use Eclipse CDT and its debugging plugins to do remote debugging as we did from the command line.
Here is how this can be done:
- Start Eclipse CDT and import the Live Debug sample:
- Select File -> New -> Project -> C/C++ -> Makefile Project with Existing Code
- Point Eclipse to the location of the LiveDebug sample
- Import the Sming Framework (if you haven’t done it yet)

Import Project
Once the two projects are in Eclipse, set the LiveDebug project to reference the Sming project.
Now create a new Debugging Configuration:
- Select Run -> Debug Configurations -> C/C++ Application
- Right-click and create a new C/C++ Application
- In the Main tab set, set:
- Project: Basic_Build
- C/C++ Application: out/Host/debug/firmware/app
- disable for now the auto build

C/C++ Application
Then go to the Debugger tab and point the GDB debugger to your
gdb binary. (Type make list-config
and look for GDB
.)

Debugger configuration
We are now ready for debugging. Press the Debug button. (In the screenshot above the Debug button is in the bottom-right corner.) After some seconds your debugging session should be up and running and you can enjoy live debugging.

Live Debugging Session
You will be able to see the current variables and their values. You should be able to go step by step, go inside of functions, add add breakpoints and watchpoints.
Debugging on ESP8266¶
A debugger is the only requirement for ESP8266. It is usually part of the provided toolchain. Make sure that you have the following executable in your PATH:
xtensa-lx106-elf-gdb
No additional hardware is required (Apart from a standard USB-to-UART adapter).
In order to debug applications based on Sming Framework make sure that you are using Sming version 3.8.0 or newer.
If you want to debug inside of the Sming Framework make sure to
(re)compile it with ENABLE_GDB
=1 directive:
cd $SMING_HOME
make dist-clean
make ENABLE_GDB=1
The commands above will re-compile Sming with debug symbols and optimizations for debugging. These commands need to be executed once.
To use, (re)compile your application with the ENABLE_GDB option and flash it to the board. For this example we will use the Live Debug sample application:
cd $SMING_HOME/../samples/LiveDebug
make clean
make ENABLE_GDB=1 # -- recompiles your application with debugging support
make flashapp # flashes ONLY the (re)compiled application
The device will restart then wait for a debugger to be connected:
make gdb
This will start a new debugging session where you can run your code interactively:
Remote debugging using /dev/ttyUSB0
gdbstub_init () at /home/slavey/dev/esp8266.dev.box/dev/Sming/Sming//gdb/gdbstub.cpp:914
914 gdb_do_break();
(gdb)
If the debugger is exited, the application will continue execution as normal. Re-connecting the debugger will pause execution.
There are multiple commands supported in GDB and we will mention only some of them.
One possibility is to see the source code of the current line where the
execution has stopped. To achieve this you should type list
in the gdb
console:
(gdb) list
909 SD(GDBSTUB_ENABLE_HOSTIO);
910 #undef SD
911
912 #if GDBSTUB_BREAK_ON_INIT
913 if(gdb_state.enabled) {
914 gdb_do_break();
915 }
916 #endif
917 }
918
This command will pause the debugger once it reaches a specific function
or line in the code. This is called breakpoint
and can be set like this:
(gdb) break blink
Breakpoint 1 at 0x40105d4c: file app/application.cpp, line 66.
Notice: break
sets a software breakpoint. This means that the
blink
function must be in IRAM. Otherwise the execution will fail.
If you take a look at samples/LiveDebug/app/application.cpp#L663,
you will see a in the definition of the init
function the following
attribute GDB_IRAM_ATTR
:
void GDB_IRAM_ATTR init()
This attribute is used to put the init
function in IRAM when the
code is compiled with the ENABLE_GDB=1
directive.
To continue the execution of the application we can use the continue
command:
(gdb) continue
Continuing.
LiveDebug sample
Explore some capabilities of the GDB debugger.
[OS] mode : sta..
...
[OS] cnt
Breakpoint 1, blink () at app/application.cpp:66
66 {
(gdb)
Because we have set already a breakpoint for the blink
function the
execution will be paused when the blink
function is reached and from
here you can go to the next line or see the current values of the
variables.
A good visualization helps us understand things faster. What we can do is use Eclipse CDT and its debugging plugins to do remote debugging as we did from the command line.
Here is how this can be done:
- Start Eclipse CDT and import the Live Debug sample:
- Select File -> New -> Project -> C/C++ -> Makefile Project with Existing Code
- Point Eclipse to the location of the LiveDebug sample
- Import the Sming Framework (if you haven’t done it yet)

Import Project
Once the two projects are in Eclipse, set the LiveDebug project to reference the Sming project.
Now create a new Remote Debugging Configuration:
- Select Run -> Debug Configurations -> C/C++ Remote Application
- Right-click and create a new C/C++ Remote Application
- In the Main tab set, set:
- Project: Basic_Build
- C/C++ Application: out/build/Esp8266/Debug/app.out
- disable for now the auto build

Remote Debugging Session
Then go to the Debugger tab and point the GDB debugger to your
Xtensa-gdb binary. (Type make list-config
and look for GDB
.)

Remote Debugging Session
Make sure to load also GDB command file. To find out its location, run make list-config
and look for GDBSTUB_DIR
. The file is called gdbcmds
, and you may wish to place
a copy of the file somewhere else, especially if you intend to modify it.
You can see the file here Sming/Arch/Esp8266/Components/gdbstub/gdbcmds.
Finally we should configure the remote connection. Go to the Debugger -> Connection tab and set:
- type: Serial
- device: /dev/ttyUSB0 (or as required for your operating system)
- speed: 115200

Set remote connection
We are now ready for debugging. Press the Debug button. (In the screenshot above the Debug button is in the bottom-right corner.) After some seconds your debugging session should be up and running and you can enjoy live debugging.

Live Debugging Session
You will be able to see the current variables and their values. You should be able to go step by step, go inside of functions, add breakpoints to code in RAM or add breakpoints to code that was in FLASH, after it was executed executed at least once.
Debugging on ESP32¶
A debugger and a JTAG hardware are required. The debugger is part of the provided toolchain. Make sure that you have the following executable in your PATH:
xtensa-esp32-elf-gdb
Debugging with JTAG is explained in details in the ESP-IDF documentation. Make sure to read it carefully.
For the purposes of this documentation we will be using ESP-Prog JTAG adapter and ESP32-Cam microcontroller from AI-Thinker.
The JTAG adapter has to be connected to your ESP32 microcontroller. The following pins from the JTAG adapter have to be connected to ESP32 for the communication to work.
ESP32 Pin JTAG Signal 1 VCC VCC 2 MTDO / GPIO15 TDO 3 MTDI / GPIO12 TDI 4 MTCK / GPIO13 TCK 5 MTMS / GPIO14 TMS 6 GND GND
Once the JTAG adapter is connected to the microcontroller and to a computer we have to start the OpenOCD server that will communicate with the JTAG adapter. For our specific hardware the following command has to be executed:
openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
If you have configured your JTAG adapter correctly the following messages should show up:
Open On-Chip Debugger v0.10.0-esp32-20190313 (2019-03-13-09:52)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 20000 kHz
Info : Configured 2 cores
esp32 interrupt mask on
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
Info : clock speed 20000 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x0F).
Info : Detected debug stubs @ 3ffb42ac on core0 of target 'esp32'
Info : Listening on port 3333 for gdb connections
Info : accepting 'gdb' connection on tcp/3333
In order to debug applications based on Sming Framework make sure that you are using Sming version 3.8.0 or newer.
If you want to debug your application and the Sming Framework code make sure to
(re)compile it with ENABLE_GDB
=1 directive:
cd $SMING_HOME/../samples/Basic_Blink
make dist-clean
make ENABLE_GDB=1
The commands above will re-compile Sming with debug symbols and optimizations for debugging. These commands need to be executed once.
To use, (re)compile your application with the ENABLE_GDB option and flash it to the board. For this example we will use the Basic Blink sample application:
cd $SMING_HOME/../samples/Basic_Blink
make clean
make ENABLE_GDB=1 # -- recompiles your application with debugging support
make flashapp # flashes ONLY the (re)compiled application
The device will restart then wait for a debugger to be connected. Before starting the debugger you must be sure that the OpenOCD server is running and listening for incoming connections on localhost port 3333. Now start the debugger with the command below
make gdb
This will start a new debugging session. The debugger will try to connect to OpenOCD server and in the OpenOCD logs you should see a message similar to the one below:
Info : accepting 'gdb' connection on tcp/3333
Info : Target halted. PRO_CPU: PC=0x4012F7EE (active) APP_CPU: PC=0x4012F7EE
Info : Target halted. PRO_CPU: PC=0x4009171A (active) APP_CPU: PC=0x4012F7EE
Info : Flash mapping 0: 0x10020 -> 0x3f400020, 89 KB
Info : Flash mapping 1: 0x30018 -> 0x400d0018, 388 KB
Info : Target halted. PRO_CPU: PC=0x4009171A (active) APP_CPU: PC=0x4012F7EE
Info : Auto-detected flash size 4096 KB
Info : Using flash size 4096 KB
And in the GDB console you will see a message similar to this one:
Reading symbols from out/Esp32/debug/build/app.out...done.
0x4012f7ee in is_wifi_clk_peripheral (periph=PERIPH_LEDC_MODULE)
at /x/esp-idf/components/driver/periph_ctrl.c:225
225 switch(periph) {
JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
esp32: Debug controller 0 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Core 0 was reset (pwrstat=0x5F, after clear 0x0F).
esp32: Debug controller 1 was reset (pwrstat=0x5F, after clear 0x5F).
esp32: Core 1 was reset (pwrstat=0x5F, after clear 0x5F).
Target halted. PRO_CPU: PC=0x5000004B (active) APP_CPU: PC=0x00000000
esp32: Core 0 was reset (pwrstat=0x1F, after clear 0x0F).
Target halted. PRO_CPU: PC=0x40000400 (active) APP_CPU: PC=0x40000400
Hardware assisted breakpoint 1 at 0x400e1cd3: file /x/Sming/Sming/Arch/Esp32/Components/esp32/startup.cpp, line 21.
(gdb)
If the debugger is exited, the application will continue execution as normal. Re-connecting the debugger will pause execution.
There are multiple commands supported in GDB and we will mention only some of them.
One possibility is to see the source code of the current line where the
execution has stopped. To achieve this you should type list
in the gdb
console:
(gdb) list
220
221 static bool is_wifi_clk_peripheral(periph_module_t periph)
222 {
223 /* A small subset of peripherals use WIFI_CLK_EN_REG and
224 CORE_RST_EN_REG for their clock & reset registers */
225 switch(periph) {
226 case PERIPH_SDMMC_MODULE:
227 case PERIPH_SDIO_SLAVE_MODULE:
228 case PERIPH_EMAC_MODULE:
229 case PERIPH_RNG_MODULE:
(gdb)
This command will pause the debugger once it reaches a specific function
or line in the code. This is called breakpoint
and can be set like this:
(gdb) break blink
Breakpoint 2 at 0x400e1dc4: file app/application.cpp, line 9.
To continue the execution of the application we can use the continue
command:
(gdb) continue
Continuing.
Target halted. PRO_CPU: PC=0x400E1DC4 (active) APP_CPU: PC=0x4012F7EE
[New Thread 1073483724]
[New Thread 1073514968]
[New Thread 1073494600]
[New Thread 1073487892]
[Switching to Thread 1073412944]
Breakpoint 1, blink () at app/application.cpp:9
9 {
(gdb)
Because we have set already a breakpoint for the blink
function the
execution will be paused when the blink
function is reached and from
here you can go to the next line or see the current values of the
variables.
A good visualization helps us understand things faster. What we can do is use Eclipse CDT and its debugging plugins to do remote debugging as we did from the command line.
Here is how this can be done:
- Start Eclipse CDT and import the Basic Blink sample:
- Select File -> New -> Project -> C/C++ -> Makefile Project with Existing Code
- Point Eclipse to the location of the Basic_Blink sample
- Import the Sming Framework (if you haven’t done it yet)

Import Project
Once the two projects are in Eclipse, set the Basic_Blink project to reference the Sming project.
Now create a new Remote Debugging Configuration:
- Select Run -> Debug Configurations -> C/C++ Remote Application
- Right-click and create a new C/C++ Remote Application
- In the Main tab set, set:
- Project: Basic_Build
- C/C++ Application: out/build/Esp8266/Debug/app.out
- disable for now the auto build

Remote Debugging Session
Then go to the Debugger tab and point the GDB debugger to your
Xtensa-gdb binary. (Type make list-config
and look for GDB
.)

Remote Debugging Session
Make sure to load also GDB command file. The file is called gdbinit
, and you may wish to place
a copy of the file somewhere else, especially if you intend to modify it.
You can see the file here Sming/Arch/Esp32/Tools/gdbinit.
Finally we should configure the remote connection. Go to the Debugger -> Connection tab and set:
- type: TCP
- host: localhost
- port: 3333

Set remote connection
We are now ready for debugging. Press the Debug button. (In the screenshot above the Debug button is in the bottom-right corner.) After some seconds your debugging session should be up and running and you can enjoy live debugging.

Live Debugging Session
You will be able to see the current variables and their values. You should be able to go step by step, go inside of functions, add breakpoints to code in RAM or add breakpoints to code that was in FLASH.
rBoot and OTA updates¶
Introduction¶
rBoot is an open source bootloader for the ESP8266, which is now fully integrated with Sming. rBoot is a more flexible alternative to the closed source bootloader supplied by Espressif with the SDK. A bootloader allows you to have more than one application on the esp8266, either completely different apps, or different version of the same app, which can be updated over the air.
The example Basic rBoot demonstrates the use of rBoot, but if you want to add it to an existing project this little tutorial will guide you.
Need to know¶
- The esp8266 can only memory map 1MB of flash at a time, your ROM must fit within the a single 1MB block of flash.
- Different 1MB blocks can be mapped at different times, so your ROM does not have to be within the first 1MB block. The support for this in rBoot is called big flash mode. A single compiled and linked ROM image can be placed at the same relative position in any 1MB block of flash.
- If you have two smaller ROMs in a single 1MB of flash (your only option if you flash is 1MB or smaller) this is referred to as two ROM mode in rBoot. Each ROM needs to be separately linked to have the correct memory mapped flash offset. Examples are given below for common scenarios.
Building¶
- The default rBoot options are perfect for a 4MB flash, so if this is what you have (e.g. an esp-12) you don’t need to do anything else. Otherwise see information below about configuration.
- Run
make
as normal, rBoot and your app ROM will both be built for you. - Running
make flash
will flash rBoot and the first ROM slot.
Configuring for two ROM mode¶
If you have a 1MB flash, you will need to have two 512KB ROM slots, both
in the same 1MB block of flash. Set the following options in your project’s
component.mk
file:
RBOOT_ROM1_ADDR = 0x80000
SPI_SIZE = 1M
SPIFFS¶
To use SPIFFS think about where you want your SPIFFS to sit on the flash.
If you have a 4MB flash the default position is for the first ROM to be placed in the first 1MB block and the second ROM to be placed in the third 1MB block of flash. This leaves a whole 1MB spare after each ROM in which you can put your SPIFFS.
If you have to a smaller flash the SPIFFS will have to share the 1MB block with the ROM. For example, the first part of each 1MB block may contain the ROM, and the second part the SPIFFS (but does not have to be split equally in half). So for the 4MB example you could put the SPIFFS for your first ROM at flash address at 0x100000 and the SPIFFS for your second ROM at 0x300000; in each case that is the 1MB block after the ROM.
To mount your SPIFFS at boot time add the following code to init:
int slot = rboot_get_current_rom();
uint32_t address = (slot == 0) ? RBOOT_SPIFFS_0 : RBOOT_SPIFFS_1;
//debugf("trying to mount SPIFFS at %x, length %d", address, SPIFF_SIZE);
spiffs_mount_manual(address, SPIFF_SIZE);
Over-the-air (OTA) updates¶
Instead of insisting on a “one-solution-fits-all” approach, Sming provides you with the ingredients to build an OTA upgrade mechanism tailored to your application. This involves selecting a transport protocol and a backend that interacts with the flash memory. Any protocol from Sming’s rich set of network classes can be used, ranging from raw TCP sockets to HTTP, FTP, MQTT, with or without SSL, etc. To conserve program memory, you might prefer a protocol already employed by your application.
On the backend side, there is OtaUpgradeStream
from the Over-the-Air Firmware Upgrade
library, which supports multiple ROM images in one upgrade file, as well as
state-of-the-art security features like a digital signatures and encryption.
Check out the HttpServer Firmware Upload example, which demonstrates a
browser-based firmware upgrade mechanism similar to what is found in many consumer
products.
A more lightweight solution is provided by RbootOutputStream
, which
is just a thin wrapper around rBoot’s flash API, in combination with RbootHttpUpdater
,
which pulls individual ROM image from an HTTP server. Add the following code:
RbootHttpUpdater* otaUpdater = nullptr;
void OtaUpdate_CallBack(RbootHttpUpdater& client, bool result)
{
if (result) {
// success - switch slot
uint8_t slot = rboot_get_current_rom();
if (slot == 0) {
slot = 1;
} else {
slot = 0;
}
// set to boot new ROM and then reboot
Serial.printf("Firmware updated, rebooting to ROM %d...\r\n", slot);
rboot_set_current_rom(slot);
System.restart();
} else {
// fail
Serial.println("Firmware update failed!");
}
}
void OtaUpdate()
{
// need a clean object, otherwise if run before and failed will not run again
delete otaUpdater;
otaUpdater = new RbootHttpUpdater();
// select ROM slot to flash
rboot_config bootconf = rboot_get_config();
uint8_t slot = bootconf.current_rom;
if (slot == 0) {
slot = 1;
} else {
slot = 0;
}
#ifndef RBOOT_TWO_ROMS
// flash ROM to position indicated in the rBoot config ROM table
otaUpdater->addItem(bootconf.roms[slot], ROM_0_URL);
#else
// flash appropriate ROM
otaUpdater->addItem(bootconf.roms[slot], (slot == 0) ? ROM_0_URL : ROM_1_URL);
#endif
// use user supplied values (defaults for 4MB flash in makefile)
otaUpdater->addItem((slot == 0) ? RBOOT_SPIFFS_0 : RBOOT_SPIFFS_1, SPIFFS_URL);
// set a callback
otaUpdater->setCallback(OtaUpdate_CallBack);
// start update
otaUpdater->start();
}
You will need to define ROM_0_URL
, ROM_1_URL
and SPIFFS_URL
with http urls for the files to download.
Command Handler¶
Summary¶
The Sming CommandHandler
implementation adds the possibility to
handle system and application commands over a variety of input media.
The CLI provides a framework in which basic system commands can be extended and application specific commands created.
Currently implemented are: - Serial - Telnet Server - Websocket Server
Implementation¶
The implementation makes use of a global object CommandHandler
,
which at the start is just a skeleton without any command active.
System commands can be activated using: -
Serial.commandProcessing(true)
-
telnetServer.enableCommand(true)
-
websockerServer.commandProcessing(true, "command")
The additional parameter for websocket is used to allow multiple connections on one websocket server instance, both with or without command proceesing.
When the websocket open request has query parameter "command=true"
command processing is enabled.
Usage¶
The usage of CommandProcessor
is the same for all implementations,
except for specific requirements. CommandProcesor
options
implemented are: - Verbose -> sets display of welcome message - Prompt
-> set prompt string - EOL -> set end of line character - welcome
message -> set the welcome message
System Commands¶
The base CommandHandler
has the following sysytem commands
implemented: - help
, Displays all available commands - status
,
Displays System Information - echo
, Displays command entered -
debugon
, Set Serial debug on - debugoff
, Set Serial debug off -
command
, Usage verbose/silent/prompt for command options
Application options¶
Applications (and Sming Core functionality) can add commands to the
CommandProcesor
using a construct like
registerCommand(CommandDelegate(
"status",
"Displays System Information",
"system",
commandFunctionDelegate(&CommandHandler::procesStatusCommand, this)
));
The added command will then be available over every opened command channel.
Example usage¶
The capabilities of CommandHandler
are shown in the example
CommandProcessing_Debug
.
The example will create an application which shows CommandProcessing
for Telnet, Websocket and Serial.
- to test Telnet, open telnet client and connect on port 23 to the ESP ip
- to test the Websocket, open a web browser with the ESP
- to test Serial use your “Serial program” and make sure “local echo” is activated
For all implementations type “help” to show the available Commands
The possibilities of extending commands with the application are shown
in: - the class ExampleCommand
- the functions
startExampleApplicationCommand()
and
processApplicationCommands()
Hot Tips!¶
Minimising Memory Usage¶
Literals use up memory, so its a good idea to move them to flash. See Program Space and FlashString.
Webpages and Spiffs¶
FlashString turns out to be very useful for sending web pages, javascript, CSS and so on. Many examples for the ESP8266 exist where a Spiffs file system is used for this purpose, but in fact Spiffs is not ideal. If you want to release a new version of your software, and your web pages are in spiffs, you now have two things to release, so there is double the chance of something going wrong. Plus you have the challenge of preserving any user files while refreshing just a few.
One solution is to use a FlashString hooked up to a FlashMemoryStream instead. In the example below, the CSS file is sent compressed to save time and space. The browser asks for core.js and gets a compressed version:
IMPORT_FSTR(flash_corejsgz, PROJECT_DIR "/web/build/core.js.gz")
void onSendCore_js(HttpRequest &request, HttpResponse &response)
{
response.headers[HTTP_HEADER_CONTENT_ENCODING] = _F("gzip");
auto stream = new FlashMemoryStream(flash_corejsgz);
response.sendDataStream(stream, MimeType::MIME_JS);
}
See FlashString for further details.
Webpages Performance¶
HTML markup can get quite large and the bigger the file the slower the page loads. One way to deal with that is to remove the white space, this process is called minifying. The downside is that the result is difficult for a human to read. I recommend against it, at least in the early stages of your project.
To support the HTML files there are CSS files and JS files, which must be kept locally on the server if one wants things to work even when the internet is absent.
I use the bootstrap library and the CSS I write goes into another special file. The file count is now three, an HTML file and two CSS files. This is already a lot of files for a microcontroller to deal with especially if it gets download requests for all three at once. A browser will start a download request for each file it sees, and for the ESP, any more than three is a problem, meaning we need to keep this under control.
One way to deal with that is to combine the CSS files together into one.
Next we have JavaScript files which includes the custom code, the bootstrap library and the jquery library. Three extra files. Once again we can deal with these by combining them into one, in which We are back to having 3, one HTML file one CSS file and one JavaScript file.
But the files are big and this is a problem not just because it is slow. The watchdog does not like things to take a long time, and you will almost certainly end up with a timeout.
When a browser asks for a file it doesn’t mind receiving a compressed version using gzip. (Note that you need to add “Content-Encoding/gzip” to the header in the response from the server). Using gzip vastly reduces the sizes of files and it’s well worth doing.
Another size optimisation for CSS files is to remove unused CSS (UNCSS) - I recommend against this as it was too aggressive at removing stuff I really needed - YMMV.
I use gulp to automate the extraction and concatenation and compression of the CSS and JS files, here is the relevant part of my gulpfile.js:
function htm() {
return gulp.src(htmConfig.src)
.pipe(useref())
.pipe(gzip()) // compresses to a gzip file
.pipe(size({ showFiles: true }))
.pipe(gulp.dest('web/build/'))
}
My webpage looks like this
<!-- build:css core.css -->
<link rel="stylesheet" type="text/css" href="bootstrap.css">
<link rel="stylesheet" type="text/css" href="style.css">
<!-- endbuild -->
After gulp runs it looks like this
<link rel="stylesheet" href="core.css">
Upgrading¶
If you are migrating from version older than 3.8 you should read the release log to find the needed steps to migrate. For newer versions we have dedicated pages.
From v4.0 to v4.1¶
Summary¶
With Sming version 4.1 there are some backwards incompatible changes. This page is provided to help with migrating your applications.
SSL¶
In version 4.1 one can choose between different SSL implementations. At the moment Sming supports axTLS and BearSSL for creating SSL enabled clients and servers.
In order to allow multiple SSL adapters and seamless integration the library code had to be refactored and that introduced some breaking changes.
Detailed documentation can be found in SSL: Secure Sockets Layer.
See SSL: Upgrading for a migration guide.
MultipartParser¶
The MultipartParser component has been decoupled from the framework and converted into a Library. In the process, the former config option ENABLE_HTTP_SERVER_MULTIPART has been removed. Therefore, in your components.mk, replace:
ENABLE_HTTP_SERVER_MULTIPART := 1
by:
ARDUINO_LIBRARIES += MultipartParser
Also, the body parser for handling HTTP requests of content-type multipart/form-data must now be registered explicitly by the application code:
#include <MultipartParser.h>
HttpServer server;
...
server.setBodyParser(MIME_FORM_MULTIPART, formMultipartParser);
From v3.8 to v4.0¶
Summary¶
With Sming version 4.0 there are some backwards incompatible changes. This page is provided to help with migrating your applications.
In particular, the build system has changed so the process is now driven from the project directory.
See Sming build system for detailed information and a list of known issues.
Header files¶
The folder structure has been revised to provide support for additional architectures, such as the Host Emulator, and in the future the ESP32.
The Sming/Arch
directory should never be accessed directly: it
contains specific files for the target architecture, and may provide
different header file versions to the main ones. Instead, consider these
directories to be your ‘root’ include directories:
Sming
Sming/Components
Sming/Core
Sming/Wiring
Examples of #include statements:
Old-style | Recommended |
---|---|
"SmingCore/SmingCore.h" |
<SmingCore.h> |
"SmingCore/Network/SmtpClient.h" |
<Network/SmtpClient.h> |
"SmingCore/Data/Stream/FlashMemoryStream.h" |
<Data/Stream/FlashMemoryStream.h> |
"Wiring/WString.h" |
<WString.h> |
"SmingCore/Platform/Station.h" |
<Platform/Station.h> |
Changed Headers¶
If you use some of the includes below directly in your application make sure to apply the following changes:
Description | Old name | New name |
---|---|---|
uart driver | "espinc/uart.h" |
<driver/uart.h> |
flesh memory | "flashmem.h" |
<esp_spi_flash.h> |
C compatible types | <espinc/c_types_compatible.h> |
<c_types.h> |
user_include.h¶
This file is generally #included ahead of everything else so that common architecture-specific definitions are available. Unless you’ve made changes to the file, it is not required and you should delete it: Sming provides a default which will be used.
If you have made customisations, please amend the file as follows:
#pragma once
#include_next <user_config.h>
<< User Customisations here >>
If you’re using #include <SmingCore.h>
then you don’t need
#include <user_config.h>
as this is included automatically.
Application Makefile¶
- Rename
Makefile-user.mk
file tocomponent.mk
. - Replace the file
Makefile
with the one from theBasic_Blink
sample project. If you’ve ignored the instructions and modified the file (!) then you’ll need to move those changes into your newcomponent.mk
file instead. - Sming uses the
#pragma once
statement for header guards, so consider updating your own files if you’re not already doing this.
Arduino Libraries¶
Your project must specify which Arduino Libraries it uses (if any). Do
this by setting ARDUINO_LIBRARIES
in your project’s
component.mk
file. For example:
ARDUINO_LIBRARIES := OneWire
This change means only the libraries you require for a project need to be built.
The following libraries have changes in their API:
JSON¶
ArduinoJson is now an optional Component, so you need to make a couple of changes to use it:
- Add
ArduinoJson6
to theARDUINO_LIBRARIES
variable in your project’scomponent.mk
file. (e.g.ARDUINO_LIBRARIES = ArduinoJson6
) To support migration of existing projects, you can elect to continue using version 5 by specifyingArduinoJson5
instead. - Add
#include <JsonObjectStream.h>
to your source code. If you’re not using the stream class, add#include <ArduinoJson.h>
instead.
See library documentation for further details:
WiFi Classes¶
Additions¶
New class to handle MAC addresses: Sming/Wiring/MacAddress.h.
Sming/Platform/Station.h¶
- getConnectionStatusName() returns String instead of char*
- EStationConnectionStatus renamed to StationConnectionStatus
Sming/Platform/WifiEvents.h¶
- Callback handler parameter lists have changed
Hardware Timers¶
The following functions have been removed from HardwareTimer.h:
- usToTimerTicks
- timerTicksToUs
Their presence is confusing. The ESP8266 has two hardware timers:
- Timer1:
- A 23-bit count-down timer accessed via the HardwareTimer class. Use the usToTicks and ticksToUs methods.
- Timer2
- A 32-bit counter accessed bia the ElapseTimer class. The current tick value is obtained using the NOW() macro. The clock frequency is defined by HW_TIMER2_CLK (in driver/hw_timer.h) and depends on the USE_US_TIMER compiler flag.
Deprecated / Changed types¶
Deprecated types will generate a compiler warning. See Deprecated List.
Experimental Stuff¶
Enabling SSL in HttpServer¶
- At the moment any TCP based server in Sming can use TLS/SSL.
- That applies to HttpServer (also with Websockets).
- But make sure to read the security considerations and limitations.
Enabling SSL in HttpServer¶
The listen
method in the TcpServer, and the child HttpServer class, accepts a second optional
parameter. If you look at the original code:
samples/HttpServer_WebSockets/app/application.cpp#L95-L99.
That can be changed to something like:
void startWebServer()
{
// TODO: Make sure to set a server certificate and key
server.listen(443, true);
And what is left is the actual setting of the server certificate:
void startWebServer()
{
// Assign the certificate
server.setSslInitHandler([](Ssl::Session& session) {
session.keyCert.assign(serverKey, serverCert);
});
server.listen(443, true);
The final code can be something like:
void startWebServer()
{
#ifdef ENABLE_SSL
server.setSslInitHandler([](Ssl::Session& session) {
session.keyCert.assign(serverKey, serverCert);
});
server.listen(443, true);
#else
server.listen(80);
#endif
server.paths.set("/", onIndex);
//...
Security Considerations¶
Does it really make sense to use SSL for an HttpServer on an ESP8266 device?
The certificate/private key pair should make it impossible for an external user to decrypt your traffic so that the things that you sent are kept private, but there are some complications with this:
- The private key will not stay private for long. The private key should be kept encrypted on the flash memory, to prevent casual reading. But even with decryption there is a high probability that someone will be able to disassemble your application and figure out how to decrypt the key.
- Costs for certificate. Let’s imagine that you have overcome the first issue. Then comes the second issue - if you want your users to accept the certificate it has to be signed by one of the trusted certificate authorities. And that costs money. And if you want to use a unique certificate/private key pair for every device than it will make things worse, moneywise. Note: Free SSL certificates are now available, for example https://letsencrypt.org/. These will expire if not kept up to date so adds additional complexity to your application.
- You can handle up to 2 or maximum 3 connections. SSL needs 16K of memory to make the initial handshake. The memory consumption after a successful handshake can decrease to 4K, just for the SSL, per request. But realistically this means that you will end up with a server that can handle maximum 2 or 3 simultaneous connections before the heap memory is consumed and has to be released.
Therefore, in our humble opinion, it would be better to rely on the WIFI security that your Access Point (AP) provides and make this AP accessible only for your IoT devices.
Signed OTA Updating¶
Introduction¶
Deploying embedded devices with (automatic) OTA functionality introduces new risks to local networks and the whole internet. If an attacker takes over the update server or runs a MITM attack, he might be able to turn the devices into zombies.
To prevent this, you can either provide a secure connection between device and update server (e. g. VPN or TLS) or add a cryptographic signature to all OTA files. Pull Request #893 provides hooks to the OTA functionality to allow checking of such signatures.
A proven method for this is, for example, ECDSA in conjunction with SHA-256. For both steps libraries are available (micro-ecc and Arduino Cryptosuite).
To use it, you can subclass RbootOutputStream like this:
#define PREFIX_MAGIC 0x54, 0x49, 0x55, 0x53
#define PREFIX_TYPE 0x00, 0x01
#define PREFIX_SIZE sizeof(_my_prefix)
#define SIGNATURE_SIZE 64
const u8 _my_prefix[6] = { PREFIX_MAGIC, PREFIX_TYPE };
typedef struct {
u8 prefix[PREFIX_SIZE];
u8 signature[SIGNATURE_SIZE];
} MyHdr;
//-----------------------------------------------------------------------------
class MyStream : public RbootOutputStream {
public:
MyStream(uint32_t startAddress, size_t maxLength = 0): RbootOutputStream(startAddress, maxLength)
{
// do some initialization if needed.
}
size_t write(const uint8_t* data, size_t size) override;
bool close() override;
virtual ~MyStream()
{
delete sha256;
}
protected:
bool init() override;
private:
Sha256 *sha256 = nullptr;
u8 hdr_len;
MyHdr hdr;
};
//-----------------------------------------------------------------------------
bool MyStream::init() {
RbootOutputStream::init();
delete sha256;
sha256 = new Sha256;
hdr_len = 0;
}
size_t MyStream::write(const uint8_t* data, size_t size) {
// store header
u8 missing = sizeof(hdr) - hdr_len;
if (missing) {
if (size < missing) missing = size;
memcpy( &hdr, data, missing );
size -= missing;
data += missing;
hdr_len += missing;
// check prefix
if ( hdr_len >= PREFIX_SIZE ) {
if ( memcmp(hdr.prefix, _my_prefix, PREFIX_SIZE) ) {
debugf("invalid prefix");
return 0;
}
}
}
// update hash
sha256->update(data, size);
// save data
return RbootOutputStream::write(data, size);
}
bool MyStream::close() {
if (!RbootOutputStream::close()) {
return false;
}
u8 hash[SHA256_BLOCK_SIZE];
sha256->final( hash );
bool sig_ok = /* add signature check here */;
if (!sig_ok) {
debugf("wrong signature");
// TODO: if needed delete the block at the startAddress
return 0;
}
return 1;
}
And then in your application you can use your MyStream with the following setup:
RbootHttpUpdater* otaUpdater = new RbootHttpUpdater();
MyStream* stream = new MyStream(1234); // Replace 1234 with the right start address
otaUpdater->addItem(ROM_0_URL, new MyStream()); // << the second parameter specifies that your stream will be used to store the data.
// and/or set a callback (called on failure or success without switching requested)
otaUpdater->setCallback(OtaUpdate_CallBack);
Contributing¶
How you can help¶
You can contribute to Sming by
- Providing Pull Requests with new features, bug fixes, new ideas, etc.
- Testing our latest source code and reporting issues.
- Supporting us financially to acquire hardware for testing and implementing or out of gratitude.
Development guides¶
Contributing to Sming Framework¶
All contributions (PRs) to Sming Framework have to be done to the develop branch.
master: Branch that contains latest production (stable) release. No PRs other than Final Release updates will be merged into master. develop: Main development branch: contains all current new features.
This means that all contributors will have to submit a PR to a develop , it will be tested and then merged to develop for automated integration testing (via TravisCI, Jenkins or SemaphoreCI), as well as manual testing on a real device.
Sming Contributing flow:
Fork *Sming* repo
After that clone your own fork.
git clone https://github.com/<my-fork>/Sming.git
Create a new branch off the develop branch
cd Sming git checkout develop git branch feature/<short-explanation> git checkout feature/<short-explanation>
Make sure to replace
short-explanation
with one or two words describing the purpose of the feature. If you want to commit a fix usefix/
as prefix for your branch name.Build, test your code
Make sure that your code compiles and it is tested on real device. Sometimes you will be asked for a proof (usually screenshot) that it was tested on your device(s).
Document your code
As a bare minimum, please include a
README.rst
orREADME.md
file. See Documentation System for further information.Commit changes
git add <changed-files> git commit -m "<Description of the change(s)>"
Push your changes to your fork on github
git push
Rebase if needed
If your branch cannot be merged automatically because there are new changes in the official develop branch that conflict with yours then make sure to rebase your branch. The following steps can help you do this.
First step: You will need to add the
upstream
repository. This step should be executed ONLY once.cd Sming git remote add upstream https://github.com/SmingHub/Sming.git git fetch upstream develop git checkout develop git reset --hard upstream/develop
Second step: If you have already defined
upstream
repository and synchronized yourdevelop
branch to fetch the updates fromupstream
( the commands above do this) the next step is to get the latest changes from the officialdevelop
branch.This can be done using
cd Sming git checkout develop git pull
Final step: Now you are ready to merge the latest changes from official
develop
branch into your branch and place your changes on top. The commands below help you achieve this.cd Sming git checkout develop git pull git checkout feature/<short-explanation> git merge develop # Fix any merge conflicts if needed. git rebase develop # Fix any merge conflicts if needed.
If there were merge conflicts you will have to resolve them locally. This usually involves calling the following commands:
git mergetool # After resolving conflicts you should type the command below to see what are the next steps # Newer versions of `git` are kind enough to show hints git status
After that operation you should have a branch that has all latest changes from develop with your changes on top.
Submit PR to the main Sming repo, develop branch.
Work with other contributors to test your feature and get it merged to develop
This is the most common approach for a git-flow: http://nvie.com/posts/a-successful-git-branching-model/
Sming Documentation¶
This directory contains the build system for Sming’s documentation. It is intended to be read online via Read The Docs.
The source
directory contains some top-level files however most of the
information is obtained from the various README files associated with the source code.
Setup¶
Should already be available as part of Sming build system
For Linux:
sudo apt install doxygen graphviz-dev
For Windows, see:
- Doxygen www.doxygen.nl
- Graphviz graphviz.org
GraphViz is used by Doxygen (and Sphinx) to render graphs from .dot files.
For Linux:
sudo apt install python3-sphinx python3-pip python3-setuptools python3-cairocffi
For Windows, see Sphinx Installation Guide.
Building¶
Build the documentation like this:
make html
This will:
- Pull in and patch every submodule
- Generate doxygen API information
- Build documentation in HTML format
If you make changes to any source documentation files these will be
picked up automatically when make html
is next run.
If you make any changes to source code comments, you’ll need to re-build the doxygen information first:
make api -B
make html
Coding Style Rules¶
The benefits of coding standards are readability, maintainability and compatibility. Any member of the development team in Sming should be able to read the code of another developer. The developer who maintains a piece of code tomorrow may not be the coder who programmed it today.
Therefore we enforce coding standards described in our
Style Guide. The coding style rules are mandatory for the
Sming/SmingCore
and samples
directories and all their
sub-directories. And they should be applied to all C, C++ and header
files in those directories.
A Pull Request that does not adhere to the coding style rules will not be merged until those rules are applied.
Tools¶
Tools will help you easily adhere to the coding standards described in our Style Guide without the need to know them by heart.
In order to automatically check and apply our coding standards you need
to install clang-format
and optionally clang-tidy
.
In Ubuntu you should be able to install them using the following command:
sudo apt-get install clang-format clang-tidy
See the the download page of the Clang project for installation instructions for other operating systems.
We are using version 6.0 of clang-format and clang-tidy on our Continuous Integration (CI) System. If possible try to install the same version or newer on your development computer.
The coding rules are described in the .clang-format which can be found in the root directory of the project. You don’t have to change anything on this file unless it is discussed and agreed coding style change.
There are multiple existing integrations for IDEs that can be found at the bottom of that page ClangFormat.html.
For our Eclipse IDE, which is our preferred IDE, we recommend installing the CppStyle plugin. You can configure your IDE to auto-format the code on “Save” using the recommended coding style and/or format according to our coding style rules using Ctrl-Shift-F (for formatting of whole file or selection of lines). Read Configure CppStyle for details.
If you want to directly apply the coding standards from the command line you can run the following command:
cd $SMING_HOME
clang-format -style=file -i Core/<modified-file>
Where Core/<modified-file>
should be replaced with the path to
the file that you have modified.
The following command will run again the coding standards formatter over
all C, C++ and header files inside the Sming/Core
, samples
and
other key directories:
cd $SMING_HOME
make cs
The command needs time to finish. So be patient. It will go over all files and will try to fix any coding style issues.
If you wish to apply coding style to your own project, add an empty .cs
marker file
to any directory containing source code or header files. All source/header files
in that directory and any sub-directories will be formatted when you run:
make cs
from your project directory.
If you have installed CppStyle as described above you can either
configure Eclipse to auto-format your files on “Save” or you can
manually apply the coding style rules by selecting the source code of a
C,C++ or header file or a selection in it and run the Format
command
(usually Ctrl-Shift-F).
Style Guide¶
You don’t have to know by heart the coding style but it is worth having an idea about our rules. Below are described some of them. Those rules will be can be automatically applied as mentioned in the previous chapter.
We use tabs for indentation. Configure your editor to display a tab as long as 4 spaces. The corresponding settings in clang-format are:
TabWidth: 4
UseTab: Always
IndentWidth: 4
Identifier type | Rules for naming | Examples |
---|---|---|
Classes | Class names must be nouns in UpperCamelCase, with the first letter of every word capitalised. Use whole words — avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML). | class HttpClient {}
class HttpClientConnection {}
|
Methods | Methods must be either verbs in lowerCamelCase, or a multi-word name that begins with a verb in lowercase; that is, with the first letter lowercase and the first letters of subsequent words in uppercase. | bind();
getStatus();
|
Variables | Local variables, instance variables, and class variables must also be written in lowerCamelCase. Variable names must not start with, end with or contain underscore (_) or dollar sign ($) characters. This is in constrast to some coding conventions which prefix all instance variables with underscore, however this is reserved by the C++ standard and can create problems. Variable names should be short yet meaningful. The choice of a variable name should be mnemonic — that is, designed to indicate to the casual observer the intent of its use. One-character variable names should be avoided except for temporary “throwaway” variables. Common names for temporary variables are i, j, k, m, and n for integers; c, d, and e for characters. |
int i;
char c;
WebsocketClient* client;
|
Constants | Constants must be written in uppercase characters separated by underscores. Constant names may contain digits if appropriate, but not as the first character. | #define MAX_PARTICIPANTS 10
|
For the moment we recommend the use of C++11. The corresponding settings in clang-format are:
Standard: Cpp11
Cpp11BracedListStyle: true
We don’t recommend the use of a starting or ending space in angles, container literals, c-style cast parentheses, parentheses and square brackets. Our settings are:
SpaceAfterCStyleCast: false
SpaceBeforeParens: Never
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
See the meaning of those keys and their selected values in the ClangFormatStyleOptions document.
We are living in the 21st century so most of the monitors should be capable of displaying 120 characters per line. If a line is longer than those characters it will be split whenever possible:
ColumnLimit: 120
Two or more empty lines will be compacted to one. Also we delete empty lines at the start of a block:
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
See the meaning of these keys and their selected values in the ClangFormatStyleOptions document:
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: true
AfterFunction: true
AfterObjCDeclaration: false
AfterStruct: false
BeforeElse: true
IndentBraces: false
BreakBeforeBraces: Linux
We don’t re-sort includes although it is highly recommended to order the headers alphabetically whenever possible:
SortIncludes: false
We try not to split comment lines into smaller ones and also we add one space between code and trailing comment:
ReflowComments: false
SpacesBeforeTrailingComments: 1
For readability put always spaces before assignment operators:
SpaceBeforeAssignmentOperators: true
Other Elements¶
Please use the standard Sming header with copyright notice:
/****
* Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
* Created 2015 by Skurydin Alexey
* http://github.com/anakod/Sming
* All files of the Sming Core are provided under the LGPL v3 license.
*
* [Insert filename here] - [optional brief description of file]
*
* @author [date] [name] [email]
*
* [comments]
*
****/
Do not include details of minor changes to the file as this is handled by GIT. It may be appropriate to add notes to identify major changes or contributions. These should be marked with a new @author tag.
Where a change in the Sming API may break existing users’ code, then the existing type/method/function/variable must be maintained for a time to allow time for migration to the new technique. Such changes should only be made if there is a good reason, for example improved reliability, performance, ease of use.
Deprecation requires two steps:
Step 1: Add a @deprecated
tag to the method header comment so the change
is flagged in the auto-generated API documentation. Include a brief
explanation of the new method or technique to be adopted. See also
Documenting the API.
Example:
/** @deprecated Use `anotherMethod()` instead */
Step 2: Append SMING_DEPRECATED
to the method declaration so the
compiler will flag a warning if that method is used during compilation.
The framework and samples must build without referencing any deprecated methods, functions or variables.
Sming makes extensive use of virtual classes. If you are modifying or adding virtual methods then please follow these guidelines:
Rule: The base class must have a virtual destructor, even if it doesn’t do anything. Example:
virtual ~Stream() {}
Rule: Inherited classes must not prepend virtual
or append
override
to any destructor. Example:
~IDataSourceStream();
Rationale: virtual destructors do not behave like regular virtual
methods - they are ‘chained’ rather than overridden - therefore
override
is not appropriate and virtual
is both un-necessary
and unhelpful
Rule: Use the override
directive on inherited virtual methods:
int read() override;
Rationale: The compiler will ensure there is actually a base method to inherit from and generate a warning if one is not found, or if parameters do not correspond.
Rule: Don’t use empty destructors in inherited virtual classes
Rationale: They’re not necessary
Some notes on commonly occurring issues:
/**
* @brief Basic example class
*/
class VirtualBuffer
{
public:
virtual ~VirtualBase
{
}
virtual unsigned getLength() const = 0;
};
/**
* @brief Descendant example class
*/
class MemoryBuffer : public VirtualBuffer
{
public:
/*
Note: Omit destructor if not required in descendant
*/
~VirtualDescendant()
{
/*
Note: delete includes null pointer check so you don't have to
*/
delete buffer;
}
/*
Use `const` qualifier for methods which don't modify object
*/
const char* getBuffer() const
{
return pos;
}
/*
Trivial code should go into the class header file where possible.
Rationale: Compiler is better able to optimise code. Easier to read.
Use `override` on virtual methods
*/
unsigned getLength() const override
{
return length;
}
/*
Use methods to access member variables rather than making them public
Rationale: Protects data, helps when tracking down bugs
*/
void setBuffer(char* newBuffer, unsigned newLength)
{
delete buffer;
buffer = newBuffer;
length = newLength;
}
private:
/*
Each class should operate on a small, well-defined item of data.
*/
/*
Class variables should be defined with initialisers, rather than using code in the constructor.
Rationale: Reduces/eliminates risk of un-initialised data causing unpredictable behaviour.
*/
char* buffer = nullptr;
/*
Remember `int` can be unsigned! If a value doesn't need to be signed, don't make it so.
Rationale: unsigned values are simpler to check, less likely to introduce bugs, compiler can better optimise computations
*/
unsigned length = 0;
};
Documentation System¶
Read the Docs and Sphinx¶
Online documention is managed via Read the Docs, which uses Sphinx as the documentation build system.
This page describes specific details for the Sming documentation build system.
reStructuredText¶
These have a .rst
file extension. Some references you should have a read through:
Markdown .md
files are supported (except for samples) but please ensure there is only one
main heading (*HEADING) at the top containing the title of the Library or Component or it
may be incorrectly rendered in the table of contents. If you run into problems trying to get
your markdown to display correctly, then it’s probably time to move to reStructuredText!
If you need to convert existing documentation into reStructuredText take a look at pandoc. Note that their online tool doesn’t handle long files.
Source file location¶
Sphinx requires all document files (documents, images, etc.) to be
located in one place, namely inside the docs/source
directory.
During the build process, documentation files from the Component, Library
and Sample directories are copied:
README.md
*.rst
*.svg
*.png
*.jpg
This is also performed for any submodules declared by the COMPONENT_SUBMODULES variable in a component.mk file.
This should be sufficient for most cases. However, if additional
documentation is referred to, such as in submodules belonging to a
Component, then these must be listed in the component.mk
file like
this:
COMPONENT_DOCFILES := submodule/docs/api-guide.md submodule/api.txt
See Sming build system for more information about component.mk files.
README files¶
All Components, Libraries and Samples must include a README.rst
or README.md
file as follows:
- Main Heading: This will be used as the title in the online documentation, so keep it brief but informative. For example,
BME280 Barometric Pressure Sensor
.- Purpose: What is the purpose of the code?
- References: Is this based on or does it use existing code? Please include details.
- Datasheets: If appropriate, please include links to manufacturer’s or external development websites. Note that any submodules or dependencies are automatically documented: see Sming build system for details, specifically COMPONENT_SUBMODULES and COMPONENT_DEPENDS.
You should also try to include any other information which could be useful information for a new developer. The purpose of samples projects is to demonstrate specific features or libraries, so please ensure this is adequately described.
Optionally, you may also like to include a screenshot or other diagrams or illustrations.
Please use .png
, .jpg
or .svg
files.
Attention
The README filename is case-sensitive
Attention
Please ensure there is only one top-level heading or the documentation contents will not display correctly.
You should use the available annotations to make browsing the documentation easier. Using the Sphinx roles <https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html> will insert hyper links to the corresponding definitions. Additional roles are provided specifically for the Sming documentation - see link_roles below.
Code blocks¶
There are multiple ways to show syntax-higlighted literal code blocks in Sphinx. See Showing code examples for full details.
Use the code-block
directive like so:
.. code-block:: c++
for(int i = 0; i < 100; ++i) {
goto hell;
}
The language for highlighting is indicated. You can find a full list at pygments.org, however for consistency it is suggested that you use one of these:
text Doesn't highlight anything
c++ C++ code examples
bash Linux shell code
batch Windows batch file or commands
make Makefile
rst reStructuredText
You can set a default like this:
.. highlight:: c++
which will apply to any subsequent use of:
.. code:block::
or, the short-hand version:
::
API Documentation¶
Function, structure, class and type information is extracted from comments in the source code (see Documenting the API). This is parsed using Doxygen into XML, which is then made available using the Breathe sphinx extension. You can then pull in definitions like this:
.. doxygenclass::`String`
If you wish to refer to a type within documentation, you can add a link to the definition like this:
The :cpp:class:`String` class is really useful.
This is handled using cpp inline expressions.
See Esp8266 GDBSTUB for Sming for a more complex example. At the bottom of the file we pull in the documentation for all the #defined configuration using:
.. doxygenfile:: gdbstub-cfg.h
We can then refer to a macro like this:
Don't wait on startup by setting :c:macro:`GDBSTUB_BREAK_ON_INIT` =0
In many cases including a file like this is not the best approach, perhaps using a group:
.. dogygengroup:: wstring
Or individual classes. Some experimentation may be necessary but there are plenty of examples within the main documentation to guide you.
You can use the following build variables within your Component’s component.mk file to direct doxygen parsing:
-
COMPONENT_DOXYGEN_INPUT
¶ Specifies directories or files to be parsed by Doxygen. All paths are relative to the Component directory.
If you need to specify an absolute path, append directly to DOXYGEN_INPUT instead.
-
COMPONENT_DOXYGEN_INCLUDE
¶ Add any directories or files which should be pre-processed but not included in the output.
If you need to specify an absolute path, append directly to DOXYGEN_INCLUDE_PATH instead.
-
COMPONENT_DOXYGEN_PREDEFINED
¶ Specify any necessary pre-processor definitions. An example where this is required is for function attributes #defines which would otherwise be incorrectly interpreted as variable names and cause parsing errors:
CUSTOM_ATTR void myFunc(); ^^^
So we can do this:
COMPONENT_DOXYGEN_PREDEFINED := \ CUSTOM_ATTR=
Build (environment) variables¶
These are defined in the README for the corresponding Component using:
:envvar::`COM_SPEED`
Determines default serial port speed
You can refer to them like this:
Change baud rate using the :envvar:`COM_SPEED` variable.
Link Roles¶
The documentation build system provides some custom roles for creating links.
Inserting a link to a Component page, using the title of that page by default:
See :component:`spiffs` for details of the flash filing system.
We use :component-esp8266:`axtls-8266` for SSL support.
The host has a special :component-host:`UART Driver <driver>`.
The last example shows how to change the hyperlink text. It defaults to the README description.
As for Components, refer to libraries like this:
Use the :library:`Adafruit_ST7735` library to do some fancy display stuff.
To refer to a sample application README:
See the :sample:`Basic_Blink` sample for a simple introduction to Sming.
To refer to source code use the path relative to the root working directory, for example:
See :source:`Sming/Core/Network/Url.h`
If the documentation is built locally, it will use the local file path, otherwise it will create a link to the source file on github.
If you want to refer to discussions on github, insert links like this:
See :pull-request:`787`
See :issue:`1764`
Eclipse¶
You can find a good plugin editor for Eclipse by searching the
marketplace for rest editor
. For example,
http://resteditor.sourceforge.net/. A useful feature is dealing with
heading underscores, just type this:
My Heading
==
Then when you save the file it gets formatted like this:
My Heading
==========
Tables, unfortunately, do take a bit of manual formatting to get right.
Sphinx Extensions¶
The documentation system is easily extended to support new features. This section summarises the extensions included.
- m2r
- Provides support for markdown content.
- breathe
- To support Doxygen integration. See API Documentation.
- link-roles
- A custom extension implemented in link-roles.py. See Link Roles.
- sphinxcontrib.wavedrom
- For implementing timing and other waveform diagrams within documents. See Servo RC PWM Control for an example.
Documenting the API¶
This guide describes how to document the Sming API. It is aimed at developers of the framework, not users of the framework.
Sming API documentation is created using javadoc style comments within the source code. Comments are added to header files and doxygen is used to create HTML documentation. API documentation is organised as a set of modules, each of which represents a logical topic, e.g. Date and Time.
The API documentation covers the core Sming framework and relevant parts of the ESP SDK (where this is required to use the framework). The API does not cover contributed libraries which should be documented by the upstream contributor. Within the source code tree, this includes:
- Services
- SmingCore
- Wiring
- rboot
The following elements of source code are documented:
- Global constants
- Classes
- Class public members: functions, variables, operators
- Macros
- Structures
- Enumerations
Javadoc comments use the following style:
- Start with /**
- End with */
- Each line (between start and end) starts with a space and a *
- Doxygen commands are prefixed with @
- Constants documentation use the command ///<
Each API documentation comment should be part of a module. To define a module, use the @defgroup command. This should be performed only once within the Sming framework source code. The format is:
@defgroup groupname Brief description of the group
To configure a group to span code, use the @{ and @} commands. When appended to a comment block, @{ will include all subsequent javadoc comments until the next @} command. For example:
/**
* @defgroup DateTime Date and time functions
* @{
*/
...
/**
* @brief Date and time class
...
* @}
*/
To add some documentation comment to a group, use the @addtogroup command. This may be performed several times within the Sming framework source code. The format is:
@addtogroup groupname
Use the @{ @} commands to span comments. This avoids the need to add @addtogroup commands to each comment.
To create a hierarchy of groups, use the @ingroup command for child groups, for example:
/**
* @defgroup SystemTime System time functions
* @ingroup DataTime
...
It is common to be able to define a group and span a whole file using @defgroup and @{ @} commands. This is often possible when all content of a header file relates to a common topic.
Constant values should be included in the constants group, for example:
/**
* @brief ESP GPIO pin configuration
* @ingroup constants
*/
To document a function, use the following comment style:
/**
* @brief Brief description of function
* @param "Parameter name" Description of parameter (Default: value if defined)
* @param ... rest of parameters
* @retval DataType Description of return value
* @note Any extra notes that may assist application developer
*/
For example:
/** @brief Get human readable date and time
* @param format Select the date format, e.g. dtDateUS for mm.dd.yyyy (Default: dd.mm.yyyy)
* @retval String Date and time in format dd.mm.yyyy hh:mm:ss
* @note Date separator may be changed by adding #define DT_DATE_SEPARATOR "/" to source code
*/
String toFullDateTimeString(dtDateFormat_t format = dtDateFormatEU);
To document a Sming framework constant, use command ///<, for example:
int8_t DayofWeek; ///< Day of week (0-6 Sunday is day 0)
To reference another method or function, write its name with ():
Use `otherMethod()` instead
This will match any method in the current class called otherMethod
,
regardless of arguments. Note the backticks ` are there just to
highlight the code. If you need to be specific:
Use `otherMethod(const char*, int)` instead
To add a See Also
section, use @see
. Example:
@see See `OtherClass()` for details
Adding External Sources¶
Introduction¶
In Sming we have source code from other repositories such as rboot, spiffs, etc.
Having local copies of those modules brings some disadvantages with it:
- We cannot easily update the local copy from the original source code.
- We cannot easily send improvements to those projects once we make local changes in our local copy.
Sming uses GIT submodules which allows the build system to fetch source code from an external repository on demand.
If modifications are required then the submodule can be patched.
This simplifies the process of integrating changes from those third-party projects.
Where to place external code¶
Submodules may be a Component by itself (such as FlashString), or contained within a Component (e.g. rBoot).
The location must be chosen carefully:
Code required within the core Sming framework
If the Component supports multiple architectures, place it inSming/Components
. Otherwise, use the appropriateSming/Arch/*/Components
directory.
Code for general use
Create a new Library inSming/Libraries
Please consult Sming build system for further details about how Components are constructed.
Copying Source Code¶
If the source code does not have a publicly accessible GIT repository then the source code needs to be copied locally.
In order to track changes more easily, the initial commit should be an exact copy of the original.
Please either comment the code or add notes to the documentation to detail any required changes for compatibility.
Add submodules¶
As an example, this is how the new PWM submodule was added to the Esp8266 Drivers Component:
Add the submodule using GIT:
cd <Sming-root-folder>/ git submodule add \ https://github.com/StefanBruens/ESP8266_new_pwm.git \ Sming/Arch/Esp8266/Components/driver/new-pwm \ --name ESP8266.new-pwm
This adds an entry to the end of the .gitmodules
file:
[submodule "ESP8266.new-pwm"]
path = Sming/Arch/Esp8266/Components/driver/new-pwm
url = https://github.com/StefanBruens/ESP8266_new_pwm.git
For naming submodules, please follow the convention used for the other entries in
.gitmodules
, which is determined by the local path:
- ``Sming/Components``: just use the name of the submodule
- ``Sming/Arch/ARCH/Components``: Use ``ARCH.name``
- ``Sming/Libraries``: Use ``Libraries.name``
- Open
.gitmodules
in a text editor and:
- Move the entry to a more suitable location in the file, i.e. at the end of the section listing all the ESP8266-specific submodules
- Add the line
ignore = dirty
Applying Patches¶
If a submodule requires changes to work with Sming, this can be handled using patches.
This is generally done by pulling in the original submodule, making the required changes
and then running a diff
to create a patch file, like this:
cd <Sming-root-folder>/third-party/<module-name>
git diff --no-ext-diff > <module-name>.patch
If using a GUI such as GIT Extensions then this can be done using a right-click.
See GIT Submodules for further details about how patches are used and where they should be placed.
Using submodules¶
If the submodule is added as a Component in its own right, no further action is required. Applications can use it by adding the name to their COMPONENT_DEPENDS or ARDUINO_LIBARIES entries in component.mk as appropriate.
Submodules contained within a Component must be declared by adding them to the COMPONENT_SUBMODULES entry in component.mk.
Moving submodules¶
If you need to change the location of a submodule, here’s a suggested approach. In this example, we’re going to move the Adafruit_Sensor submodule into a Component:
# Move the submodule temporarily
Sming/Libraries$ git mv Adafruit_Sensor tmp
# Create our new Component directory
Sming/Libraries$ mkdir Adafruit_Sensor
# Move the submodule back as a sub-directory
Sming/Libraries$ git mv tmp Adafruit_Sensor/Adafruit_Sensor
Now we can add a component.mk file, README.rst, etc. as required for the component.
Financial contributions¶
We welcome financial contributions in full transparency on our open collective page. They help us improve the project and the community around it. If you would like to support us you can become a backer or a sponsor.
In addition to that anyone who is helping this project can file an expense. If the expense makes sense for the development of the community, it will be “merged” in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
Backers and sponsors¶
Thank you to all the people who have backed Sming or sponsored it.
Tools Integration¶
Using with CLion¶
Developing with the Sming framework can also be done in CLion.
- Copy and paste Makefiles into the project
- Create
app
folder and addapplication.cpp
there - Edit
CMakeLists.txt
## Edit CMakeLists.txt
include_directories("/opt/Sming/Sming")
include_directories("/opt/Sming/Sming/Libraries")
include_directories("/opt/Sming/Sming/system/include")
include_directories("/opt/esp-open-sdk/sdk/include")
set(SOURCE_FILES app/application.cpp)
add_executable(Pathfinder ${SOURCE_FILES})
Build the project using terminal¶
make && make flash
Using with MS Visual Studio Code¶
Visual Studio Code is free (as in
“free beer”, and they claim the code is Open Source) code editor for
Windows, Linux and Mac. While not as sophisticated in C/C++ support as
full featured Visual Studio, it already has some official support with
C/C++ extension from
Microsoft.
GNU Global replaces venerable ctags
tool and help collecting symbols
for Intellisense engine.
For easier integration make sure you have both ESP_HOME
and
SMING_HOME
exported in your working environment.
${workspaceRoot}
below is the directory with your project, this
notation is used also in VS Code config files. All environment variables
are available in configuration using this notation, eg. ${HOME}
etc.
Software involved¶
Fire and forget way¶
- install VS Code, extensions and tools
- download sming-qstart.py from https://github.com/zgoda/sming-qstart/blob/master/sming-qstart.py
- run it from terminal, eg.
python sming-qstart.py myproject
, see the program documentation for detailed invocation options
Easy way¶
- install VS Code, extensions and tools
- clone project skeleton using https://github.com/zgoda/sming-skel.git as source
- remove unwanted bits (at least
.git
directory) - update paths configuration in
${workspaceRoot}/.vscode/c_cpp_properties.json
- should already work out of the box with Linux providing you haveESP_HOME
andSMING_HOME
properly exported
Step by step¶
- install VS Code, extensions and tools
- update paths configuration in
${workspaceRoot}/.vscode/c_cpp_properties.json
so the list includes toolchain include path (${ESP_HOME}/xtensa-lx106-elf/xtensa-lx106-elf/include
), Sming framework include paths (${SMING_HOME}
and${SMING_HOME}/system/include
) and possibly your project additional paths (eg.${workspaceRoot}/lib
), if you screw your configuration just close VS Code, delete this file and start from scratch - make sure
path
list inbrowse
section contains the same entries asincludePath
list in root section - define RunOnSave task in your
${workspaceRoot}/.vscode/settings.json
(create file if does not exist) to regenerate GNU Global database on every save, eg:
{
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.(c|cpp|h|hpp)$",
"isAsync": true,
"cmd": "gtags ${workspaceRoot}"
}
]
}
}
- create file
${workspaceRoot}/.vscode/tasks.json
and define tasks you want to run from command palette, eg minimal set:
{
"version": "0.1.0",
"command": "make",
"isShellCommand": true,
"showOutput": "always",
"echoCommand": true,
"suppressTaskName": true,
"tasks": [
{
"taskName": "Build",
"isBuildCommand": true
},
{
"taskName": "Clean",
"args": [
"clean"
]
},
{
"taskName": "Flash",
"args": [
"flash"
]
}
]
}
- add tools and binary artifacts to
.gitignore
, eg:
out
# development tools
.vscode
GTAGS
GRTAGS
GPATH
Troubleshooting¶
Troubleshooting Windows¶
If something goes wrong - don’t worry, community will be able to help you out. Don’t forget to check User questions before posting a github issues. Maybe someone else had a similar issue!
If nothing found, please make sure to provide all required information
when posting issues. Here’s the minimum that you will need to get:
Start cmd.exe
and provide output of the following commands:
echo %PATH%
echo %SMING_HOME%
echo %ESP_HOME%
dir %SMING_HOME%
dir %ESP_HOME%
where make
Common issues & solutions¶
SMING_HOME
should be set toc:\tools\sming\Sming
, with\
as a path separator, and NO backslash\
at the end.ESP_HOME
should be set toc:\Espressif
, using\
as a path separator, and NO backslash\
at the end.- MinGW paths should be at the start of PATH environment variable (before other items).
- If you update your sming-core source don’t forget to do
cd c:\tools\sming\Sming && make clean && make
Random Restarts¶
First try setting the baud rate to 74880
. Example for Linux:
python -m serial.tools.miniterm /dev/ttyUSB0 74880
The random symbols should become readable messages.
If you see repeating messages containing rf_cal[0] !=0x05
then most
probably you should initialize
the flash memory on your ESP8266
device.
To achieve this do the following:
- Set the SPI_SIZE of your flash memory. Example: If you have device with 4 megabytes make sure that the following is set:
export SPI_SIZE=4M
- Run
flashinit
.
Run the following commands.
cd $SMING_HOME/../samples/Basic_Blink
make flashinit
flashinit
is erasing the current flash memory and populating some
areas on it with the bytes that your SDK / BootROM is expecting to be
present.
This command needs to be executed only when you change SDKs or memory layouts.
Sample Compilation¶
The first thing that you need to do is to make sure that you have a clean source code. And second if the sample is still not compiling you have to provide us with more information.
Let’s start with the first part: “Clean Source Code State”. If you are
familiar with git
you can run git status
to get more
information. Sometimes this won’t be enough therefore we recommend you
the following steps ( They are working on Linux with bash shell. If you
have another OS and shell you should adjust them accordingly).
cd /tmp
git clone https://github.com/SmingHub/Sming.git SmingForTest
cd /tmp/SmingForTest/Sming
export SMING_HOME=/tmp/SmingForTest/Sming
The commands above will fetch the latest source code in a directory that should be completely different than the Sming directory that you are using on a daily basis. Also it points the SMING_HOME variable to the new temporary directory with the clean source code.
Now let’s go to the second step: “Compile a sample and report issues, if any”. We will use the Basic_Ssl sample. Before we compile a sample we need to compile the Sming library. This can be done calling the following commands:
cd /tmp/SmingForTest/Sming
export SMING_HOME=/tmp/SmingForTest/Sming
make clean
The last makes sure to clean any intermediate files or directories. If
we run now make
. It will fetch the needed submodules, compile the
code and build a library out of it. In our case we need to compile Sming
with an optional SSL support. In order to compile Sming with SSL we need
to add the ENABLE_SSL
=1 directive. The command that we need to run now
will look like this:
make ENABLE_SSL=1
On error If the compilation stops with an error, please, copy the output that the command above produces and append it to your bug report. Now run the same command one more time but with the V=1 directive. This will produce a more verbose output that can help the Sming developers figure out the issue.
make ENABLE_SSL=1 V=1
Make sure to append that output too to your bug report. Tell the Sming developers also what is your SDK (esp-open-sdk, esp-alt-sdk, …) and version, operating system & version, git version, make & version, so that the developers can reproduce your problem.
On success It is time to compile the Basic_Ssl sample. Do this by executing the commands below:
cd /tmp/SmingForTest/samples/Basic_Ssl
export SMING_HOME=/tmp/SmingForTest/Sming
make clean
make
On error 2 If that compilation fails make sure to append the output to your bug report. Now compile the sample with the V=1 flags, similar to the compilation of the Sming library.
cd /tmp/SmingForTest/samples/Basic_Ssl
export SMING_HOME=/tmp/SmingForTest/Sming
make V=1
Check User questions before posting a github issues. Maybe someone else had a similar issue!
About Sming¶
ESP8266¶
This is the documentation for the API of Sming, a C++ framework for development on the ESP8266 microcontroller platform.
The ESP8266 is a microcontroller with Wi-Fi, manufactured by Espressif Systems.
The microcontroller is used in modules from various manufacturers, each of which present a subset of the interface pins. For example, the ESP-01 only provides 2 digital GPIO whereas the ESP-12 provides 9 digital GPIO plus ADC analogue input.
Sming provides a C++ framework that facilitates the creation of application code for the ESP8266. The core framework provides access to the ESP8266 functions such as GPIO, timers, WiFi configuration, etc. A set of libraries extend this functionality such as switch debounce, SD Card interface, etc.
Licenses¶
- Sming Core
- LGPL v3
- Espressif SDK
- ESPRSSIF MIT License (with some closed-source blobs)
- Libraries
- See each library for details of its own open source license