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
Multiple file system support: Installable File System, SPIFFS IFS Library, LittleFS
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.
Over-The-Air(OTA) firmware upgrades via HTTP(S) and MQTT(S).
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¶
Choose your preferred development environment for how to install the needed development software and toolchain(s):
Linux Installation¶
Quick Install¶
Debian (Ubuntu) and Fedora systems can use the scripted installer.
Prepare installation directory
Let’s use /opt as the main directory for tools and Sming.
Regular users may not have access to /opt, so do this:
sudo chown $USER:$USER /opt
(alternatively, use a different directory).
Install GIT
Debian:
sudo apt-get install -y git
Fedora:
dnf install -y git
Fetch the Sming repository
git clone https://github.com/SmingHub/Sming /opt/sming
Run the installer
source /opt/sming/Tools/install.sh all
If you want to save disk space then you can select which tools to install. Get a list of available options like this:
/opt/sming/Tools/install.sh
Install locations can be customised by setting environment variables before
running the install. See /opt/sming/Tools/export.sh
for details.
If you want to use the stable (release) branch:
cd /opt/sming
git checkout master
git pull
Build a ‘Basic Blink’ example¶
Change to the application directory and build:
cd $SMING_HOME/../samples/Basic_Blink
make
Flash to your device (using default serial port):
cd $SMING_HOME/../samples/Basic_Blink
make flash
Next steps¶
Proceed to Configuring your device.
Mac-OS Installation¶
Pre-requisites¶
(You might already have it)
xcode-select --install
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
(Optional):
brew install Caskroom/cask/eclipse-cpp
Build tools¶
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
ESP8266 Toolchain¶
We pull this in from the SmingTools repository:
cd ~/
export ESP_HOME=/opt/esp-quick-toolchain
curl -LO https://github.com/SmingHub/SmingTools/releases/download/1.0/x86_64-apple-darwin14.xtensa-lx106-elf-e6a192b.201211.tar.gz
sudo mkdir -p $ESP_HOME
sudo tar -zxf x86_64-apple-darwin14.xtensa-lx106-elf-e6a192b.201211.tar.gz -C $ESP_HOME
sudo chmod -R 775 $ESP_HOME
You can also build it yourself with Homebrew or with MacPorts.
Get Sming Core¶
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 is 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`
Environment Variables¶
Open with a text editor the .profile
file in your home directory, and add these lines:
export ESP_HOME=/opt/esp-quick-toolchain
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
Using Eclipse on Mac¶
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.
Compile Sming Examples¶
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
Next steps¶
Proceed to Configuring your device.
Windows Installation¶
This page describes how to install the required tools and obtain the current release version of Sming using the Chocolatey package manager.
See also:
Manual Windows Installation¶
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 Quick Toolchain.
Unzip to default location:
7z -oC:\tools\esp-quick-toolchain x x86_64-w64-mingw32.xtensa-lx106-elf-e6a192b.201211.zip
Set
ESP_HOME
environment variable:SETX ESP_HOME C:\tools\esp-quick-toolchain
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 device.
Windows WSL¶
Building under Windows is generally slower than in Linux. This is because the current build system requires a Posix emulation layer (MinGW). However, it does offer the simplest way to use Sming on a Windows PC and does not affect the quality or functionality of your applications.
However, there are situations where it is highly desirable to build Sming in a Linux environment, such as:
Making use of linux-only development tools, such as valgrind (dynamic bug detection system)
Integration building/testing prior to submitting a PR to the Sming repository
Need/want faster builds
Whilst a Windows computer can be configured to dual-boot with Linux, this is generally inconvenient for day-to-day use. A better solution is to run Linux inside a virtual machine environment such as VirtualBox, VmWare or Hyper-V.
Note that Docker is not a virtual environment but can in fact be run inside a virtual machine to take advantage of the process isolation and security benefits.
https://docs.microsoft.com/en-us/windows/wsl/
“The Windows Subsystem for Linux lets developers run a GNU/Linux environment – including most command-line tools, utilities, and applications – directly on Windows, unmodified, without the overhead of a traditional virtual machine or dual-boot setup.”
There are currently two versions of WSL, dubbed WSL1 and WSL2. Either is fine, and you can switch between versions but WSL2 is recommended.
Note
WSL2 uses Hyper-V so may conflict with other virtual machines you may be using.
See instructions here https://docs.microsoft.com/en-us/windows/wsl/install-win10#manual-installation-steps.
Install an up-to-date Linux distribution from the Microsoft store, currently Ubuntu-20.04
.
Note
You may encounter an error message similar to this during installation:
WslRegisterDistribution failed with error: 0x80370102
Error: 0x80370102 The virtual machine could not be started because a required feature is not installed.
One thing not mentioned in the instructions is to check that the hypervisor is set to auto-start at system boot. This is the default but for various reasons it can get disabled.
To check, type:
bcdedit
At an administrative command prompt. Under the Windows Boot Loader
entry you should see an entry like this:
hypervisorlaunchtype Auto
If it’s missing or set to another value (e.g. off
) then change it as follows:
bcdedit /set {current} hypervisorlaunchtype auto
After a system reboot you should be able to continue with the installation.
Open a WSL command prompt and follow the instructions in Linux Installation.
WSL2 does not currently support access to USB serial devices, so the Sming build system incorporates a workaround which runs the appropriate application (esptool) directly under Windows (via powershell).
Therefore, use the normal Windows COM port name rather than the linux ones (such as /dev/ttyUSB0).
For example:
make flash COM_PORT=COM4
Again, as we have no direct access to USB COM ports a workaround is required.
A small python application can be run on Windows to act as a simple bridge between the serial port and a TCP port.
See Tools/tcp_serial_redirect.py
- run without arguments to see available options.
You can start the server like this:
make tcp-serial-redirect
A new console will be created (minimised) showing something like this:
--- TCP/IP to Serial redirect on COM4 115200,8,N,1 ---
--- type Ctrl-C / BREAK to quit
Waiting for connection on 192.168.1.101:7780...
This uses the current COM_PORT
and COM_SPEED_SERIAL
settings.
Now we can start the debugger:
make gdb COM_PORT_GDB=192.168.1.101:7780
You may get an error running make valgrind
advising that libc6-dbg:i386
be installed. Here’s how:
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6-dbg:i386
Quick Install¶
Open an administrative cmd.exe command prompt and paste the text from the box below and press enter:
curl -LO https://raw.githubusercontent.com/SmingHub/Sming/develop/Tools/choco-install.cmd && choco-install.cmd
At the moment the Esp32 toolchain is not installed by default. If you want to install it run the following command:
choco install -y sming.esp32
Important
After installation, please close the administrative command prompt and open a new, regular command shell.
This ensures that environment variables are set correctly.
It is also inadvisable to continue running with elevated privileges.
If you followed and executed carefully the steps above Sming should be installed and configured. You can scroll down to Build Basic_Blink to check the installation.
The installer uses the latest develop branch. This one contains great new features and bugfixes but can be unstable
at times.
Switching to our stable
release will guarantee you that Sming’s code will not change so often.
On the downside you will have to wait for all new shiny features and bugfixes.
If you really want to use the latest stable
release you can type the command below:
cd %SMING_HOME%
git checkout master
git pull
In case something is broken, this will perform a forced re-install of all packages:
rmdir /s /q c:\tools\sming
choco install sming -y -f -x
Packages¶
You can find the installer sources at https://github.com/slaff/chocolatey-packages. Packages are as follows:
- git
GIT CLI client.
Please configure after installation to leave line-endings intact or else patching will fail:
git config --global core.autocrlf input
- python
Python version 3.
- cmake
-
Required to build some Components, also for Host mode.
- mingw
MinGW 32-bit.
The installer updates the system
PATH
but please check by running:where make.exe
The output should show only one result:
"C:\MinGW\msys\1.0\bin\make.exe"
- esp8266-eqt
-
Sets a system-wide
ESP_HOME
variable. - sming.esp32
Sming-compatible version of ESP-IDF and tools.
- sming.core
Latest stable version of Sming.
Sets a system-wide
SMING_HOME
environment variable.
Note that setting SMING_HOME and ESP_HOME as system-wide variables means they do not need to be set every time a command prompt is opened, and will be seen by eclipse without any further configuration.
Build Basic_Blink¶
To check the installation, open a command prompt and type these commands:
cd %SMING_HOME%\..\samples\Basic_Blink
make
The project should build without error.
Next steps¶
Proceed to Configuring your device.
Docker¶
Docker is a useful tool if you want to experiment with Sming in an isolated environment.
If you’re unfamiliar with Docker, you can find a good overview in the article, What is a Container?.
This page shows how to create docker containers with all the necessary tools to build Sming applications.
Install Docker¶
Visit the official Docker Installation Page and follow the instructions tailored for your operating system.
Install docker-compose¶
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 a single file and spin it up using one command.
Visit the official Docker Compose Installation Page and follow the instructions tailored for your operating system.
Building images¶
You can find the related Docker scripts in $SMING_HOME/Tools/Docker
.
To build your own images, do this:
cd $SMING_HOME/Tools/Docker/cli
docker-compose build
cd $SMING_HOME/Tools/Docker/ide
docker-compose build
Adjust your settings¶
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
Start your container¶
cd /opt/sming/Tools/Docker/ide && docker-compose up -d
Open your browser¶
http://localhost:10080

cd /opt/sming/samples/Basic_Blink
make
make flash
You can also try Sming without installing anything locally. We have an interactive tutorial that can be run directly from your browser.
Configuring your device¶
You may need to configure your project to support the specific device being programmed:
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 COM_PORT=/dev/ttyUSB3 COM_SPEED_ESPTOOL=921600
(For Windows or Windows WSL expect to use COM2, COM3, etc.)
Once you’re happy with the settings, you can add them to your project’s component.mk
file.
You may need to do this to reset the cached values:
make config-clean
The current set of configuration variables can be seen thus:
make list-config
Other hardware-specific settings are stored in the hardware configuration file. You can examine the current configuration like this:
make hwconfig
The standard config should work with all ESP8266 variants. If you want to use SPIFFS then you should add this line to your component.mk file:
HWCONFIG = spiffs
This expects your device to have at least 4MBytes of flash.
See Sming build system for further details about configuring your project.
See Features for configuring Sming options.
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.
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 your 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¶
void doUpgrade()
{
// need a clean object, otherwise if run before and failed will not run again
if(otaUpdater) {
delete otaUpdater;
}
otaUpdater = new Ota::Network::HttpUpgrader();
// select rom partition to flash
auto part = ota.getNextBootPartition();
// The content located on ROM_0_URL will be stored to the new partition
otaUpdater->addItem(ROM_0_URL, part);
// and/or set a callback (called on failure or success without switching requested)
otaUpdater->setCallback(upgradeCallback);
// start update
otaUpdater->start();
}
For a complete example take a look at the Basic Ota 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.
Networking¶
-
DISABLE_WIFI
¶ Note
EXPERIMENTAL
0 (Default) 1 - Remove core networking support
Applications which do not require networking can set this flag to avoid building or linking the core Networking Support library.
This will reduce build times, application size and RAM usage. Builds will not succeeded if network code has been inadvertently included.
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 reference
ObjectType
: 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 object
ObjectType
: Object type for reference
file
: 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
, typenameElementType
>
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 instantiated
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.
- size_t
length
() const¶Get the length of the content in elements.
- size_t
read
(size_t index, ElementType *buffer, size_t count) const¶Read content into RAM.
- Parameters
index
: First element to read
buffer
: Where to store data
count
: 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) const¶Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to read
buffer
: Where to store data
count
: How many elements to read- Return Value
size_t
: Number of elements actually readPublic 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 terminator
size()
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 lists
The 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 define
str
: 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 structure
str
: 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[] buffer
str
: 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 object
file
: 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 identicalArrays¶ 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 define
ElementType
:
...
: 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 structure
ElementType
:
...
: 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 object
ElementType
: Array element type
file
: 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
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¶ 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 define
ObjectType
:
...
: 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 define
ObjectType
:
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 structure
ObjectType
:
...
: 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 structure
ObjectType
:
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
: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¶
DECLARE_FSTR_MAP
(name, KeyType, ContentType)¶Declare a global Map& reference.
- Note
Use DEFINE_FSTR_MAP to instantiate the global object
- Parameters
name
: Name of the Map& reference to define
KeyType
: Integral type to use for key
ContentType
: Object type to declare for content
DEFINE_FSTR_MAP
(name, KeyType, ContentType, ...)¶Define a Map Object with global reference.
- Note
Size will be calculated
- Parameters
name
: Name of the Map& reference to define
KeyType
: Integral type to use for key
ContentType
: Object type to declare for content
...
: List of MapPair definitions { key, &content }
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 a Map Object with global reference, specifying the number of elements.
- Parameters
name
: Name of the Map& reference to define
KeyType
: Integral type to use for key
ContentType
: Object type to declare for content
size
: Number of elements
...
: List of MapPair definitions { key, &content }
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 structure
KeyType
: Integral type to use for key
ContentType
: 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 structure
KeyType
: Integral type to use for key
ContentType
: Object type to declare for content
size
: Number of elements
...
: List of MapPair definitions { key, &content }
- template<typename
KeyType
, classContentType
>
classMapPair
¶- #include <MapPair.hpp>
describes a pair mapping key => data for a specified key type
- Template Parameters
KeyType
: Integral, floating point, enum or String
ContentType
: Object type to use for contentClass Templates¶
- template<typename
KeyType
, classContentType
, classPair
= MapPair<KeyType, ContentType>>
classMap
: public FSTR::Object<Map<KeyType, ContentType>, Pair>¶Class template to access an associative map.
- Template Parameters
KeyType
:Public Functions
- const Pair
valueAt
(unsigned index) const¶Get a map entry by index, if it exists.
- Note
Result validity can be checked using if()
- template<typename
TRefKey
, typenameT
= KeyType>
std::enable_if<!std::is_class<T>::value, int>::typeindexOf
(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
, typenameT
= KeyType>
std::enable_if<std::is_same<T, String>::value, int>::typeindexOf
(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 Pairoperator[]
(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>
printer
() const¶Returns a printer object for this array.
- Note
ElementType must be supported by Print
- template<typename
KeyType
, classContentType
>
classMapPair
describes a pair mapping key => data for a specified key type
- Template Parameters
KeyType
: Integral, floating point, enum or String
ContentType
: Object type to use for contentPublic Functions
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
() const¶Get the key (String key type)
- const ContentType &
content
() const¶Accessor to get a reference to the content.
Public 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)¶Sming Integration¶ Sming provides several aliases to provide compatibility with existing code:
FlashString
->FSTR::String
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
objectUse 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
References¶
HostEd Component
HostEd¶
The hosted component allows Sming’s host emulator to run parts of the commands on an actual microcontroller. The communication is done via simplePRC and the microcontroller has to be flashed with a special application.
Overview¶ Sming’s host emulator allows easier debugging and development of embedded applications. This component named “Hosted” extends the host emulator and facilitates testing functionality that only a real microcontroller can provide as for example digital I/O operations or SPI operations.
For example in order to run the Basic_Blink application under the host emulator and run the actual blinking of a LED on a microcontroller we can compile the application using the following directives:
make SMING_ARCH=Host ENABLE_HOSTED=tcp HOSTED_SERVER_IP=192.168.4.1SMING_ARCH=Host instructs the build system to build the application for the Host architecture. ENABLE_HOSTED=tcp instructs the host emulator to communication with the real microcontroller using TCP HOSTED_SERVER_IP=192.168.4.1 instructs the host emulator to connect to IP 192.168.4.1.
We need to compile and flash also a special application on the desired microcontroller. This application will act as an RPC Server and will execute the commands from the host emulator on the microcontroller.
In the sub-directory
samples
inside this directory you will find the sample applications that will turn your microcontroller into RCP server.The compilation and flashing for ESP32, for example, can be done using the following commands:
cd samples/tcp make SMING_ARCH=Esp32 WIFI_SSID=YourSSID WIFI_PWD=YourPassword make flashIf you replace
SMING_ARCH=Esp32
withSMING_ARCH=Esp8266
then the hosted application will be compiled and flashed on a ESP8266 microcontroller. Make sure to replace the values of WIFI_SSID and WIFI_PWD with the actual name and password for the Access Point (AP).Communication¶ At the moment the communication between an application running on the Host and the RCP server running on a microcontroller can be done using TCP or serial interface. The
transport
classes are located underinclude/Hosted/Transport
.Configuration¶
ENABLE_HOSTED
¶Default: empty (disabled)
Enables the hosted component. Valid values for the moment are: - tcp - for communication over TCP network. - serial - for communication over serial interface
HOSTED_SERVER_IP
¶Default: 192.168.13.1
Used only when ENABLE_HOSTED=tcp is specified. Specifies the IP address of the remote RPC server.
HOSTED_COM_PORT
¶Default: /dev/ttyUSB0 or the value of the environment variable COM_PORT if defined
Used only when ENABLE_HOSTED=serial is specified. Specifies which local communication port should be used to connect to the remote RPC server.
HOSTED_COM_SPEED
¶Default: 115200
Used only when ENABLE_HOSTED=serial is specified. Specifies the communication baud rate.
References¶
References Component
Used by¶
References ,Component
Hosted RCP Server over TCP Sample
Environment Variables¶ Installable File System¶
Created for Sming Framework Project August 2018 by mikee47
I struggled to find anything like this for embedded systems. Probably didn’t look hard enough, but it seemed like a fun thing to do so here we are.
The term ‘IFS’ came about because of the ‘I’ naming convention for virtual ‘Interface’ classes, hence IFileSystem. The term ‘installable’ is entirely appropriate because IFS allows file systems to be loaded and unloaded dynamically. Or maybe I just nicked the term from Microsoft :-)
Overview¶ IFS is written in C++ and has these core components:
- FileSystem API
File systems are implemented using the
IFS::IFileSystem
virtual class. This is, in essence, a single large ‘function table’ you will see in regular filesystem implementations.Class methods are similar to SPIFFS (which is POSIX-like).
Note
A single
Stat
structure is used both for reading directory entries and for regularfileStat()
operations.This differs from regular file APIs but is intended to simplify operation.
Applications will typically use
IFS::FileSystem
instead, which adds additional methods and overloads such as String parameter support. This used to implement the standard ‘flat’ Sming filesystem API, with a few minor changes and a number of additions.Two wrapper clases (
IFS::File
andIFS::Directory
) are provided for applications to manage access to files and folders.- Firmware FileSystem (FWFS)
Files, directories and metadata are all stored as objects in read-only image. FWFS images are compact, fast to access and use very little RAM (approx. 240 bytes for file descriptors, etc.)
To support read/write data a writeable filesystem can be mounted in a sub-directory.
A python tool
fsbuild
is used to build an FWFS image from user files. See Filesystem builder.This is integrated into the build system using the
fwfs-build
target for the partition. Example Hardware configuration fragment:"partitions": { "fwfs1": { "address": "0x280000", "size": "0x60000", "type": "data", "subtype": "fwfs", "filename": "out/fwfs1.bin", "build": { "target": "fwfs-build", // To build a FWFS image "config": "fsimage.fwfs" // Configuration for the image } } }Sming provides the Basic IFS sample application which gives a worked example of this.
The following basic IFS implementations are provided in this library:
IFS::FWFS::FileSystem
Firmware Filesystem. It is designed to support all features of IFS, whereas other filesystems may only use a subset.
IFS::HYFS::FileSystem
Hybrid filesystem. Uses FWFS as the read-only root filesystem, with a writeable filesystem ‘layered’ on top.
When a file is opened for writing it is transparently copied to the SPIFFS partition so it can be updated. Wiping the SPIFFS partition reverts the filesystem to its original state.
Note that files marked as ‘read-only’ on the FWFS system are blocked from this behaviour.
IFS::Host::FileSystem
For Host architecture this allows access to the Linux/Windows host filesystem.
IFS::Gdb::FileSystem
When running under a debugger this allows access to the Host filesystem. (Currently only works for ESP8266.)
IFS (and FWFS) has the following features:
- Attributes
Files have a standard set of attribute flags plus modification time and simple role-based access control list (ACL).
- Directories
Fully supported, and can be enumerated with associated file information using a standard opendir/readdir/closedir function set.
- User metadata
Supported for application use. The API for this is loosely based on Linux extended attributes (non-POSIX). Attributes are small chunks of data attached to files and directories, each identified by a numeric
IFS::AttributeTag
.- Filesystem API
The Sming FileSystem functions are now wrappers around a single IFileSystem instance, which is provided by the application.
- Streaming classes
Sming provides IFS implementations for these so they can be constructed on any filesystem, not just the main (global) one.
- Dynamic loading
File systems may be loaded/created and unloaded/destroyed at runtime
- Multiple filesystems
Applications may use any supported filesystem, or write their own, or use any combination of existing filesystems to meet requirements. The API is the same.
- Mount points
FWFS is designed for use as a read-only root filing system, and supports mounting other filesystems in special directories.
FWFS¶ Many applications require a default, often fixed set of files. The easiest way is just to use SPIFFS. The problem is that power outages can corrupt a filesystem. For an embedded device that’s bad news. SPIFFS is also a bit overkill if you’re just storing configuration data, or it’s just for read-only use.
So what do you do if your filesystem gets wiped? Resetting a system back to a functional, default state can be tricky if the core user interface web files are gone. You could reformat and pull a standard set of files off a server somewhere. If your storage requirements are minimal, you could link the file data into your firmware as constant data blocks.
That’s kind of what FWFS does, but in a more structured and user-friendly way.
FWFS offers a more convenient solution by providing all your default files in a compact, fast, read-only format. Images can be mounted in separate partitions, linked into the program image itself or stored as files within another filesystem.
Note
This behaviour is supported by partitions (see Storage Management) using custom
Storage::Device
objects.Redirection¶ FWFS incorporates a redirector. This works by creating a mount point (a named object), which looks like an empty directory. When accessed, this get redirected to the root of another filesystem. The maximum number of mount points is fixed at compile time, but file systems can be mounted and dismounted at any time.
Mount points are identified explicitly in the build configuration file:
The filesystem builder creates the MountPoint objects and tags them with the given volume indices. For example, the directory “path/to/use/littlefs” is attached to volume index #0.
Note
Unlike other filesystems you cannot use a regular directory as a mountpoint. To change the name of a mountpoint requires the filesystem image to be re-built and re-flashed.
Applications use the
IFileSystem::setVolume()
method to install the actual filesystem.Streaming backup/archive support¶ The
IFS::FWFS::ArchiveStream
class can be used to generate streaming filesystem backups from any supported filesystem. The archive files are in FWFS format.Here are some examples of how it can be used:
Stream filesystem (or directory) images directly to remote servers
Make local filesystem backups
Compact log files which don’t change much (think of ZIP files - just needs a compression plugin)
Backup entire filesystem a local file, an empty partition, etc.
Defragment/compact or repair a damaged filesystem by re-formatting then restoring from backup
The archiver has some additional features:
Specify whether to archive an entire filesystem or start from a specific directory
Specify whether to follow links (e.g. other filesystems in mountpoints) or not
Exclude any file or directory via custom callback (or by overriding methods)
Perform custom file data encoding such as compression or encryption via callbacks
Add additional metadata to files (comments, encryption codes, etc.)
See the Basic IFS sample for
Access Control¶ This came about because I wanted to secure down my ESP8266 web server applications so that only the basic index.html, stylesheets and accompanying javascript would be publicly accessibly. Everything else would require user authentication.
I also wanted to prevent certain users from accessing restricted files. Other users would also be able to edit files. So a simple role-based access control mechanism seemed appropriate.
Access control typically encapsulates two areas:
- Authentication
Is the user who they say they are? Usually performed by validating a username/password combination.
- Authorisation
What is the user permitted to do?
I’ll step aside for a brief word on security. Authentication is the weakest link because it’s exposed to public scrutiny. To avoid compromise authentication must only be done over a secured link. That means SSL.
If you have the option it’s usually best to put all your smart devices behind a secure proxy. The raspberry Pi is great for stuff like this. The Pi deals with keeping the public connection secure, and translates it into a regular HTTP connection for the ESP8266.
If you don’t have this option, but you need to connect your ESP8266 to the internet, use the SSL build for Sming.
Having done this, we don’t need to worry about encrypting passwords as the SSL layer will do that. We just need to make sure they’re good passwords.
In my applications authentication is done by matching username/password against the user database, stored in a JSON file. If successful, the session gets a token which appears in every subsequent request. The user database indicates a User Role, one of public, guest, user, manager or admin. IFS keeps an ‘Access Control List’ (ACL) for each file containing two entries (ACE), one for read access and another for write access. The ACE specifies the minimum assigned
IFS::UserRole
required for access.This is probably as much as the filesystem needs to do. I can’t see that file ownership, inherited permissions or more finely-grained access permissions would be required, but having said that extending this system would probably be fairly straightforward.
Configuration filesystem¶ If an application only requires write access for configuration files, SPIFFS is overkill. These files would be updated very infrequently, so wear-levelling would be un-necessary. The names and number of files would probably also be known at build time, and an individual file could be limited to a fixed size, for example one or two flash sectors. A ConfigFileSystem implementation would not need to support file creation or deletion.
Such a system would require almost no static RAM allocation and code size would be tiny.
However, the LittleFS has excellent metadata support and is ideal for storing configuration information. This can be done using :IFS::FileSystem::setUserAttribute and read using :IFS::FileSystem::getUserAttribute or :IFS::FileSystem::enumAttributes.
Note
The ESP-IDF has a mechanism for flash-based configuration space via the
NVS
component. It is robust and flexible but uses a signficant amount of RAM for buffering which may preclude its use with the ESP8266.FWFS Objects¶ All files, directories and associated information elements are stored as ‘objects’. Files and directories are ‘named’ objects, which may contain other objects either directly or as references. Small objects (255 bytes or less) are stored directly, larger ones get their own file. Maximum object size is 16Mbytes.
File content is stored in un-named data objects. A named object can have any number of these and will be treated as a single entity for read/write operations. File ‘fragments’ do not need to be contiguous, and are reassembled during read operations.
Named objects can be enumerated using
IFS::IFileSystem::readdir()
. Internally, FWFS uses handles to access any named object. Handles are allocated from a static pool to avoid excessive dynamic (heap) allocation. Users can attach their own data to any named object using custom object types.The filesystem layout is displayed during initial mount if this library is built with
DEBUG_VERBOSE_LEVEL
= 3.Why FWFS?¶ There are many existing candidates for a read-only system, so why do we need another one? Here are some reasons:
SPIFFS and LittleFS could be used in read-only mode but they are not designed for space-efficiency. Images are therefore larger than necessary, sometimes considerably larger. This is also true of other such filesystems designed for Linux, etc.
FWFS is designed to produce the smallest possible images to conserve limited flash storage. It therefore has a high effective capacity, i.e. you can put a lot more in there than with other filesystems.
With ROMFS, for example, information is laid out with headers first, followed by data. The root directory and volume information are at the front.
FWFS works in reverse by writing out file contents first, then file headers and then directory records. The root directory comes at the end, followed by the volume information record. This allows images to be created as a stream because directory records can be efficiently constructed in RAM as each file or subdirectory record is written out. This keeps memory usage low.
In addition, checksums and additional metadata can be created while file data is written out. This could be required for compressing or encrypting the contents, or for error tolerance. For example, if corruption is encountered whilst reading file contents this can be noted in the metadata which is written out afterwards.
Filesystem images are therefore generated in a single pass, with each file or directory only read once.
Standard attribute support not well-suited to embedded microsystems.
The small set of standard metadata defined by IFS is designed to solve specific problems with typical IOT applications.
Code dependencies¶ Written initially for Sming, the library should be fairly portable to other systems.
No definitions from SPIFFS or other modules should be used in the public interface; such dependencies should be managed internally.
Applications should avoid using filesystem-dependent calls, structures or error codes. Such code, if necessary, should be placed into a separate module.
Implementation details¶ The traditional way to implement installable filing systems is using function tables, such as you’ll see in Linux. One reason is because the Linux kernel is written in C, not C++. For Sming, a virtual class seems the obvious choice, however there are some pros and cons.
- VMT
- Advantages
Compiler ensures correct ordering of methods, parameter type checking
Simpler coding
Extending and overriding is natural
- Function table
- Advantages
Portable to C applications (although with some fudging so are VMTs).
- Disadvantages
Care required to keep function order and parameters correct. Very likely we’d use a bunch of macros to deal with this.
Macros
We could #define the active filing system name which the FileSystem functions would map to the appropriate call. For example, fileOpen would get mapped to SPIFlashFileSystem_open(). We need to provide macros for defining file system functions.
- Advantages
Fast
- Disadvantages
Complicated
Prone to bugs
Not C++
Configuration variables¶
FWFS_DEBUG
¶default: 0
Set to 1 to enable more detailed debugging information.
API¶
- namespace
IFS
¶Access.h Access control definitions
Created on: 6 Jun 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Attribute.h
Created: April 2021
Copyright 2021 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Compression.h
Created on: 31 Aug 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Control.h
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Directory.h
Created: May 2019
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
File.h
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
FileAttributes.h
Created on: 31 Aug 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
FsBase.h Common base for file system classes
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
ArchiveStream.h
Copyright 2021 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
FileSystem.h FWFS - Firmware File System
Created on: 19 Jul 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Object.h Basic definitions for FW file system structure.
Created on: 7 Aug 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
A filesystem image is basically:
uint32_t START_MARKER; Object Objects[]; Object EndObject; uint32_t END_MARKER;An FWFS Object is a variable-length structure which can be read as either 1 or 2 words, depending on the type. Objects always start on a word boundary. File and directory objects are both emitted as ‘named’ objects which contain a list of zero or more child objects. When the image is built the child objects are emitted first, followed by the parent. This puts the root directory at the end of the image. This arrangement means an image can be generated without having to back-track and rewrite headers.
Child objects can be of any type. A directory object will mostly contain other file and directory objects. File data is stored in a data object, not in the file object itself. This is usually found following the file object, but it doesn’t have to be. Any object may be referenced by zero or more named object(s). For example, file links/aliases can contain references to the same file data. A file object may contain multiple data objects. These are treated as a contiguous block for file operations. This would potentially allow a file system builder to place common file blocks into shared data objects.
Object names are from 0 to 255 characters, inclusive. The root directory has a zero-length name. Paths lengths are unlimited. ‘/’ is used as the path separator. It informs the filesystem of the parent/child relationship between one directory object and a sub-ordinate. ‘:’ is used as the file stream separator. It performs the equivalent of the path separator for non-directory named objects. For exaample, file object may contain named objects accessible thus: index.html:info opens a handle to a named object called ‘info’ belonging to index.html.
OK, I admit it; this is pinched from NTFS; but it’s such a cool idea. Applications can use it to attach custom data to their files without limitation.
As a side note, of course FWFS is read-only. More precisely, it only supports random reading of files, not random writing. Serial writing is supported in the form of image creation.
For SPIFFS, IFS is a wrapper. The metadata features are supported using SPIFFS metadata. An alternative approach is to implement every named object as a SPIFFS file. We’d then get all the features of FWFS in a rewritable system, with all the benefits of SPIFFS wear-levelling.
Objects are identified by their index, but it’s not stored in the image. Instead, it’s tracked via internal object descriptor.
To optimise lookups, an object table can be stored at the end of the image. This is just an array of 32-bit image offsets so that an object can be located instantly on large volumes. This will be optional as it can consume significant space.
ObjectBuffer.h
Copyright 2021 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
FileSystem.h IFS wrapper for GDB syscall file access
Created on: 1 December 2020
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Helpers.h Helper functions to assist with standard filesystem creation
Created on: 27 Jan 2019
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
NameBuffer.h
Created on: 31 Aug 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
OpenFlags.h
Created on: 31 Aug 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
IProfiler.h - Abstract interface to implement filesystem profiling
Copyright 2021 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Stat.h
Created: August 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
TimeStamp.h
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
UserRole.h
Created on: 6 Jun 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Util.h Various bits for file system implementations to use
Created on: 10 Sep 2018
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Return compression corresponding to given string
- Parameters
str
:- Return Value
Compression::Type
:
- Compression::Type
getCompressionType
(const char *str, Compression::Type defaultValue = Compression::Type::None)¶Return the access type value for the given string.
- Parameters
str
:
defaultRole
: Returned if string isn’t recognsed- Return Value
UserRole
:Typedefs
- using
AttributeEnumCallback
= Delegate<bool(AttributeEnum &e)>¶Return true to continue enumeration, false to stop.
- using
ErrorCode
= int¶
- using
FileAttributes
= BitSet<uint8_t, FileAttribute, size_t(FileAttribute::MAX)>¶File attributes are stored as a bitmask.
- using
DirHandle
= struct ImplFileDir *¶Enums
- enum
ControlCode
¶See
IFS::IFileSystem::fcontrol
These are weakly typed as values may be defined elsewhere.
Values:
FCNTL_GET_MD5_HASH
= 1¶Get stored MD5 hash for file.
FWFS calculates this when the filesystem image is built and can be used by applications to verify file integrity.
On success, returns size of the hash itself (16) If the file is zero-length then Error::NotFound will be returned as the hash is not stored for empty files.
FCNTL_USER_BASE
= 0x8000¶Start of user-defined codes.
Codes before this are reserved for system use
- enum
OpenFlag
¶Values:
XX
MAX
- enum
UserRole
¶Values:
XX
MAX
Actually maxmimum value + 1…
Functions
- String
getAclString
(const IFS::ACL &acl)¶Return a brief textual representation for an ACL Suitable for inclusion in a file listing.
- Parameters
acl
:- Return Value
- AttributeTag
getUserAttributeTag
(uint8_t value)¶
- size_t
getAttributeSize
(AttributeTag tag)¶
struct IFS::__attribute__((packed))
A compression descriptor.
- String
getFileAttributeString
(FileAttributes attr)¶Get the string representation for the given set of file attributes suitable for inclusion in a file listing.
- Parameters
attr
:- Return Value
- FileSystem *
createFirmwareFilesystem
(Storage::Partition partition)¶Create a firmware filesystem.
- Parameters
partition
:- Return Value
FileSystem*
: constructed filesystem object
- FileSystem *
createHybridFilesystem
(Storage::Partition fwfsPartition, IFileSystem *flashFileSystem)¶Create a hybrid filesystem.
- Parameters
fwfsPartition
: Base read-only filesystem partition
flashFileSystem
: The filesystem to use for writing- Return Value
FileSystem*
: constructed filesystem object
- time_t
fsGetTimeUTC
()¶Get current timestamp in UTC.
- Note
Filing systems must store timestamps in UTC Use this function; makes porting easier.
- Return Value
time_t
:
- bool
isRootPath
(const char *&path)¶Check if path is root directory.
Paths equal to “/” or “” are empty and considered equivalent to nullptr. Methods or functions can use this macro to resolve these for simpler parsing.
- Parameters
Path
: to check, set to nullptr if it’s the root directory- Return Value
bool
: true if path is root directory
- struct
AttributeEnum
¶- #include <Attribute.h>
Attribute information passed to enumeration callback.
- class
Directory
: public IFS::FsBase¶- #include <Directory.h>
Wrapper class for enumerating a directory.
Subclassed by Directory
Public Functions
- bool
open
(const String &dirName = nullptr)¶Open a directory and attach this stream object to it.
- Note
call getLastError() to determine cause of failure
- Parameters
dirName
: Default is root directory- Return Value
bool
: true on success, false on error
- void
close
()¶Close directory.
- bool
rewind
()¶Rewind directory stream to start so it can be re-enumerated.
- Note
call getLastError() to determine cause of failure
- Return Value
bool
: true on success, false on error
- const String &
getDirName
() const¶Name of directory stream is attached to.
- Return Value
String
: invalid if stream isn’t open
- bool
dirExist
() const¶Determine if directory exists.
- Return Value
bool
: true if stream is attached to a directory
- class
DirectoryTemplate
: public SectionTemplate¶- #include <DirectoryTemplate.h>
Directory stream class.
Subclassed by IFS::HtmlDirectoryTemplate, IFS::JsonDirectoryTemplate
Public Functions
- bool
nextRecord
()¶Move to next record.
- Return Value
bool
: true to emit section, false to skip
- class
File
: public IFS::FsBase¶- #include <File.h>
Wraps up all file access methods.
Subclassed by File
Public Functions
- bool
stat
(Stat &stat)¶get file information
- Parameters
stat
: structure to return information in, may be null- Return Value
bool
: true on success
- int
control
(ControlCode code, void *buffer, size_t bufSize)¶Low-level and non-standard file control operations.
To simplify usage the same buffer is used for both input and output. Only the size of the buffer is provided. If a specific FCNTL code requires more information then it will be contained within the provided data.
- Parameters
code
: FCNTL_XXX code
buffer
: Input/Output buffer
bufSize
: Size of buffer- Return Value
int
: error code or, on success, data size
- template<typename
T
>
boolopen
(const T &path, OpenFlags flags = OpenFlag::Read)¶open a file by name/path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
bool
: true on success
- bool
close
()¶close an open file
- Return Value
bool
: true on success
- int
read
(void *data, size_t size)¶read content from a file and advance cursor
- Parameters
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- int
write
(const void *data, size_t size)¶write content to a file at current position and advance cursor
- Parameters
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- int
seek
(int offset, SeekOrigin origin)¶change file read/write position
- Parameters
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- bool
eof
()¶determine if current file position is at end of file
- Return Value
bool
: true if at EOF or file is invalid
- int32_t
tell
()¶get current file position
- Return Value
int32_t
: current position relative to start of file, or error code
- bool
truncate
(size_t new_size)¶Truncate (reduce) the size of an open file.
- Parameters
newSize
:- Return Value
bool
: true on success
- bool
truncate
()¶Truncate an open file at the current cursor position.
- Return Value
bool
: true on success
- bool
flush
()¶flush any buffered data to physical media
- Return Value
bool
: true on success
- bool
setacl
(const ACL &acl)¶Set access control information for file.
- Parameters
acl
:- Return Value
bool
: true on success
- bool
settime
(time_t mtime)¶Set modification time for file.
- Note
any subsequent writes to file will reset this to current time
- Return Value
bool
: true on success
- bool
setcompression
(const Compression &compression)¶Set file compression information.
- Parameters
compression
:- Return Value
bool
: true on success
- bool
remove
()¶remove (delete) an open file (and close it)
- Return Value
bool
: true on success
- uint32_t
getSize
()¶Get size of file.
- Return Value
uint32_t
: Size of file in bytes, 0 on error
- int
readContent
(size_t size, ReadContentCallback callback)¶Read from current file position and invoke callback for each block read.
- Parameters
size
: Maximum number of bytes to read
callback
:- Return Value
int
: Number of bytes processed, or error code
- int
readContent
(ReadContentCallback callback)¶Read from current file position to end of file and invoke callback for each block read.
- Parameters
callback
:- Return Value
int
: Number of bytes processed, or error code
- String
getContent
()¶Read content of a file.
- Note
After calling this function the content of the file is placed in to a string. The result will be an invalid String (equates to
false
) if the file could not be read. If the file exists, but is empty, the result will be an empty string “”.- Parameters
fileName
: Name of file to read from- Return Value
- struct
FileNameBuffer
: public IFS::NameBuffer¶- #include <NameBuffer.h>
a quick’n’dirty name buffer with maximum path allocation
- class
FileStream
: public IFS::FsBase, public ReadWriteStream¶- #include <FileStream.h>
File stream class.
Subclassed by FileStream, GdbFileStream, HostFileStream
Public Functions
- void
attach
(FileHandle file, size_t size)¶Attach this stream object to an open file handle.
- Parameters
file
:
size
:
- bool
open
(const String &fileName, IFS::OpenFlags openFlags = OpenFlag::Read)¶Open a file by path, and attach this stream object to it.
- Note
call getLastError() to determine cause of failure
- Parameters
fileName
: Full path to file
openFlags
:- Return Value
bool
: true on success, false on error
- bool
open
(DirHandle dir, const String &name, OpenFlags openFlags = OpenFlag::Read)¶Open a file and attach this stream object to it.
- Note
call getLastError() to determine cause of failure
- Parameters
dir
: Location of file
fileName
: Name of file
openFlags
:- Return Value
bool
: true on success, false on error
- void
close
()¶Close file.
- StreamType
getStreamType
() const¶Get the stream type.
- Return Value
StreamType
: The stream type.
- size_t
write
(const uint8_t *buffer, size_t size)¶Write chars to stream.
- Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters
buffer
: Pointer to buffer to write to the stream
size
: Quantity of chars to write- Return Value
size_t
: Quantity of chars written to stream
- int
read
()¶Read one character and moves the stream pointer.
- Return Value
The
: character that was read or -1 if none is available
- size_t
readBytes
(char *buffer, size_t length)¶Read chars from stream into buffer.
Terminates if length characters have been read or timeout (see setTimeout). Returns the number of characters placed in the buffer (0 means no valid data found).
- Note
Inherited classes may provide more efficient implementations without timeout.
- uint16_t
readMemoryBlock
(char *data, int bufSize)¶Read a block of memory.
- Parameters
data
: Pointer to the data to be read
bufSize
: Quantity of chars to read- Return Value
uint16_t
: Quantity of chars read
- int
seekFrom
(int offset, SeekOrigin 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
:- Return Value
New
: position, < 0 on error
- bool
isFinished
()¶Check if all data has been read.
- Return Value
bool
: True on success.
- String
fileName
() const¶Filename of file stream is attached to.
- Return Value
String
: invalid if stream isn’t open
- bool
fileExist
() const¶Determine if file exists.
- Return Value
bool
: true if stream contains valid file
- String
getName
() const¶Returns name of the resource.
- Note
Commonly used to obtain name of file
- Return Value
- MimeType
getMimeType
() const¶Get MIME type for stream content.
- Return Value
MimeType
:
- 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
- size_t
getPos
() const¶Get the offset of cursor from beginning of data.
- Return Value
size_t
: Cursor offset
- int
available
()¶Return the maximum bytes available to read, from current position.
- Return Value
int
: -1 is returned when the size cannot be determined
- String
id
() const¶Returns unique id of the resource.
- Return Value
String
: the unique id of the stream.
- bool
truncate
(size_t newSize)¶Reduce the file size.
- Parameters
newSize
:- Return Value
bool
: true on success
- bool
truncate
()¶Truncate file at current position.
- Return Value
bool
: true on success
- class
FileSystem
: public IFS::IFileSystem¶- #include <FileSystem.h>
Installable File System base class.
Adds additional methods to ease use over base IFileSystem.
rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- using
ReadContentCallback
= Delegate<int(const char *buffer, size_t size)>¶Callback for readContent method.
- Parameters
buffer
:
size
:- Return Value
int
: Return number of bytes consumed, < size to stop If < 0 then this is returned as error code toreadContent
call.
- int
remove
(const String &path)¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- template<typename
T
>
intsetacl
(const T &file, const ACL &acl)¶Set access control information for file.
- Parameters
file
: handle or path to file
acl
:- Return Value
int
: error code
- template<typename
T
>
intsetattr
(const T &file, FileAttributes attr)¶Set file attributes.
- Parameters
file
: handle or path to file
attr
:- Return Value
int
: error code
- template<typename
T
>
intsettime
(const T &file, time_t mtime)¶Set modification time for file.
- Note
any subsequent writes to file will reset this to current time
- Parameters
file
: handle or path to file- Return Value
int
: error code
- template<typename
T
>
intsetcompression
(const T &file, const Compression &compression)¶Set file compression information.
- Parameters
file
:
compression
:- Return Value
int
: error code
- uint32_t
getSize
(FileHandle file)¶Get size of file.
- Parameters
file
: File handle- Return Value
uint32_t
: Size of file in bytes, 0 on error
- uint32_t
getSize
(const char *fileName)¶Get size of file.
- Parameters
fileName
: Name of file- Return Value
uint32_t
: Size of file in bytes, 0 on error
- int
readContent
(FileHandle file, size_t size, ReadContentCallback callback)¶Read from current file position and invoke callback for each block read.
- Parameters
file
:
size
: Maximum number of bytes to read
callback
:- Return Value
int
: Number of bytes processed, or error code
- int
readContent
(FileHandle file, ReadContentCallback callback)¶Read from current file position to end of file and invoke callback for each block read.
- Parameters
file
:
callback
:- Return Value
int
: Number of bytes processed, or error code
- int
readContent
(const String &filename, ReadContentCallback callback)¶Read entire file content in blocks, invoking callback after every read.
- Parameters
filename
:
callback
:- Return Value
int
: Number of bytes processed, or error codeRead content of a file
After calling this function the content of the file is placed in to a c-string Ensure there is sufficient space in the buffer for file content plus extra trailing null, i.e. at least bufSize + 1 Always check the return value!
- Parameters
fileName
: Name of file to read from
buffer
: Pointer to a character buffer in to which to read the file content
bufSize
: Quantity of bytes to read from file- Return Value
size_t
: Quantity of bytes read from file or zero on failureReturns 0 if the file could not be read
Create or replace file with defined content
This function creates a new file or replaces an existing file and populates the file with the content of a c-string buffer.
- Parameters
fileName
: Name of file to create or replace
content
: Pointer to c-string containing content to populate file with- Return Value
int
: Number of bytes transferred or error code- Parameters
length
: (optional) number of characters to writePublic Functions
- int
makedirs
(const char *path)¶Create a directory and any intermediate directories if they do not already exist.
- Parameters
path
: Path to directory. If no trailing ‘/’ is present the final element is considered a filename.- Return Value
int
: error code
- int
truncate
(const char *fileName, size_t newSize)¶Truncate a file to a specific size.
- Parameters
fileName
: File to truncate- Return Value
int
: new file size, or error code
- String
getContent
(const String &fileName)¶Read content of a file.
- Note
After calling this function the content of the file is placed in to a string. The result will be an invalid String (equates to
false
) if the file could not be read. If the file exists, but is empty, the result will be an empty string “”.- Parameters
fileName
: Name of file to read from- Return Value
- class
FsBase
¶- #include <FsBase.h>
Subclassed by IFS::Directory, IFS::File, IFS::FileStream, IFS::FWFS::ArchiveStream
Public Functions
- int
getLastError
()¶determine if an error occurred during operation
- Return Value
int
: filesystem error code
- class
HtmlDirectoryTemplate
: public IFS::DirectoryTemplate¶- #include <HtmlDirectoryTemplate.h>
Read-only stream access to directory listing with HTML output.
- class
IFileSystem
¶- #include <IFileSystem.h>
Installable File System base class.
Construction and initialisation of a filing system is implementation-dependent so there are no methods here for that.
- Note
The ‘I’ implies Installable but could be for Interface :-)
Methods are defined as virtual abstract unless we actually have a default base implementation. Whilst some methods could just return Error::NotImplemented by default, keeping them abstract forces all file system implementations to consider them so provides an extra check for completeness.
Subclassed by IFS::FileSystem, IFS::FWFS::FileSystem, IFS::Gdb::FileSystem, IFS::Host::FileSystem, IFS::HYFS::FileSystem
Public Functions
- virtual
~IFileSystem
()¶Filing system implementations should dismount and cleanup here.
- virtual int
mount
() = 0¶Mount file system, performing any required initialisation.
- Return Value
error
: code
- virtual int
getinfo
(Info &info) = 0¶get filing system information
- Parameters
info
: structure to read information into- Return Value
int
: error code
- virtual int
setProfiler
(IProfiler *profiler)¶Set profiler instance to enable debugging and performance assessment.
- Parameters
profiler
:- Return Value
int
: error code - profiling may not be supported on all filesystems
- virtual int
setVolume
(uint8_t index, IFileSystem *fileSystem)¶Set volume for mountpoint.
- Parameters
index
: Volume index
fileSystem
: The filesystem to root at this mountpoint- Return Value
int
: error code
- virtual int
opendir
(const char *path, DirHandle &dir) = 0¶open a directory for reading
- Parameters
path
: path to directory. nullptr is interpreted as root directory
dir
: returns a pointer to the directory object- Return Value
int
: error code
- virtual int
readdir
(DirHandle dir, Stat &stat) = 0¶read a directory entry
- Note
File system allocates entries structure as it usually needs to track other information. It releases memory when closedir() is called.
- Parameters
dir
:
stat
:- Return Value
int
: error code
- virtual int
rewinddir
(DirHandle dir) = 0¶Reset directory read position to start.
- Parameters
dir
:- Return Value
int
: error code
- virtual int
closedir
(DirHandle dir) = 0¶close a directory object
- Parameters
dir
: directory to close- Return Value
int
: error code
- virtual int
mkdir
(const char *path) = 0¶Create a directory.
Only the final directory in the path is guaranteed to be created. Usually, this call will fail if intermediate directories are not present. Use
makedirs()
for this purpose.
- Parameters
path
: Path to directory- Return Value
int
: error code
- virtual int
stat
(const char *path, Stat *stat) = 0¶get file information
- Parameters
path
: name or path of file
s
: structure to return information in, may be null to do a simple file existence check- Return Value
int
: error code
- virtual int
fstat
(FileHandle file, Stat *stat) = 0¶get file information
- Parameters
file
: handle to open file
stat
: structure to return information in, may be null- Return Value
int
: error code
- virtual int
fcontrol
(FileHandle file, ControlCode code, void *buffer, size_t bufSize)¶Low-level and non-standard file control operations.
To simplify usage the same buffer is used for both input and output. Only the size of the buffer is provided. If a specific FCNTL code requires more information then it will be contained within the provided data.
- Parameters
file
:
code
: FCNTL_XXX code
buffer
: Input/Output buffer
bufSize
: Size of buffer- Return Value
int
: error code or, on success, data size
- virtual FileHandle
open
(const char *path, OpenFlags flags) = 0¶open a file by path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
FileHandle
: file handle or error code
- virtual int
close
(FileHandle file) = 0¶close an open file
- Parameters
file
: handle to open file- Return Value
int
: error code
- virtual int
read
(FileHandle file, void *data, size_t size) = 0¶read content from a file and advance cursor
- Parameters
file
: handle to open file
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- virtual int
write
(FileHandle file, const void *data, size_t size) = 0¶write content to a file at current position and advance cursor
- Parameters
file
: handle to open file
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- virtual int
lseek
(FileHandle file, int offset, SeekOrigin origin) = 0¶change file read/write position
- Parameters
file
: handle to open file
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- virtual int
eof
(FileHandle file) = 0¶determine if current file position is at end of file
- Parameters
file
: handle to open file- Return Value
int
: 0 - not EOF, > 0 - at EOF, < 0 - error
- virtual int32_t
tell
(FileHandle file) = 0¶get current file position
- Parameters
file
: handle to open file- Return Value
int32_t
: current position relative to start of file, or error code
- virtual int
ftruncate
(FileHandle file, size_t new_size) = 0¶Truncate (reduce) the size of an open file.
- Note
In POSIX
ftruncate()
can also make the file bigger, however SPIFFS can only reduce the file size and will return an error if newSize > fileSize- Parameters
file
: Open file handle, must have Write access
newSize
:- Return Value
int
: Error code
- virtual int
flush
(FileHandle file) = 0¶flush any buffered data to physical media
- Parameters
file
: handle to open file- Return Value
int
: error code
- virtual int
fsetxattr
(FileHandle file, AttributeTag tag, const void *data, size_t size) = 0¶Set an extended attribute on an open file.
- virtual int
fgetxattr
(FileHandle file, AttributeTag tag, void *buffer, size_t size) = 0¶Get an extended attribute from an open file.
- Parameters
file
: handle to open file
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- virtual int
fenumxattr
(FileHandle file, AttributeEnumCallback callback, void *buffer, size_t bufsize) = 0¶Enumerate attributes.
- Parameters
file
: handle to open file
callback
: Callback function to invoke for each attribute found
buffer
: Buffer to use for reading attribute data. Use nullptr if only tags are required
bufsize
: Size of buffer- Return Value
int
: error code, on success returns number of attributes read
- virtual int
setxattr
(const char *path, AttributeTag tag, const void *data, size_t size) = 0¶Set an extended attribute for a file given its path.
- Parameters
path
: Full path to file (or directory)
tag
: The attribute to write
data
: Content of the attribute. Pass nullptr to remove the attribute (if possible).
size
: Size of the attribute in bytes- Return Value
int
: error code
- virtual int
getxattr
(const char *path, AttributeTag tag, void *buffer, size_t size) = 0¶Get an attribute from a file given its path.
- Parameters
file
: Full path to file (or directory)
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- virtual int
rename
(const char *oldpath, const char *newpath) = 0¶rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- virtual int
remove
(const char *path) = 0¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- virtual int
fremove
(FileHandle file) = 0¶remove (delete) a file by handle
- Parameters
file
: handle to open file- Return Value
int
: error code
- virtual int
format
() = 0¶format the filing system
- Note
this does a default format, returning file system to a fresh state The filing system implementation may define more specialised methods which can be called directly.
- Return Value
int
: error code
- virtual int
check
()¶Perform a file system consistency check.
- Note
if possible, issues should be resolved. Returns 0 if file system checked out OK. Otherwise there were issues: < 0 for unrecoverable errors,
- Return Value
int
: error code
- struct
Info
¶- #include <IFileSystem.h>
Basic information about filing system.
Subclassed by IFS::IFileSystem::NameInfo
Public Members
- Type
type
= {}¶The filing system type identifier.
- Attributes
attr
= {}¶Attribute flags.
- size_t
maxNameLength
= {255}¶Maximum length of a single file name.
- size_t
maxPathLength
= {255}¶Maximum length of a full file path.
- uint32_t
volumeID
= {0}¶Unique identifier for volume.
- NameBuffer
name
¶Buffer for name.
- uint32_t
volumeSize
= {0}¶Size of volume, in bytes.
- uint32_t
freeSpace
= {0}¶Available space, in bytes.
- struct
NameInfo
: public IFS::IFileSystem::Info¶- #include <IFileSystem.h>
Filing system information with buffer for name.
- class
IProfiler
¶- #include <Profiler.h>
Filesystems may optionally provide performance statistics.
Subclassed by IFS::Profiler
Public Functions
- virtual void
read
(uint32_t address, const void *buffer, size_t size) = 0¶Called AFTER reading a block of data.
- virtual void
write
(uint32_t address, const void *buffer, size_t size) = 0¶Called BEFORE writing a block of data.
- virtual void
erase
(uint32_t address, size_t size) = 0¶Called BEFORE an erase operation.
- class
JsonDirectoryTemplate
: public IFS::DirectoryTemplate¶- #include <JsonDirectoryTemplate.h>
Read-only stream providing directory listing in JSON format.
- struct
NameBuffer
¶- #include <NameBuffer.h>
defines a ‘safe’ name buffer
There are fancier ways to do this but a structure is transparent and requires no heap allocation.
- Note
Instead of including a fixed name array in Stat (and IFileSystem::Info) structures, we use a NameBuffer to identify a separate buffer. This has several advantages:
- Maximum size is not fixed - Finding and copying the name is optional - Actual name length is returned in the 'length' field, regardless of size - A NameBuffer structure (or one containing it) only requires initialising once before a loop operation as buffer/size are preserved.
- Note
length
always reflects the required name/path length, and may be longer than size.Subclassed by IFS::FileNameBuffer
Public Functions
NameBuffer
(String &s)¶Make a NameBuffer point to contents of a String.
- int
copy
(const char *src, uint16_t srclen)¶copies text from a source buffer into a name buffer
- Note
length field is always set to srclen, regardless of number of characters copied.
- Parameters
src
: source name
srclen
: number of characters in name
- int
addSep
()¶When building file paths this method simplified appending separators.
- Note
if the path is not empty, a separator character is appended
- Return Value
int
: error code
- char *
endptr
()¶get a pointer to the next write position
- Note
use space() to ensure buffer doesn’t overrun When writing text be sure to call terminate() when complete
- Return Value
char*
:
- uint16_t
space
()¶get the number of free characters available
- Note
returns 0 if buffer has overrun
- Return Value
uint16_t
:
- void
terminate
()¶ensure the buffer has a nul terminator, even if it means overwriting content
- bool
overflow
() const¶determine if name buffer overflowed
- Note
Compares returned length with buffer size; A nul terminator is always appended, so size should be >= (length + 1)
- struct
NameStat
: public IFS::Stat¶- #include <Stat.h>
version of Stat with integrated name buffer
- Note
provide for convenience
- struct
Stat
¶- #include <Stat.h>
File Status structure.
Subclassed by IFS::NameStat
Public Functions
Public Members
- IFileSystem *
fs
= {nullptr}¶The filing system owning this file.
- NameBuffer
name
¶Name of file.
- uint32_t
size
= {0}¶Size of file in bytes.
- struct
TimeStamp
¶- #include <TimeStamp.h>
Manage IFS timestamps stored as an unsigned 32-bit value.
A signed 32-bit value containing seconds will overflow in about 136 years. time_t starts at 1970.
- namespace
Error
¶Functions
- namespace
FWFS
¶Functions
- FileAttributes
getFileAttributes
(Object::Attributes objattr)¶
- Object::Attributes
getObjectAttributes
(FileAttributes fileAttr)¶Variables
- constexpr size_t
FWFS_BASE_OFFSET
= {sizeof(uint32_t)}¶
- constexpr uint32_t
FWFILESYS_START_MARKER
= {0x53465746}¶
- constexpr uint32_t
FWFILESYS_END_MARKER
= {0x46574653}¶
- class
ArchiveStream
: public IFS::FsBase, public IDataSourceStream¶- #include <ArchiveStream.h>
Supports direct streaming into FWFS archive format.
Data needs to be enumerated so that all child files and directories are written first. As this happens, the parent directory is built as a list of object references.
The size of all child objects must be known before the containing object is written out. It should be sufficient to buffer all of these into an internal stream. This would only be a problem if large child objects are used. This is possible, but the builder avoids doing it and we should too.
Top-level object is a Volume, below that is the root Directory. That means objects are written in the order: child files/directories Root directory Volume End marker
Subclassed by ArchiveStream
Public Functions
ArchiveStream
(FileSystem *fileSystem, VolumeInfo volumeInfo, String rootPath = nullptr, Flags flags = 0)¶Construct an archive stream.
- Parameters
fileSystem
: The filesystem to read
rootPath
: Where to root the generated filesystem
flags
:
- virtual bool
filterStat
(const Stat &stat)¶Override this method to filter items.
Use to omit temporary files or directories.
- Parameters
stat
: The current item- Return Value
bool
: Return true to process the item, false to skip it
- virtual IBlockEncoder *
createEncoder
(FileInfo &file)¶Override this method to implement custom encoding such as compression or encryption.
To support compression or encryption, this method can create the appropriate stream type and set the appropriate attributes using methods of
FileInfo
.
- Parameters
file
: Details of the file being archived- Return Value
IBlockEncoder*
: Stream to use for file content. Return nullptr for default behaviour.
- uint16_t
readMemoryBlock
(char *data, int bufSize)¶Read a block of memory.
- Parameters
data
: Pointer to the data to be read
bufSize
: Quantity of chars to read- Return Value
uint16_t
: Quantity of chars read
- int
seekFrom
(int offset, SeekOrigin 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
:- Return Value
New
: position, < 0 on error
- bool
isFinished
()¶Check if all data has been read.
- Return Value
bool
: True on success.
- MimeType
getMimeType
() const¶Get MIME type for stream content.
- Return Value
MimeType
:
- void
reset
()¶Reset stream to beginning.
- class
FileInfo
¶- #include <ArchiveStream.h>
Passed to callbacks to allow modification of output data.
Public Functions
- int
setAttribute
(AttributeTag tag, const void *data, size_t size)¶Set an additional attribute on the file.
These are written out before existing file metadata is copied, so will take priority. For example, if we set the compression attribute here then that is the one which the filesystem will use when mounted. However, the original compression attribute will still be present which may be helpful.
- template<typename ...
ParamTypes
>
intsetUserAttribute
(uint8_t tagValue, ParamTypes... params)¶Set an additional user attribute.
- struct
VolumeInfo
¶- #include <ArchiveStream.h>
- class
BasicEncoder
: public IFS::FWFS::IBlockEncoder¶- #include <BlockEncoder.h>
Public Functions
- IDataSourceStream *
getNextStream
()¶this method and return nullptr when all blocks have been encoded.
The stream returned must know it’s size (i.e. available() must not return -1). The encoder owns any stream objects created so is responsible for destroying them when finished. This allows them to be re-used if appropriate.
- class
FileSystem
: public IFS::IFileSystem¶- #include <FileSystem.h>
Implementation of firmware filing system using IFS.
Public Functions
- int
mount
()¶Mount file system, performing any required initialisation.
- Return Value
error
: code
- int
getinfo
(Info &info)¶get filing system information
- Parameters
info
: structure to read information into- Return Value
int
: error code
- int
setVolume
(uint8_t index, IFileSystem *fileSystem)¶Set volume for mountpoint.
- Parameters
index
: Volume index
fileSystem
: The filesystem to root at this mountpoint- Return Value
int
: error code
- int
opendir
(const char *path, DirHandle &dir)¶open a directory for reading
- Parameters
path
: path to directory. nullptr is interpreted as root directory
dir
: returns a pointer to the directory object- Return Value
int
: error code
- int
readdir
(DirHandle dir, Stat &stat)¶read a directory entry
- Note
File system allocates entries structure as it usually needs to track other information. It releases memory when closedir() is called.
- Parameters
dir
:
stat
:- Return Value
int
: error code
- int
rewinddir
(DirHandle dir)¶Reset directory read position to start.
- Parameters
dir
:- Return Value
int
: error code
- int
closedir
(DirHandle dir)¶close a directory object
- Parameters
dir
: directory to close- Return Value
int
: error code
- int
mkdir
(const char *path)¶Create a directory.
Only the final directory in the path is guaranteed to be created. Usually, this call will fail if intermediate directories are not present. Use
makedirs()
for this purpose.
- Parameters
path
: Path to directory- Return Value
int
: error code
- int
stat
(const char *path, Stat *stat)¶get file information
- Parameters
path
: name or path of file
s
: structure to return information in, may be null to do a simple file existence check- Return Value
int
: error code
- int
fstat
(FileHandle file, Stat *stat)¶get file information
- Parameters
file
: handle to open file
stat
: structure to return information in, may be null- Return Value
int
: error code
- int
fcontrol
(FileHandle file, ControlCode code, void *buffer, size_t bufSize)¶Low-level and non-standard file control operations.
To simplify usage the same buffer is used for both input and output. Only the size of the buffer is provided. If a specific FCNTL code requires more information then it will be contained within the provided data.
- Parameters
file
:
code
: FCNTL_XXX code
buffer
: Input/Output buffer
bufSize
: Size of buffer- Return Value
int
: error code or, on success, data size
- int
fsetxattr
(FileHandle file, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute on an open file.
- int
fgetxattr
(FileHandle file, AttributeTag tag, void *buffer, size_t size)¶Get an extended attribute from an open file.
- Parameters
file
: handle to open file
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- int
fenumxattr
(FileHandle file, AttributeEnumCallback callback, void *buffer, size_t bufsize)¶Enumerate attributes.
- Parameters
file
: handle to open file
callback
: Callback function to invoke for each attribute found
buffer
: Buffer to use for reading attribute data. Use nullptr if only tags are required
bufsize
: Size of buffer- Return Value
int
: error code, on success returns number of attributes read
- int
setxattr
(const char *path, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute for a file given its path.
- Parameters
path
: Full path to file (or directory)
tag
: The attribute to write
data
: Content of the attribute. Pass nullptr to remove the attribute (if possible).
size
: Size of the attribute in bytes- Return Value
int
: error code
- int
getxattr
(const char *path, AttributeTag tag, void *buffer, size_t size)¶Get an attribute from a file given its path.
- Parameters
file
: Full path to file (or directory)
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- FileHandle
open
(const char *path, OpenFlags flags)¶open a file by path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
FileHandle
: file handle or error code
- int
close
(FileHandle file)¶close an open file
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
read
(FileHandle file, void *data, size_t size)¶read content from a file and advance cursor
- Parameters
file
: handle to open file
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- int
write
(FileHandle file, const void *data, size_t size)¶write content to a file at current position and advance cursor
- Parameters
file
: handle to open file
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- int
lseek
(FileHandle file, int offset, SeekOrigin origin)¶change file read/write position
- Parameters
file
: handle to open file
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- int
eof
(FileHandle file)¶determine if current file position is at end of file
- Parameters
file
: handle to open file- Return Value
int
: 0 - not EOF, > 0 - at EOF, < 0 - error
- int32_t
tell
(FileHandle file)¶get current file position
- Parameters
file
: handle to open file- Return Value
int32_t
: current position relative to start of file, or error code
- int
ftruncate
(FileHandle file, size_t new_size)¶Truncate (reduce) the size of an open file.
- Note
In POSIX
ftruncate()
can also make the file bigger, however SPIFFS can only reduce the file size and will return an error if newSize > fileSize- Parameters
file
: Open file handle, must have Write access
newSize
:- Return Value
int
: Error code
- int
flush
(FileHandle file)¶flush any buffered data to physical media
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
rename
(const char *oldpath, const char *newpath)¶rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- int
remove
(const char *path)¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- int
fremove
(FileHandle file)¶remove (delete) a file by handle
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
format
()¶format the filing system
- Note
this does a default format, returning file system to a fresh state The filing system implementation may define more specialised methods which can be called directly.
- Return Value
int
: error code
- int
check
()¶Perform a file system consistency check.
- Note
if possible, issues should be resolved. Returns 0 if file system checked out OK. Otherwise there were issues: < 0 for unrecoverable errors,
- Return Value
int
: error code
- class
IBlockEncoder
¶- #include <BlockEncoder.h>
Virtual base class to support (file) data encryption and compression.
Encryption and compression are typically done in blocks of a fixed size. To support these operations an instance of this class is created which encodes data one block at a time. Each block is stored separately and the resulting file consists of a chain of these blocks. This is natively supported by FWFS.
If the final data size is known in advance then the implementation will return just a single data stream.
Subclassed by IFS::FWFS::BasicEncoder
Public Functions
- virtual IDataSourceStream *
getNextStream
() = 0¶this method and return nullptr when all blocks have been encoded.
The stream returned must know it’s size (i.e. available() must not return -1). The encoder owns any stream objects created so is responsible for destroying them when finished. This allows them to be re-used if appropriate.
- struct
Object
¶- #include <Object.h>
Object structure.
- Note
all objects conform to this structure. Only the first word (4 bytes) are required to nagivate the file system. All objects have an 8, 16 or 24-bit size field. Content is always immediately after this field. Reference objects are always 8-bit sized.
Public Types
- enum
Attribute
¶Object attributes.
- Note
these are bit values
Values:
Archive
¶Object modified flag.
- Note
Object has been changed on disk. Typically used by backup applications
Encrypted
¶Object data is encrypted.
This is just a hint. Applications will typically provide additional user metadata to provide any additional information required for decryption.
MAX
¶Public Functions
- size_t
contentOffset
() const¶return offset to start of object content
- uint32_t
contentSize
() const¶return size of object content, excluding header and size fields
- Note
must check return error code
- Return Value
size
: or error code
- uint32_t
size
() const¶total size this object occupies in the image
- Return Value
size
: or error code
- class
ObjectBuffer
: public MemoryDataStream¶- #include <ObjectBuffer.h>
Class to manage writing object data into a stream.
- namespace
Gdb
¶
- class
FileSystem
: public IFS::IFileSystem¶- #include <FileSystem.h>
IFS implementation of Host filing system.
Public Functions
- int
mount
()¶Mount file system, performing any required initialisation.
- Return Value
error
: code
- int
getinfo
(Info &info)¶get filing system information
- Parameters
info
: structure to read information into- Return Value
int
: error code
- int
opendir
(const char *path, DirHandle &dir)¶open a directory for reading
- Parameters
path
: path to directory. nullptr is interpreted as root directory
dir
: returns a pointer to the directory object- Return Value
int
: error code
- int
rewinddir
(DirHandle dir)¶Reset directory read position to start.
- Parameters
dir
:- Return Value
int
: error code
- int
readdir
(DirHandle dir, Stat &stat)¶read a directory entry
- Note
File system allocates entries structure as it usually needs to track other information. It releases memory when closedir() is called.
- Parameters
dir
:
stat
:- Return Value
int
: error code
- int
closedir
(DirHandle dir)¶close a directory object
- Parameters
dir
: directory to close- Return Value
int
: error code
- int
mkdir
(const char *path)¶Create a directory.
Only the final directory in the path is guaranteed to be created. Usually, this call will fail if intermediate directories are not present. Use
makedirs()
for this purpose.
- Parameters
path
: Path to directory- Return Value
int
: error code
- int
stat
(const char *path, Stat *stat)¶get file information
- Parameters
path
: name or path of file
s
: structure to return information in, may be null to do a simple file existence check- Return Value
int
: error code
- int
fstat
(FileHandle file, Stat *stat)¶get file information
- Parameters
file
: handle to open file
stat
: structure to return information in, may be null- Return Value
int
: error code
- int
fsetxattr
(FileHandle file, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute on an open file.
- int
fgetxattr
(FileHandle file, AttributeTag tag, void *buffer, size_t size)¶Get an extended attribute from an open file.
- Parameters
file
: handle to open file
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- int
fenumxattr
(FileHandle file, AttributeEnumCallback callback, void *buffer, size_t bufsize)¶Enumerate attributes.
- Parameters
file
: handle to open file
callback
: Callback function to invoke for each attribute found
buffer
: Buffer to use for reading attribute data. Use nullptr if only tags are required
bufsize
: Size of buffer- Return Value
int
: error code, on success returns number of attributes read
- int
setxattr
(const char *path, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute for a file given its path.
- Parameters
path
: Full path to file (or directory)
tag
: The attribute to write
data
: Content of the attribute. Pass nullptr to remove the attribute (if possible).
size
: Size of the attribute in bytes- Return Value
int
: error code
- int
getxattr
(const char *path, AttributeTag tag, void *buffer, size_t size)¶Get an attribute from a file given its path.
- Parameters
file
: Full path to file (or directory)
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- FileHandle
open
(const char *path, OpenFlags flags)¶open a file by path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
FileHandle
: file handle or error code
- int
close
(FileHandle file)¶close an open file
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
read
(FileHandle file, void *data, size_t size)¶read content from a file and advance cursor
- Parameters
file
: handle to open file
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- int
write
(FileHandle file, const void *data, size_t size)¶write content to a file at current position and advance cursor
- Parameters
file
: handle to open file
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- int
lseek
(FileHandle file, int offset, SeekOrigin origin)¶change file read/write position
- Parameters
file
: handle to open file
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- int
eof
(FileHandle file)¶determine if current file position is at end of file
- Parameters
file
: handle to open file- Return Value
int
: 0 - not EOF, > 0 - at EOF, < 0 - error
- int32_t
tell
(FileHandle file)¶get current file position
- Parameters
file
: handle to open file- Return Value
int32_t
: current position relative to start of file, or error code
- int
ftruncate
(FileHandle file, size_t new_size)¶Truncate (reduce) the size of an open file.
- Note
In POSIX
ftruncate()
can also make the file bigger, however SPIFFS can only reduce the file size and will return an error if newSize > fileSize- Parameters
file
: Open file handle, must have Write access
newSize
:- Return Value
int
: Error code
- int
flush
(FileHandle file)¶flush any buffered data to physical media
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
rename
(const char *oldpath, const char *newpath)¶rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- int
remove
(const char *path)¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- int
fremove
(FileHandle file)¶remove (delete) a file by handle
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
format
()¶format the filing system
- Note
this does a default format, returning file system to a fresh state The filing system implementation may define more specialised methods which can be called directly.
- Return Value
int
: error code
- int
check
()¶Perform a file system consistency check.
- Note
if possible, issues should be resolved. Returns 0 if file system checked out OK. Otherwise there were issues: < 0 for unrecoverable errors,
- Return Value
int
: error code
- namespace
Host
¶Functions
- FileSystem &
getFileSystem
()¶Get the currently active file system, if any.
- Return Value
IFS::FileSystem*
:
- class
FileSystem
: public IFS::IFileSystem¶- #include <FileSystem.h>
IFS implementation of Host filing system.
Public Functions
- int
mount
()¶Mount file system, performing any required initialisation.
- Return Value
error
: code
- int
getinfo
(Info &info)¶get filing system information
- Parameters
info
: structure to read information into- Return Value
int
: error code
- int
opendir
(const char *path, DirHandle &dir)¶open a directory for reading
- Parameters
path
: path to directory. nullptr is interpreted as root directory
dir
: returns a pointer to the directory object- Return Value
int
: error code
- int
rewinddir
(DirHandle dir)¶Reset directory read position to start.
- Parameters
dir
:- Return Value
int
: error code
- int
readdir
(DirHandle dir, Stat &stat)¶read a directory entry
- Note
File system allocates entries structure as it usually needs to track other information. It releases memory when closedir() is called.
- Parameters
dir
:
stat
:- Return Value
int
: error code
- int
closedir
(DirHandle dir)¶close a directory object
- Parameters
dir
: directory to close- Return Value
int
: error code
- int
mkdir
(const char *path)¶Create a directory.
Only the final directory in the path is guaranteed to be created. Usually, this call will fail if intermediate directories are not present. Use
makedirs()
for this purpose.
- Parameters
path
: Path to directory- Return Value
int
: error code
- int
stat
(const char *path, Stat *stat)¶get file information
- Parameters
path
: name or path of file
s
: structure to return information in, may be null to do a simple file existence check- Return Value
int
: error code
- int
fstat
(FileHandle file, Stat *stat)¶get file information
- Parameters
file
: handle to open file
stat
: structure to return information in, may be null- Return Value
int
: error code
- int
fsetxattr
(FileHandle file, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute on an open file.
- int
fgetxattr
(FileHandle file, AttributeTag tag, void *buffer, size_t size)¶Get an extended attribute from an open file.
- Parameters
file
: handle to open file
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- int
fenumxattr
(FileHandle file, AttributeEnumCallback callback, void *buffer, size_t bufsize)¶Enumerate attributes.
- Parameters
file
: handle to open file
callback
: Callback function to invoke for each attribute found
buffer
: Buffer to use for reading attribute data. Use nullptr if only tags are required
bufsize
: Size of buffer- Return Value
int
: error code, on success returns number of attributes read
- int
setxattr
(const char *path, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute for a file given its path.
- Parameters
path
: Full path to file (or directory)
tag
: The attribute to write
data
: Content of the attribute. Pass nullptr to remove the attribute (if possible).
size
: Size of the attribute in bytes- Return Value
int
: error code
- int
getxattr
(const char *path, AttributeTag tag, void *buffer, size_t size)¶Get an attribute from a file given its path.
- Parameters
file
: Full path to file (or directory)
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- FileHandle
open
(const char *path, OpenFlags flags)¶open a file by path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
FileHandle
: file handle or error code
- int
close
(FileHandle file)¶close an open file
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
read
(FileHandle file, void *data, size_t size)¶read content from a file and advance cursor
- Parameters
file
: handle to open file
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- int
write
(FileHandle file, const void *data, size_t size)¶write content to a file at current position and advance cursor
- Parameters
file
: handle to open file
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- int
lseek
(FileHandle file, int offset, SeekOrigin origin)¶change file read/write position
- Parameters
file
: handle to open file
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- int
eof
(FileHandle file)¶determine if current file position is at end of file
- Parameters
file
: handle to open file- Return Value
int
: 0 - not EOF, > 0 - at EOF, < 0 - error
- int32_t
tell
(FileHandle file)¶get current file position
- Parameters
file
: handle to open file- Return Value
int32_t
: current position relative to start of file, or error code
- int
ftruncate
(FileHandle file, size_t new_size)¶Truncate (reduce) the size of an open file.
- Note
In POSIX
ftruncate()
can also make the file bigger, however SPIFFS can only reduce the file size and will return an error if newSize > fileSize- Parameters
file
: Open file handle, must have Write access
newSize
:- Return Value
int
: Error code
- int
flush
(FileHandle file)¶flush any buffered data to physical media
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
rename
(const char *oldpath, const char *newpath)¶rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- int
remove
(const char *path)¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- int
fremove
(FileHandle file)¶remove (delete) a file by handle
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
format
()¶format the filing system
- Note
this does a default format, returning file system to a fresh state The filing system implementation may define more specialised methods which can be called directly.
- Return Value
int
: error code
- int
check
()¶Perform a file system consistency check.
- Note
if possible, issues should be resolved. Returns 0 if file system checked out OK. Otherwise there were issues: < 0 for unrecoverable errors,
- Return Value
int
: error code
- namespace
HYFS
¶
- class
FileSystem
: public IFS::IFileSystem¶- #include <FileSystem.h>
Public Functions
- int
mount
()¶Mount file system, performing any required initialisation.
- Return Value
error
: code
- int
getinfo
(Info &info)¶get filing system information
- Parameters
info
: structure to read information into- Return Value
int
: error code
- int
setVolume
(uint8_t index, IFileSystem *fileSystem)¶Set volume for mountpoint.
- Parameters
index
: Volume index
fileSystem
: The filesystem to root at this mountpoint- Return Value
int
: error code
- int
opendir
(const char *path, DirHandle &dir)¶open a directory for reading
- Parameters
path
: path to directory. nullptr is interpreted as root directory
dir
: returns a pointer to the directory object- Return Value
int
: error code
- int
readdir
(DirHandle dir, Stat &stat)¶read a directory entry
- Note
File system allocates entries structure as it usually needs to track other information. It releases memory when closedir() is called.
- Parameters
dir
:
stat
:- Return Value
int
: error code
- int
rewinddir
(DirHandle dir)¶Reset directory read position to start.
- Parameters
dir
:- Return Value
int
: error code
- int
closedir
(DirHandle dir)¶close a directory object
- Parameters
dir
: directory to close- Return Value
int
: error code
- int
mkdir
(const char *path)¶Create a directory.
Only the final directory in the path is guaranteed to be created. Usually, this call will fail if intermediate directories are not present. Use
makedirs()
for this purpose.
- Parameters
path
: Path to directory- Return Value
int
: error code
- int
stat
(const char *path, Stat *stat)¶get file information
- Parameters
path
: name or path of file
s
: structure to return information in, may be null to do a simple file existence check- Return Value
int
: error code
- int
fstat
(FileHandle file, Stat *stat)¶get file information
- Parameters
file
: handle to open file
stat
: structure to return information in, may be null- Return Value
int
: error code
- int
fcontrol
(FileHandle file, ControlCode code, void *buffer, size_t bufSize)¶Low-level and non-standard file control operations.
To simplify usage the same buffer is used for both input and output. Only the size of the buffer is provided. If a specific FCNTL code requires more information then it will be contained within the provided data.
- Parameters
file
:
code
: FCNTL_XXX code
buffer
: Input/Output buffer
bufSize
: Size of buffer- Return Value
int
: error code or, on success, data size
- int
fsetxattr
(FileHandle file, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute on an open file.
- int
fgetxattr
(FileHandle file, AttributeTag tag, void *buffer, size_t size)¶Get an extended attribute from an open file.
- Parameters
file
: handle to open file
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- int
fenumxattr
(FileHandle file, AttributeEnumCallback callback, void *buffer, size_t bufsize)¶Enumerate attributes.
- Parameters
file
: handle to open file
callback
: Callback function to invoke for each attribute found
buffer
: Buffer to use for reading attribute data. Use nullptr if only tags are required
bufsize
: Size of buffer- Return Value
int
: error code, on success returns number of attributes read
- int
setxattr
(const char *path, AttributeTag tag, const void *data, size_t size)¶Set an extended attribute for a file given its path.
- Parameters
path
: Full path to file (or directory)
tag
: The attribute to write
data
: Content of the attribute. Pass nullptr to remove the attribute (if possible).
size
: Size of the attribute in bytes- Return Value
int
: error code
- int
getxattr
(const char *path, AttributeTag tag, void *buffer, size_t size)¶Get an attribute from a file given its path.
- Parameters
file
: Full path to file (or directory)
tag
: The attribute to read
buffer
: Buffer to receive attribute content
size
: Size of the buffer- Return Value
int
: error code, on success returns size of attribute (which may be larger than size)
- FileHandle
open
(const char *path, OpenFlags flags)¶open a file by path
- Parameters
path
: full path to file
flags
: opens for opening file- Return Value
FileHandle
: file handle or error code
- int
close
(FileHandle file)¶close an open file
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
read
(FileHandle file, void *data, size_t size)¶read content from a file and advance cursor
- Parameters
file
: handle to open file
data
: buffer to write into
size
: size of file buffer, maximum number of bytes to read- Return Value
int
: number of bytes read or error code
- int
write
(FileHandle file, const void *data, size_t size)¶write content to a file at current position and advance cursor
- Parameters
file
: handle to open file
data
: buffer to read from
size
: number of bytes to write- Return Value
int
: number of bytes written or error code
- int
lseek
(FileHandle file, int offset, SeekOrigin origin)¶change file read/write position
- Parameters
file
: handle to open file
offset
: position relative to origin
origin
: where to seek from (start/end or current position)- Return Value
int
: current position or error code
- int
eof
(FileHandle file)¶determine if current file position is at end of file
- Parameters
file
: handle to open file- Return Value
int
: 0 - not EOF, > 0 - at EOF, < 0 - error
- int32_t
tell
(FileHandle file)¶get current file position
- Parameters
file
: handle to open file- Return Value
int32_t
: current position relative to start of file, or error code
- int
ftruncate
(FileHandle file, size_t new_size)¶Truncate (reduce) the size of an open file.
- Note
In POSIX
ftruncate()
can also make the file bigger, however SPIFFS can only reduce the file size and will return an error if newSize > fileSize- Parameters
file
: Open file handle, must have Write access
newSize
:- Return Value
int
: Error code
- int
flush
(FileHandle file)¶flush any buffered data to physical media
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
rename
(const char *oldpath, const char *newpath)¶rename a file
- Parameters
oldpath
:
newpath
:- Return Value
int
: error code
- int
remove
(const char *path)¶remove (delete) a file by path
- Parameters
path
:- Return Value
int
: error code
- int
fremove
(FileHandle file)¶remove (delete) a file by handle
- Parameters
file
: handle to open file- Return Value
int
: error code
- int
format
()¶format the filing system
- Note
this does a default format, returning file system to a fresh state The filing system implementation may define more specialised methods which can be called directly.
- Return Value
int
: error code
- int
check
()¶Perform a file system consistency check.
- Note
if possible, issues should be resolved. Returns 0 if file system checked out OK. Otherwise there were issues: < 0 for unrecoverable errors,
- Return Value
int
: error codeReferences¶
Source Code (submodule, may be patched).
Used by¶
Sming (main) ,Component
Environment Variables¶
FSBUILD
Networking Support¶
Contains core networking protocol support classes.
DNS: Domain Name System¶ https://en.m.wikipedia.org/wiki/Domain_Name_System
Server API¶
- enum
dnsserver
::
DnsReplyCode
¶Values:
NoError
= 0¶
FormError
= 1¶
ServerFailure
= 2¶
NonExistentDomain
= 3¶
NotImplemented
= 4¶
Refused
= 5¶
YXDomain
= 6¶
YXRRSet
= 7¶
NXRRSet
= 8¶
- typedef DnsServer
DNSServer
¶
DNS_QR_QUERY
¶
DNS_QR_RESPONSE
¶
DNS_OPCODE_QUERY
¶FTP: File Transfer Protocol¶ https://en.m.wikipedia.org/wiki/File_Transfer_Protocol
Server API¶ HTTP: HyperText Transfer Protocol¶ https://en.m.wikipedia.org/wiki/Hypertext_Transfer_Protocol
Build Variables¶
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.
Support API¶
- namespace
ContentType
¶Obtain content type string from file name or path, with extension
- Parameters
fileName
:- Return Value
Functions
- MimeType
fromFileExtension
(const char *extension, MimeType unknown)¶Obtain MIME type value from file extension.
- Parameters
extension
: excluding ‘.’ separator (e.g. “htm”, “json”)
unknown
: Value to return if type cannot be determined- Return Value
MimeType
:
- String
fromFileExtension
(const char *extension)¶Obtain content type string from file extension.
- Parameters
extension
: excluding ‘.’ separator (e.g. “htm”, “json”)- Return Value
- String
fromFileExtension
(const String &extension)¶Obtain content type string from file extension.
- Parameters
extension
:- 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
- MimeType
fromFullFileName
(const char *fileName, MimeType unknown)¶Obtain MIME type value from file name or path, with extension.
- Parameters
fileName
:
unknown
: Value to return if type cannot be determined- Return Value
MimeType
:Client API¶
- 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
downloadString
(const Url &url, RequestCompletedDelegate requestComplete, size_t maxLength = NETWORK_SEND_BUFFER_SIZE)¶Queue request to download content as string (in memory)
- Parameters
url
: URL from which the content will be fetched
requestComplete
: Completion callback
maxLength
: maximum bytes to store in memory. If the response is bigger thanmaxLength
then the rest bytes will be discarded. Use this parameter wisely as setting the value too high may consume all available RAM resulting in device restart and Denial-Of-Service
- bool
downloadFile
(const Url &url, const String &saveFileName, RequestCompletedDelegate requestComplete = nullptr)¶Queue request to download a file.
- Parameters
url
: Source of file data
saveFileName
: Path to save file to. Optional: specify nullptr to use name from url
requestComplete
: Completion callbackPublic Static Functions
- static void
cleanup
()¶Use this method to clean all object pools.
Server API¶
- 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.
- class
HttpServer
: public TcpServer¶- #include <HttpServer.h>
Public Functions
- 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 registered
parser
:
- 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)¶Public Members
- HttpResourceTree
paths
¶Maps paths to resources which deal with incoming requests.
MQTT: MQ Telemetry Transport¶ https://en.m.wikipedia.org/wiki/MQTT
Client API¶
- using
MqttDelegate
= Delegate<int(MqttClient &client, mqtt_message_t *message)>¶
- using
MqttRequestQueue
= ObjectQueue<mqtt_message_t, MQTT_REQUEST_POOL_SIZE>¶
- using
MqttMessageDeliveredCallback
= Delegate<void(uint16_t msgId, int type)>¶
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
- void
setKeepAlive
(uint16_t seconds)¶Sets keep-alive time. That information is sent during connection to the server.
- Parameters
seconds
:
- void
setPingRepeatTime
(uint16_t 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
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.
NTP: Network Time Protocol¶ https://en.m.wikipedia.org/wiki/Network_Time_Protocol
Client API¶
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 server
reqIntervalSeconds
: Quantity of seconds between NTP requests
onTimeReceivedCb
: 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.SMTP: Simple Mail Transfer Protocol¶ https://en.m.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
Client API¶
- 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
¶
- using
SmtpClientCallback
= Delegate<int(SmtpClient &client, int code, char *status)>¶
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
(String &&body, MimeType mime = MIME_TEXT)¶Sets the body of the email using move semantics.
- Parameters
body
: Will be moved into message then invalidated
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&
:
- class
SmtpClient
: protected TcpClient¶- #include <SmtpClient.h>
Unnamed Group
- 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 otherwisePublic Functions
- 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
(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
- 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
:TCP: Transmission Control Protocol¶ https://en.m.wikipedia.org/wiki/Transmission_Control_Protocol
Connection API¶
- enum
tcp
::
TcpConnectionEvent
¶Values:
eTCE_Connected
= 0¶Occurs after connection establishment.
eTCE_Received
¶Occurs on data receive.
eTCE_Sent
¶
eTCE_Poll
¶
- using
TcpConnectionDestroyedDelegate
= Delegate<void(TcpConnection&)>¶
NETWORK_DEBUG
¶
NETWORK_SEND_BUFFER_SIZE
¶
- class
TcpConnection
: public IpConnection¶- #include <TcpConnection.h>
Subclassed by FtpDataStream, FtpServerConnection, TcpClient, TcpServer
Public Functions
- int
writeString
(const char *data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)¶Writes string data directly to the TCP buffer.
- Parameters
data
: null terminated string
apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE- Return Value
int
: negative on error, 0 when retry is needed or possitive on success
- int
writeString
(const String &data, uint8_t apiflags = TCP_WRITE_FLAG_COPY)¶Writes string data directly to the TCP buffer.
- Parameters
data
:
apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE- Return Value
int
: negative on error, 0 when retry is needed or possitive on success
- 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
: negative on error, 0 when retry is needed or possitive on success
- int
write
(IDataSourceStream *stream)¶Writes stream data directly to the TCP buffer.
- Parameters
stream
:
apiflags
: TCP_WRITE_FLAG_COPY, TCP_WRITE_FLAG_MORE- Return Value
int
: negative on error, 0 when retry is needed or possitive on success
- void
setDestroyedDelegate
(TcpConnectionDestroyedDelegate destroyedDelegate)¶Sets a callback to be called when the object instance is destroyed.
- Parameters
destroyedDelegate
:Client API¶
- 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
- 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
- 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.
- void
commit
()¶Tries to send the pending data immediately.
- Note
Call this method to decrease latency. Use it carefully.
Server API¶
TCP_SERVER_TIMEOUT
¶
- class
TcpServer
: public TcpConnection¶- #include <TcpServer.h>
Subclassed by CustomFtpServer, HttpServer, TelnetServer
Telnet¶ https://en.m.wikipedia.org/wiki/Telnet
Server API¶
TELNETSERVER_MAX_COMMANDSIZE
¶UDP: User Datagram Protocol¶ https://en.m.wikipedia.org/wiki/User_Datagram_Protocol
Connection API¶
- using
UdpConnectionDataDelegate
= Delegate<void(UdpConnection &connection, char *data, int size, IpAddress remoteIP, uint16_t remotePort)>¶
- class
UdpConnection
: public IpConnection¶- #include <UdpConnection.h>
Subclassed by DnsServer, mDNS::Server, NtpClient
Public Functions
- bool
setMulticast
(IpAddress ip)¶Sets the UDP multicast IP.
- Note
This method works only when LWIP is compiled with LWIP_MULTICAST_TX_OPTIONS
- Parameters
ip
:- Return Value
true
: when LWIP supports this operation, false otherwise
- bool
setMulticastTtl
(size_t ttl)¶Sets the UDP multicast Time-To-Live(TTL).
- Note
This method works only when LWIP is compiled with LWIP_MULTICAST_TX_OPTIONS
- Parameters
ttl
: - time to live in hops. For example if a milticast UDP packet needs to pass through two routes to reach the receiver then the TTL should be set to 2- Return Value
true
: when LWIP supports this operation, false otherwiseURL: 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
(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 &
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
- 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
:Public Members
- int
Port
= 0¶Undefined by default.
WebSocket Protocol¶ https://en.m.wikipedia.org/wiki/WebSocket
Connection API¶
- using
WebsocketList
= Vector<WebsocketConnection *>¶
- using
WebsocketDelegate
= Delegate<void(WebsocketConnection&)>¶
- using
WebsocketMessageDelegate
= Delegate<void(WebsocketConnection&, const String&)>¶
- using
WebsocketBinaryDelegate
= Delegate<void(WebsocketConnection&, uint8_t *data, size_t size)>¶
WEBSOCKET_VERSION
¶
- 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 connection
isClientConnection
: true when the passed connection is an http client conneciton
- 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 message
type
:
- 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
setPongHandler
(WebsocketDelegate handler)¶Sets the callback handler to be called when pong reply 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 connection
isClientConnection
: 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&Client API¶
- class
WebsocketClient
: protected WebsocketConnection¶- #include <WebsocketClient.h>
Websocket Client.
Public Functions
- 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.
Other networking libraries:
References¶
Esp8266 WiFi Component
Esp8266 WiFi Component
Host WiFi Component
LWIP Component
HTTP Parser Component
b64: Base64 Encoding/Decoding Routines Component
libyuarel Component
mqtt-protocol-c Component
SSL: Secure Sockets Layer Component
ws_parser Component
Used by¶
Sming (main) ,Component
Over-The-Air(OTA) Network Upgrader ,Component
Environment Variables¶ Over-The-Air(OTA) Upgrader¶
Introduction¶ This architecture-agnostic component adds support for Over-The-Air upgrades.
Usage¶
Add
COMPONENT_DEPENDS += Ota
to your application componenent.mk file.Add these lines to your application:
#include <Ota/Manager.h>After that you will have access to a global
OtaManager
instance that can be used to manage your OTA upgrade process.
You can use
OtaManager
to get information about the bootable partitions and update them. The code below will display the current bootable and running partition:void init() { // ... auto partition = OtaManager.getRunningPartition(); Serial.printf("\r\nCurrently running %s @ 0x%08x.\r\n", partition.name().c_str(), partition.address()); }If needed you can also create your own instance of the of OtaUpgrader as shown below:
// Call when IP address has been obtained void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) { // ... OtaUpgrader ota; auto part = ota.getNextBootPartition(); ota.begin(part); // ... write all the data to the partition ota.end(); // ... }See the Upgrade sample application.
API Documentation¶ Warning
doxygennamespace: Cannot find namespace “Ota” in doxygen xml output for project “api” from directory: ../api/xml/
References¶
rBoot Component
Used by¶
Over-The-Air(OTA) Network Upgrader ,Component
Over-the-Air Firmware Upgrade Library
OTA Firmware Upgrade via MQTT Library
Over-The-Air(OTA) Network Upgrader¶
Introduction¶ This architecture-agnostic component adds support for Over-The-Air upgrades.
Usage¶
Add
COMPONENT_DEPENDS += Ota
to your application componenent.mk file.Add these lines to your application:
#include <Ota/Manager.h>After that you will have access to a global
OtaManager
instance that can be used to manage your OTA upgrade process.
You can use
OtaManager
to get information about the bootable partitions and update them. The code below will display the current bootable and running partition:void init() { // ... auto partition = OtaManager.getRunningPartition(); Serial.printf("\r\nCurrently running %s @ 0x%08x.\r\n", partition.name().c_str(), partition.address()); }If needed you can also create your own instance of the of OtaUpgrader as shown below:
// Call when IP address has been obtained void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) { // ... OtaUpgrader ota; auto partition = ota.getNextBootPartition(); ota.begin(partition); // ... write all the data to the partition ota.end(); // ... }See the Upgrade sample application.
API Documentation¶ Warning
doxygennamespace: Cannot find namespace “Ota” in doxygen xml output for project “api” from directory: ../api/xml/
References¶
Networking Support Component
Over-The-Air(OTA) Upgrader Component
Used by¶
Basic Ota Sample
Storage Management¶
This Component provides support for using storage devices in a structured way by partitioning them into areas for specific uses. Partitions may can contain information such as:
Application (firmware) images
Filesystem(s)
Configuration/calibration/parameter data
Custom flash storage areas
A single partition table is located on the main flash device,
Storage::spiFlash
, and defines all partitions with a unique name and associatedStorage::Partition::Type
/Storage::Partition::SubType
.Hardware configuration¶ Each project has an associated
Hardware configuration
, specified by theHWCONFIG
setting: this is a JSON file with a.hw
extension.For user convenience, the configuration file may contain comments however these are stripped before processing.
The build system locates the file by searching, in order:
{PROJECT_DIR}
the root project directory
{SMING_HOME}/Arch/{SMING_ARCH}
{SMING_HOME}
Each architecture provides a
standard
configuration which defines such things as the partition table location and standard system partitions. Other configurations inherit from this by providing abase_config
value.You can list the available configs like this:
make hwconfig-listThis also shows the file path should you wish to view or edit it.
To select and view the resulting configuration, do this:
make hwconfig HWCONFIG=spiffsor, to show the partition map:
make map HWCONFIG=spiffsNote
You can set
HWCONFIG
in your project’scomponent.mk
file, however as with other configuration variables it will be overridden by the cached value set on the command line.For example, if you want to change from
standard
tostandard-4m
for your project, first add this line to your component.mk file:HWCONFIG := standard-4m
Then either run
make HWCONFIG=standard-4m
ormake config-clean
.Hardware configuration options¶ Commonly used settings can be stored in an option library for easier use. The library files are named
options.json
and located in the place as .hw files.For example, we can do this:
make HWCONFIG=standard HWCONFIG_OPTS=4m,spiffsThis loads the ‘standard’ profile then merges the fragments found in the option library with the given names. This is how the
standard-4m
profile is constructed.If using this approach, remember to updated your project’s
component.mk
with the desired settings, and verify the layout is correct usingmake map
.OTA updates¶ When planning OTA updates please check that the displayed partition map corresponds to your project. For example, the partition table requires a free sector so must not overlap other partitions.
Your OTA update process must include a step to write the partition table to the correct location.
It is not necessary to update the bootloader. See rBoot for further information.
Custom configurations¶ To customise the hardware configuration for a project, for example ‘my_project’:
Create a new configuration file in your project root, such as
my_project.hw
:{ "name": "My project config", "base_config": "spiffs", "options": ["vdd"] }You can use any available configuration as the base_config. Option fragments can be pulled in as shown. See Hardware configuration options.
If required, modify any inherited settings:
{ "name": "My config", "base_config": "standard", "devices": { "spiFlash": { "speed": 80, "mode": "qio", "size": "2M" } }, "partitions": { "rom0": { "address": "0x10000", "size": "0x80000" } } }This will adjust flash parameters (previously via SPI_SPEED, SPI_MODE and SPI_SIZE), and the location/size of the primary application partition.
Add any additional partitions:
{ "name": "My config", "base_config": "standard-4m", "partitions": { "rom0": { "address": "0x10000", "size": "0x80000" }, "spiffs1": { "address": "0x00280000", "size": "256K", "type": "data", "subtype": "spiffs", "filename": "$(FW_BASE)/spiffs1_rom.bin", "build": { "target": "spiffsgen", "files": "files/spiffs1" } } } }This adds a second SPIFFS partition, and instructs the build system to generate an image file for it using the files in the project’s
files/spiffs1
directory.Select the new configuration and re-build the project:
make HWCONFIG=my_projectYou should also add this to your project’s
component.mk
file:HWCONFIG := my_project
Program your device:
make flashThis will flash everything: bootloader, partition table and all defined partitions (those with a
filename
entry).Note
The build system isn’t smart enough to track dependencies for partition build targets.
To rebuild these manually type:
make partbuildThese will be removed when
make clean
is run, but you can also clean them separately thus:make part-cleanPartition maps¶ This is a concise view of your flash partitions. Display it like this:
make mapFor the Basic Storage sample application, we get this:
Basic_Storage: Invoking 'map' for Esp8266 (debug) architecture Partition map: Device Start End Size Type SubType Name Filename ---------------- ---------- ---------- ---------- -------- -------- ---------------- ------------ spiFlash 0x00000000 0x00001fff 8K Boot Sector spiFlash 0x00002000 0x00002fff 4K Partition Table spiFlash 0x00003000 0x00003fff 4K data phy phy_init $(FLASH_INIT_DATA) spiFlash 0x00004000 0x00007fff 16K data sysparam sys_param spiFlash 0x00008000 0x000fffff 992K app factory rom0 $(RBOOT_ROM_0_BIN) spiFlash 0x00100000 0x001effff 960K (unused) spiFlash 0x001f0000 0x001f3fff 16K user 0 user0 user0.bin spiFlash 0x001f4000 0x001f7fff 16K user 1 user1 spiFlash 0x001f8000 0x001fffff 32K (unused) spiFlash 0x00200000 0x0027ffff 512K data spiffs spiffs0 $(SPIFF_BIN_OUT) spiFlash 0x00280000 0x002bffff 256K data spiffs spiffs1 $(FW_BASE)/spiffs1_rom.bin spiFlash 0x002c0000 0x002fffff 256K data spiffs spiffs2 $(FW_BASE)/spiffs2_rom.bin spiFlash 0x00300000 0x003fffff 1M (unused)For comparison, here’s the output for Esp32:
Basic_Storage: Invoking 'map' for Esp32 (debug) architecture Partition map: Device Start End Size Type SubType Name Filename ---------------- ---------- ---------- ---------- -------- -------- ---------------- ------------ spiFlash 0x00000000 0x00007fff 32K Boot Sector spiFlash 0x00008000 0x00008fff 4K Partition Table spiFlash 0x00009000 0x0000efff 24K data nvs nvs spiFlash 0x0000f000 0x0000ffff 4K data phy phy_init spiFlash 0x00010000 0x001fffff 1984K app factory factory $(TARGET_BIN) spiFlash 0x001f0000 0x001f3fff 16K user 0 user0 user0.bin spiFlash 0x001f4000 0x001f7fff 16K user 1 user1 spiFlash 0x001f8000 0x001fffff 32K (unused) spiFlash 0x00200000 0x0027ffff 512K data spiffs spiffs0 $(SPIFF_BIN_OUT) spiFlash 0x00280000 0x002bffff 256K data spiffs spiffs1 $(FW_BASE)/spiffs1_rom.bin spiFlash 0x002c0000 0x002fffff 256K data spiffs spiffs2 $(FW_BASE)/spiffs2_rom.bin spiFlash 0x00300000 0x003fffff 1M (unused)To compare this with the partition map programmed into a device, do this:
make readmap mapJSON validation¶ When the binary partition table is built or updated, the configuration is first validated against a schema Sming/Components/Storage/schema.json.
This complements the checks performed by the
hwconfig
tool.You can run the validation manually like this:
make hwconfig-validateSee JSON Schema for details about JSON schemas.
Configuration¶
HWCONFIG
¶default: standard
Set this to the hardware configuration to use for your project.
Default configurations:
- standard
Base profile with 1MB flash size which should work on all device variants. Located in the
Sming/Arch/{SMING_ARCH}
directory.
- standard-4m
Overrides
standard
to set 4Mbyte flash size
- spiffs
Adds a single SPIFFS partition. See SPIFFS IFS Library.
Other configurations may be available, depending on architecture. You can see these by running
make hwconfig-list
.For example, to select
spiffs
add the following line to your project:HWCONFIG := spiffs
You will also need to run
make HWCONFIG=spiffs
to change the cached value (ormake config-clean
to reset everything).
HWCONFIG_OPTS
¶Set this to adjust the hardware profile using option fragments. See Hardware configuration options.
Binary partition table¶ Sming uses the same binary partition table structure as ESP-IDF, located immediately after the boot sector. However, it is organised slighly differently to allow partitions to be registered for multiple storage devices.
Entries are fixed 32-byte structures,
Storage::esp_partition_info_t
, organised as follows:
The first entry is always a
storage
type defining the mainspiFlash
device.This is followed by regular partition entries sorted in ascending address order. There may be gaps between the partitions.
The partition table md5sum entry is inserted as normal
If any external devices are defined: - A SMING_EXTENSION entry, which the esp32 bootloader interprets as the end of the partition table. - The next entry is a
storage
type for theexternal
device. - This is followed by regular partition entries as before. - A second md5sum entry is inserted for the entire partition table thus farThe end of the partition table is identified by an empty sector (i.e. all bytes 0xFF).
Partition API¶ This is a C++ interface. Some examples:
Storage::Partition part = Storage::findPartition("spiffs0"); // Find by name if(part) { debugf("Partition '%s' found", part.name().c_str()); } else { debugf("Partition NOT found"); } // Enumerate all partitions for(auto it = Storage::findPartition(); it; ++it) { auto part = *it; debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); } // Enumerate all SPIFFS partitions for(auto it = Storage::findPartition(Partition::SubType::Data::spiffs; it; it++) { debugf("Found '%s' at 0x%08x, size 0x%08x", it->name().c_str(), it->address(), it->size()); }A
Storage::Partition
object is just a wrapper and can be freely copied around. It defines methods which should be used to read/write/erase the partition contents.Each partition has an associated
Storage::Device
. This is usuallyStorage::spiFlash
for the main flash device.Other devices must be registed via
Storage::PartitionTable::registerStorageDevice()
.You can query partition entries from a Storage object directly, for example:
#include <Storage/SpiFlash.h> for(auto part: Storage::spiFlash->partitions()) { debugf("Found '%s' at 0x%08x, size 0x%08x", part.name().c_str(), part.address(), part.size()); }External Storage¶ If your design has additional fixed storage devices, such as SPI RAM, flash or EEPROM, you can take advantage of the partition API to manage them as follows:
Implement a class to manage the storage, inheriting from
Storage::Device
.Create a custom hardware configuration for your project and add a
devices
entry describing your storage device, plus partition entries: thedevice
field identifies which device these entries relate to.Create an instance of your custom device and make a call to
Storage::registerDevice()
in yourinit()
function (or elsewhere if more appropriate).API¶
- namespace
Storage
¶FileDevice.h
Copyright 2019 mikee47 mike@sillyhouse.net
This file is part of the IFS Library
This 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, version 3 or later.
This 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 this library. If not, see https://www.gnu.org/licenses/.
Functions
- void
initialize
()¶Called early in the startup phase.
- bool
registerDevice
(Device *device)¶Register a storage device.
- Return Value
bool
: true on success, false if another device already registered with same name
- bool
unRegisterDevice
(Device *device)¶Unregister a storage device.
Use extreme care: behaviour is unpredictable if partitions are in use
Variables
- constexpr uint16_t
ESP_PARTITION_MAGIC
= {0x50AA}¶Identifies a valid partition.
- constexpr uint16_t
ESP_PARTITION_MAGIC_MD5
= {0xEBEB}¶Identifies an MD5 hash block.
- constexpr size_t
ESP_PARTITION_TABLE_MAX_LEN
= {0xC00}¶
- class
CustomDevice
: public Storage::Device¶- #include <CustomDevice.h>
Class to support dynamic partitions.
Call
createPartition
to add partitions up to a maximum of 16 entries.Subclassed by Storage::FileDevice, Storage::ProgMem, Storage::StreamDevice, Storage::SysMem
- class
Device
: public LinkedObjectTemplate<Device>¶- #include <Device.h>
Represents a storage device (e.g. flash memory)
Subclassed by Storage::CustomDevice, Storage::SpiFlash
Public Functions
- bool
loadPartitions
(uint32_t tableOffset)¶Load partition table entries Location of partition table to read.
- Return Value
bool
: true on success, false on failure
- bool
loadPartitions
(Device &source, uint32_t tableOffset)¶Load partition table entries from another table.
- Parameters
source
: Device to load entries from Location of partition table to read- Return Value
bool
: true on success, false on failure
- virtual uint32_t
getId
() const¶Obtain device ID.
- Return Value
uint32_t
: typically flash chip ID
- virtual size_t
getBlockSize
() const = 0¶Obtain smallest allocation unit for erase operations.
- virtual size_t
getSize
() const = 0¶Obtain addressable size of this device.
- Return Value
size_t
: Must be at least as large as the value declared in the partition table
- virtual bool
read
(uint32_t address, void *dst, size_t size) = 0¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- virtual bool
write
(uint32_t address, const void *src, size_t size) = 0¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- virtual bool
erase_range
(uint32_t address, size_t size) = 0¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- struct
esp_partition_info_t
¶- #include <partition_info.h>
Internal structure describing the binary layout of a partition table entry.
- class
FileDevice
: public Storage::CustomDevice¶- #include <FileDevice.h>
Read-only partition on a stream object.
- Note
Writes not possible as streams always append data, cannot do random writes
Public Functions
- size_t
getSize
() const¶Obtain addressable size of this device.
- Return Value
size_t
: Must be at least as large as the value declared in the partition table
- size_t
getBlockSize
() const¶Obtain smallest allocation unit for erase operations.
- bool
read
(uint32_t address, void *dst, size_t size)¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(uint32_t address, const void *src, size_t size)¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(uint32_t address, size_t size)¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- class
Partition
¶- #include <Partition.h>
Represents a flash partition.
Confirm partition is of the expected type
- Parameters
type
: Expected partition type
subtype
: Expected partition sub-type- Return Value
bool
: true if type is OK, false if not. Logs debug messages on failure.Public Functions
- bool
read
(size_t offset, void *dst, size_t size)¶Read data from the partition.
- Parameters
offset
: Where to start reading, relative to start of partition
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(size_t offset, const void *src, size_t size)¶Write data to the partition.
- Note
Flash region must be erased first
- Parameters
offset
: Where to start writing, relative to start of partition
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(size_t offset, size_t size)¶Erase part of the partition.
- Note
Both offset and size must be aligned to flash sector size (4Kbytes)
- Parameters
offset
: Where to start erasing, relative to start of partition
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- uint8_t
subType
() const¶Obtain partition sub-type.
- uint32_t
lastAddress
() const¶Obtain address of last byte in this this partition.
- Parameters
uint32_t
: Device address
- uint32_t
size
() const¶Obtain partition size.
- Return Value
uint32_t
: Size in bytes
- Flags
flags
() const¶Get partition flags.
- bool
isEncrypted
() const¶Check state of partition
encrypted
flag.
- bool
isReadOnly
() const¶Check state of partition
readOnly
flag.
- bool
getDeviceAddress
(uint32_t &address, size_t size) const¶Get corresponding storage device address for a given partition offset.
- Parameters
address
: IN: Zero-based offset within partition, OUT: Device address
size
: Size of data to be accessed- Return Value
bool
: true on success, false on failure Fails if the given offset/size combination is out of range, or the partition is undefined.
- Device *
getDevice
() const¶Get storage device containing this partition.
- Return Value
Device*
: null if device isn’t registered
- bool
contains
(uint32_t addr) const¶Determine if given address contained within this partition.
- size_t
getBlockSize
() const¶Obtain smallest allocation unit for erase operations.
Public Static Functions
- struct
SubType
¶- #include <Partition.h>
- class
PartitionStream
: public ReadWriteStream¶- #include <PartitionStream.h>
Stream operating directory on a Storage partition.
To support write operations, the target region must be erased first.
Public Functions
- int
available
()¶Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
- uint16_t
readMemoryBlock
(char *data, int bufSize)¶Read a block of memory.
- Parameters
data
: Pointer to the data to be read
bufSize
: Quantity of chars to read- Return Value
uint16_t
: Quantity of chars read
- int
seekFrom
(int offset, SeekOrigin 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
:- Return Value
New
: position, < 0 on error
- size_t
write
(const uint8_t *buffer, size_t size)¶Write chars to stream.
- Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters
buffer
: Pointer to buffer to write to the stream
size
: Quantity of chars to write- Return Value
size_t
: Quantity of chars written to stream
- bool
isFinished
()¶Check if all data has been read.
- Return Value
bool
: True on success.
- class
PartitionTable
¶- #include <PartitionTable.h>
Partition search
Find partitions based on one or more parameters
Public Functions
- Partition
find
(const String &name) const¶Find partition by name.
- Parameters
Name
: Name to search for, case-sensitive- Return Value
Partition
: Names are unique so at most only one match
- class
ProgMem
: public Storage::CustomDevice¶- #include <ProgMem.h>
Storage device to access PROGMEM using flash API.
Public Functions
- size_t
getBlockSize
() const¶Obtain smallest allocation unit for erase operations.
- size_t
getSize
() const¶Obtain addressable size of this device.
- Return Value
size_t
: Must be at least as large as the value declared in the partition table
- bool
read
(uint32_t address, void *dst, size_t size)¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(uint32_t address, const void *src, size_t size)¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(uint32_t address, size_t size)¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- class
SpiFlash
: public Storage::Device¶- #include <SpiFlash.h>
Main flash storage device.
Public Functions
- size_t
getBlockSize
() const¶Obtain smallest allocation unit for erase operations.
- size_t
getSize
() const¶Obtain addressable size of this device.
- Return Value
size_t
: Must be at least as large as the value declared in the partition table
- uint32_t
getId
() const¶Obtain device ID.
- Return Value
uint32_t
: typically flash chip ID
- bool
read
(uint32_t address, void *dst, size_t size)¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(uint32_t address, const void *src, size_t size)¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(uint32_t address, size_t size)¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- class
StreamDevice
: public Storage::CustomDevice¶- #include <StreamDevice.h>
Read-only partition on a stream object.
- Note
Writes not possible as streams always append data, cannot do random writes
Public Functions
- bool
read
(uint32_t address, void *dst, size_t size)¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(uint32_t address, const void *src, size_t size)¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(uint32_t address, size_t size)¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on error
- class
SysMem
: public Storage::CustomDevice¶- #include <SysMem.h>
Storage device to access system memory, e.g. RAM.
Public Functions
- size_t
getBlockSize
() const¶Obtain smallest allocation unit for erase operations.
- size_t
getSize
() const¶Obtain addressable size of this device.
- Return Value
size_t
: Must be at least as large as the value declared in the partition table
- bool
read
(uint32_t address, void *dst, size_t size)¶Read data from the storage device.
- Parameters
address
: Where to start reading
dst
: Buffer to store data
size
: Size of data to be read, in bytes.- Return Value
bool
: true on success, false on error
- bool
write
(uint32_t address, const void *src, size_t size)¶Write data to the storage device.
- Parameters
address
: Where to start writing
src
: Data to write
size
: Size of data to be written, in bytes.- Return Value
bool
: true on success, false on error
- bool
erase_range
(uint32_t address, size_t size)¶Erase a region of storage in preparation for writing.
- Parameters
address
: Where to start erasing
size
: Size of region to erase, in bytes- Return Value
bool
: true on success, false on errorReferences¶ Used by¶
Sming (main) ,Component
Environment Variables¶ Arch Driver¶
This is an internal Component to pull together common headers and code used at a low-level by more than once Arch.
This is to:
Ease maintenance
Avoid code duplication
Provide a consistent API for the framework to use
References¶ Used by¶
Esp32 Drivers ,Component
Esp8266 Drivers ,Component
Host Drivers ,Component
AXTLS 8266¶
SSL support using the AXTLS library
References¶
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
- alt
Build status
To build, add xtensa toolchain to your path, and run
make
. The library will be built inbin/
directory.Credits and license¶ axTLS is written and maintained by Cameron Rich.
Other people have contributed to this port; see git logs for a full list.
See LICENSE file for axTLS license.
Bear SSL¶
SSL support using Bear SSL for ESP8266.
References¶ Submodule: bearssl¶ 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
Blake2s
= HashContext<Blake2sEngine<hashsize>>¶
- using
HmacBlake2s
= HmacContext<Blake2s<hashsize>>¶
- using
HmacBlake2s256
= HmacBlake2s<32>¶
- using
HmacBlake2s128
= HmacBlake2s<16>¶
- using
ByteArray
= 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
Md5
= HashContext<Md5Engine>¶
- using
HmacMd5
= HmacContext<Md5>¶
- using
Sha1
= HashContext<Sha1Engine>¶
- using
HmacSha1
= HmacContext<Sha1>¶
- using
Sha224
= HashContext<Sha224Engine>¶
- using
Sha256
= HashContext<Sha256Engine>¶
- using
Sha384
= HashContext<Sha384Engine>¶
- using
Sha512
= HashContext<Sha512Engine>¶
- using
HmacSha224
= HmacContext<Sha224>¶
- using
HmacSha256
= HmacContext<Sha256>¶
- using
HmacSha384
= HmacContext<Sha384>¶
- using
HmacSha512
= HmacContext<Sha512>¶Functions
- 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
- template<class
HashContext
>
classHmacContext
¶- #include <HmacContext.h>
HMAC class template.
Implements the HMAC algorithm using any defined hash context
References¶ Used by¶
AXTLS 8266 ,Component
SSL: Secure Sockets Layer ,Component
libsodium Library
Esptool¶
This Component provides Espressif’s tool for reading and writing firmware and other data to hardware.
Options¶
SPI_SPEED
¶[read-only] Set by Hardware configuration.
Clock speed for flash memory (20, 26, 40 or 80). Default is 40.
SPI_MODE
¶[read-only] Set by Hardware configuration.
Flash memory operating mode (quot, dio, dout, qio). Default is qio.
SPI_SIZE
¶[read-only] Set by Hardware configuration.
Size of flash memory chip (256KB, 512KB, 1MB, 2MB, 4MB). Default is 512K bytes.
The default hardware profile
standard
sets this to 1MB. You can setHWCONFIG=standard-4m
to increase it or create a custom Hardware configuration for your project.
ESPTOOL
¶Full path of esptool.py
References¶ Used by¶
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Environment Variables¶ Submodule: esptool¶ esptool.py¶ 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.
![]()
Installation / dependencies¶ Easy Installation¶ 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 esptoolWith some Python installations this may not work and you’ll receive an error, try
python -m pip install esptool
orpip2 install esptool
, or consult your Python installation manual for information about how to access pip.After installing, you will have
esptool.py
installed into the default Python executables directory and you should be able to run it with the commandesptool.py
.Development Mode Installation¶ Development mode allows you to run the latest development version from this repository.
$ git clone https://github.com/espressif/esptool.git $ cd esptool $ pip install --user -e .This will install esptool’s dependencies and create some executable script wrappers in the user’s
bin
directory. The wrappers will run the the scripts found in the git working directory directly, so any time the working directory contents change it will pick up the new versions.It’s also possible to run the scripts directly from the working directory with this Development Mode installation.
(Note: if you actually plan to do development work with esptool itself, see the CONTRIBUTING.md file.)
Usage¶ 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. ieesptool.py write_flash -h
.Common Options¶ Serial Port¶
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 likesudo usermod -a -G dialout <USERNAME>
. Check your Linux distribution’s documentation for more information.Baud rate¶ 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 theESPTOOL_BAUD
environment variable. This can speed upwrite_flash
andread_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.
Commands¶ Write binary data to flash: write_flash¶ 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.binMultiple 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.binThe
--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.
Setting flash mode and size¶ 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.binSince 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.Compression¶ By default, the serial transfer data is compressed for better performance. The
-u/--no-compress
option disables this behaviour.Read Flash Contents: read_flash¶ 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.)Erase Flash: erase_flash & erase region¶ To erase the entire flash chip (all data replaced with 0xFF bytes):
esptool.py erase_flashTo erase a region of the flash, starting at address 0x20000 with length 0x4000 bytes (16KB):
esptool.py erase_region 0x20000 0x4000The address and length must both be multiples of the SPI flash erase sector size. This is 0x1000 (4096) bytes for supported flash chips.
Read built-in MAC address: read_mac¶ esptool.py read_macRead SPI flash id: flash_id¶ esptool.py flash_idExample output:
Manufacturer: e0 Device: 4016 Detected flash size: 4MBRefer to flashrom source code for flash chip manufacturer name and part number.
Convert ELF to Binary: elf2image¶ 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.elfThis 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 thewrite_flash
command, see the write_flash command for details.elf2image for ESP8266¶ The default command output is two binary files:
my_app.elf-0x00000.bin
andmy_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.elfelf2image for ESP32¶ 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.elfIn the above example, the output image file would be called
my_esp32_app.bin
.Output .bin image details: image_info¶ The
image_info
command outputs some information (load addresses, sizes, etc) about a.bin
file created byelf2image
.esptool.py --chip esp32 image_info my_esp32_app.binNote 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.Advanced Commands¶ The following commands are less commonly used, or only of interest to advanced users. They are documented on the wiki:
Additional ESP32 Tools¶ The following tools for ESP32, bundled with esptool.py, are documented on the wiki:
Serial Connections¶ 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!
Entering the Bootloader¶ 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:
Boot Mode¶ 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:
Flash Modes¶
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 afterwrite_flash
on the command line, for example:esptool.py --port /dev/ttyUSB1 write_flash --flash_mode dio --flash_size 4MB 0x0 bootloader.binThese 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.
Flash Mode (–flash_mode, -fm)¶ These set Quad Flash I/O or Dual Flash I/O modes. Valid values are
keep
,qio
,qout
,dio
,dout
. The default iskeep
, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variableESPTOOL_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 todio
then these pins are available for other purposes.For a full explanation of these modes, see the SPI Flash Modes wiki page.
Flash Frequency (–flash_freq, -ff)¶ Clock frequency for SPI flash interactions. Valid values are
keep
,40m
,26m
,20m
,80m
(MHz). The default iskeep
, which keeps whatever value is already in the image file. This parameter can also be specified using the environment variableESPTOOL_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.
Flash Size (–flash_size, -fs)¶ 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 isdetect
, which tries to autodetect size based on SPI flash ID. If detection fails, a warning is printed and a default value of of4MB
(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 variableESPTOOL_FS
.ESP8266 and Flash Size¶ 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
.ESP32 and Flash Size¶ 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.
Advanced Options¶ See the Advanced Options wiki page for some of the more unusual esptool.py command line options.
Remote Serial Ports¶ 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.
Troubleshooting¶ Flashing problems can be fiddly to troubleshoot. Try the suggestions here if you’re having problems:
Bootloader won’t respond¶ 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.)write_flash operation fails part way through¶ 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.)
write_flash succeeds but program doesn’t run¶ If esptool.py can flash your module with
write_flash
but your program doesn’t run, try the following:Wrong Flash Mode¶ Some devices only support the
dio
flash mode. Writing to flash withqio
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.
Insufficient Power¶ 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.
Insufficient Capacitance¶ 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.
Power Supply Rating¶ 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.
Missing bootloader¶ 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.
SPI Pins which must be disconnected¶ 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.
Early stage crash¶ 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.
Serial Terminal Programs¶ 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.Tracing esptool.py interactions¶ 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.Using esptool.py from Python¶ 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)Internal Technical Documentation¶ 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:
About¶ 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.
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 Node library in Javascript
References¶
Source Code (submodule, may be patched).
Used by¶
Networking Support ,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:
- base64, another implementation of a commandline en/decoder:
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¶
Networking Support ,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 installTry it¶ Compile the example in
examples/
:$ make examplesRun the example program:
$ ./simpleThe 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¶
Networking Support ,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, orby 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
Basic Alexa Sample
RingTone Player Sample
SmingTest Library
Basic SSL 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.License¶ BSD-3 Clause license. You can read the full license from here.
Copyright¶
2018 - present Slavey Karadzhov slav@attachix.com
2014 - Deoxxa Development
References¶
Source Code (submodule, may be patched).
Used by¶
Networking Support ,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.
Note
With Sming 4.3 partitions are used to manage flash storage. A “slot” refers to a specific application partition, typically
rom0
,rom1
orrom2
.The location or size of these partitions is determined by the Hardware configuration.
The bootloader has been modified to use the partition table as reference, identifying slots by the partition sub-type.
Where systems are to be updated Over the Air (OTA) at least two application partitions are required. The bootloader identifies these by their partition subtype:
slot #0
->App/Ota_0
,slot #1
->App/Ota_1
, etc.Fixed applications without OTA capability use a single application image. This must be the
App/Factory
partition type, and corresponds toslot #0
.At startup, the bootloader will use the partition table to locate the application image. It will also ensure that the ROM slot information in the boot configuration is consistent, and update it if necessary.
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 (
rom0
, the primary application partition) which is always used.Slot 1¶
RBOOT_ROM1_ADDR
¶[read-only] default: disabled
The start address of slot 1.
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.
Note
The
spiffs-two-roms
configuration can be used for this purpose.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 for
rom1
with the same offset within its 1MB block asrom0
.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
¶[read-only]
Address for slot 2. You must create a custom Hardware configuration for your project with a definition for
rom2
.{ ... "partitions": { "rom2": { "address": "0x100000", "size": "512K", "type": "app", "subtype": "ota_1" } } }Note
At present, 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. Create a new Hardware configuration and configure the
rom0
start address and size to the same as therom2
partition of the main project.option (a)
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.option (b)
Run a normal
make
for your recovery projectLocate the firmware image file, typically
out/Esp8266/release/firmware/rom0.bin
(adjust accordingly if using a debug build). Copy this image file asrom2.bin
into your main project directory.Add an additional property to the
rom2
partition entry in your main project:"filename": "rom2.bin"When you run
make flash
in this will get written along with the other partitions.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. You should use the
two-rom-mode
Hardware configuration for this. The Sming build system will handle everything else, 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, const 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 status
data
: Pointer to a block of uint8_t data elements to be written to flash
len
: 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.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/
References¶ Used by¶
Sming (Esp8266) ,Component
Sming (Host) ,Component
Over-The-Air(OTA) Upgrader ,Component
Environment Variables¶
RBOOT_DIR
RBOOT_ROM_0_BIN
RBOOT_ROM_1_BIN
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.SSL: 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; // Go with maximum buffer sizes session.maxBufferSize = Ssl::MaxBufferSize::K16; }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.
Alternatively, 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
- 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 socket
tcp
: 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 data
output
: 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
Array
= FSTR::Array<Ssl::CipherSuite>¶Certificates¶
- class
Certificate
¶Implemented by SSL adapter to handle certificate operations.
- 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.
- 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
- struct
Sha256
¶- #include <Fingerprints.h>
Fingerprint based on the SHA256 value of the certificate.
Typically displayed in browser certificate information
- 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.
SSL Adapter API¶ These classes provide the interface between a
Ssl::Session
and an appropriate adapter.Error codes¶ Error codes are implementation specific, however 0 always indicates success and < 0 for error.
To obtain a description for an error code, use
Ssl::Connection::getErrorString()
.SSL Alerts are reported via error codes. To obtain the alert code call
Ssl::Connection::getAlert()
which returns anSsl::Alert
code. If the error code is not an alert thenAlert::INVALID
is returned.Classes¶
- class
Factory
¶Implemented by SSL adapter.
- class
Context
¶Implemented by SSL adapter to create and manage SSL connections.
Public Functions
- 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 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 data
output
: 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
- size_t
printTo
(Print &p) const¶For debugging.
References¶
AXTLS 8266 Component
Cryptographic Support Component
Used by¶
Networking Support ,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
Environment Variables¶ 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¶
Networking Support ,Component
References¶
Sming (Esp32) Component
Sming (Esp8266) Component
Sming (Host) Component
FlashString Component
Installable File System Component
Networking Support Component
Storage Management Component
Terminal Component
SPIFFS IFS Library 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.1 installed. The Sming installers can do this for you - see Getting Started.
You can find further details in the ESP-IDF documentation.
Building¶
Make sure that the IDF_PATH
is set.
Also make sure that the other ESP-IDF environmental variables are set.
In Linux this can be done using the following command:
source $SMING_HOME/Tools/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
See Esp32 Core Component for further details.
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.
Esp32 Drivers Component
Esp32 Core Component Component
FAT Filing System Component
GDB Stub for Esp32 Component
Heap Component
Esp32 LIBC Component Component
Esp8266 SPI Flash Support Component
Esptool Component
Sming (main) ,Component
TARGET_BIN
Esp32 Drivers¶
Provides low-level peripheral drivers.
SDK definitions for GPIO.
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_1
-
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.
-
NOW
()¶
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.
Warning
doxygengroup: Cannot find namespace “i2s_driver” in doxygen xml output for project “api” from directory: ../api/xml/
-
typedef ETSTimerFunc
os_timer_func_t
¶
-
typedef ETSTimer
os_timer_t
¶
-
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
-
os_timer_arm
(ptimer, ms, repeat_flag)¶
-
os_timer_arm_us
(ptimer, us, repeat_flag)¶
-
os_timer_disarm
(ptimer)¶
-
os_timer_setfn
(ptimer, pfunction, parg)¶
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.
Custom asynchronous driver.
Warning
doxygengroup: Cannot find namespace “uart_driver” in doxygen xml output for project “api” from directory: ../api/xml/
Esp32 Core Component Component
Arch Driver 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, including the ESP-IDF SDK.
If you want to tune ESP-IDF to your needs you should run:
make SMING_ARCH=Esp32 sdk-menuconfig
Followed by:
make
These are read-only debug variables:
-
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
Option variables:
-
ESP_VARIANT
¶ Build for for esp32 or esp32s2 device
The following variables may need to be changed if tools are installed in a different location, or if multiple versions are installed. By default, the most current version will be used.
-
ESP32_COMPILER_PATH
¶ Location of xtensa compiler toolchain
-
ESP32_ULP_PATH
¶ Location of ULP compiler toolchain
-
ESP32_OPENOCD_PATH
¶ Location of ESP32 version of Open OCD JTAG debugging tools.
-
ESP32_PYTHON_PATH
¶ Location of ESP-IDF python.
Esp32 LIBC Component Component
Esp32 Drivers ,Component
Esp8266 WiFi ,Component
Sming (Esp32) ,Component
Esp8266 SPI Flash Support ,Component
SDK_FULL_BUILD
Esp8266 WiFi¶
All related libraries for WiFi support. Definitions are provided in the Espressif Non-OS SDK.
Esp32 Core Component Component
Sming (Esp8266) ,Component
Host Library ,Component
Networking Support ,Component
FAT Filing System¶
Required by the SDCard library.
http://elm-chan.org/fsw/ff/00index_e.html
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
GDB Stub for Esp32¶
This defines the command line to use when make gdb
is run.
Esp32 debugging is handled via JTAG interface.
No additional code is required as serial debugging is not (currently) implemented.
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Sming (Host) ,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.
Esp32 Core Component ,Component
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Sming (Host) ,Component
Esp8266 SPI Flash Support¶
Provides functions for access to flash memory.
-
enum
spi_flash
::
SPIFlashMode
¶ Values:
-
MODE_QIO
= 0¶
-
MODE_QOUT
= 1¶
-
MODE_DIO
= 2¶
-
MODE_DOUT
= 15¶
-
MODE_SLOW_READ
= 0xFE¶ Not supported.
-
MODE_FAST_READ
= 0xFF¶ Not supported.
-
MODE_QIO
= ESP_IMAGE_SPI_MODE_QIO
-
MODE_QOUT
= ESP_IMAGE_SPI_MODE_QOUT
-
MODE_DIO
= ESP_IMAGE_SPI_MODE_DIO
-
MODE_DOUT
= ESP_IMAGE_SPI_MODE_DOUT
-
MODE_FAST_READ
= ESP_IMAGE_SPI_MODE_FAST_READ
-
MODE_SLOW_READ
= ESP_IMAGE_SPI_MODE_SLOW_READ
-
-
enum
spi_flash
::
SPIFlashSpeed
¶ Values:
-
SPEED_40MHZ
= 0¶
-
SPEED_26MHZ
= 1¶
-
SPEED_20MHZ
= 2¶
-
SPEED_80MHZ
= 15¶
-
SPEED_40MHZ
= ESP_IMAGE_SPI_SPEED_40M
-
SPEED_26MHZ
= ESP_IMAGE_SPI_SPEED_26M
-
SPEED_20MHZ
= ESP_IMAGE_SPI_SPEED_20M
-
SPEED_80MHZ
= ESP_IMAGE_SPI_SPEED_80M
-
-
enum
spi_flash
::
SPIFlashSize
¶ Values:
-
SIZE_4MBIT
= 0¶
-
SIZE_2MBIT
= 1¶
-
SIZE_8MBIT
= 2¶
-
SIZE_16MBIT
= 3¶
-
SIZE_32MBIT
= 4¶
-
SIZE_1MBIT
= 0xFF¶ Not supported.
-
SIZE_1MBIT
= ESP_IMAGE_FLASH_SIZE_1MB
-
SIZE_2MBIT
= ESP_IMAGE_FLASH_SIZE_2MB
-
SIZE_4MBIT
= ESP_IMAGE_FLASH_SIZE_4MB
-
SIZE_8MBIT
= ESP_IMAGE_FLASH_SIZE_8MB
-
SIZE_16MBIT
= ESP_IMAGE_FLASH_SIZE_16MB
-
SIZE_32MBIT
= 0xFF Not listed.
-
-
enum
spi_flash
::
SPIFlashMode
Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
MODE_SLOW_READ
= 0xFE Not supported.
-
MODE_FAST_READ
= 0xFF Not supported.
-
MODE_QIO
= ESP_IMAGE_SPI_MODE_QIO
-
MODE_QOUT
= ESP_IMAGE_SPI_MODE_QOUT
-
MODE_DIO
= ESP_IMAGE_SPI_MODE_DIO
-
MODE_DOUT
= ESP_IMAGE_SPI_MODE_DOUT
-
MODE_FAST_READ
= ESP_IMAGE_SPI_MODE_FAST_READ
-
MODE_SLOW_READ
= ESP_IMAGE_SPI_MODE_SLOW_READ
-
-
enum
spi_flash
::
SPIFlashSpeed
Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
SPEED_40MHZ
= ESP_IMAGE_SPI_SPEED_40M
-
SPEED_26MHZ
= ESP_IMAGE_SPI_SPEED_26M
-
SPEED_20MHZ
= ESP_IMAGE_SPI_SPEED_20M
-
SPEED_80MHZ
= ESP_IMAGE_SPI_SPEED_80M
-
-
enum
spi_flash
::
SPIFlashSize
Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
SIZE_1MBIT
= 0xFF Not supported.
-
SIZE_1MBIT
= ESP_IMAGE_FLASH_SIZE_1MB
-
SIZE_2MBIT
= ESP_IMAGE_FLASH_SIZE_2MB
-
SIZE_4MBIT
= ESP_IMAGE_FLASH_SIZE_4MB
-
SIZE_8MBIT
= ESP_IMAGE_FLASH_SIZE_8MB
-
SIZE_16MBIT
= ESP_IMAGE_FLASH_SIZE_16MB
-
SIZE_32MBIT
= 0xFF Not listed.
-
-
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
-
struct
STORE_TYPEDEF_ATTR
¶ - #include <esp_spi_flash.h>
SPI Flash memory information block. Stored at the beginning of flash memory.
-
struct
SPIFlashInfo
¶ - #include <esp_spi_flash.h>
SPI Flash memory information block. Copied from bootloader header. See
esp_image_header_t
.
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.
See also ESP Quick Toolchain.
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.
Note
This is an EXPERIMENTAL feature. Not all hardware functions may be available.
If a project does not require WiFi (or networking) then setting the DISABLE_WIFI
variable
will reduce code size and RAM usage significantly.
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.
Esp8266 Drivers Component
Esp8266 Core Component Component
Esp8266 WiFi Component
FAT Filing System Component
Esp8266 GDBSTUB for Sming Component
Heap Component
Esp8266 LIBC Component Component
Esp8266 SPI Flash Support Component
Esptool Component
rBoot Component
Sming (main) ,Component
Esp8266 Drivers¶
Provides low-level peripheral drivers.
SDK definitions for GPIO.
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_1
-
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.
-
NOW
()¶
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.
Warning
doxygengroup: Cannot find namespace “i2s_driver” in doxygen xml output for project “api” from directory: ../api/xml/
-
typedef ETSTimerFunc
os_timer_func_t
-
typedef ETSTimer
os_timer_t
-
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
-
os_timer_arm
(ptimer, ms, repeat_flag)¶
-
os_timer_arm_us
(ptimer, us, repeat_flag)¶
-
os_timer_disarm
(ptimer)¶
-
os_timer_setfn
(ptimer, pfunction, parg)¶
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.
Custom asynchronous driver.
Warning
doxygengroup: Cannot find namespace “uart_driver” in doxygen xml output for project “api” from directory: ../api/xml/
Esp8266 Core Component Component
Arch Driver 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
.
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
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
Esp8266 GDBSTUB for Sming ,Component
Esp8266 LWIP Version 2 ,Component
Sming (Esp8266) ,Component
Esp8266 SPI Flash Support ,Component
FLASH_INIT_DATA
FLASH_INIT_DATA_VCC
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
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.
Esp8266 Core Component Component
Sming (Esp8266) ,Component
Host Library ,Component
Networking Support ,Component
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.
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 enabledRun 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
- 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.
Esp8266 Core Component Component
Sming (Esp32) ,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 looksfor 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 looksfor 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.
Esp32 Core Component ,Component
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.
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.
-
enum
spi_flash
::
SPIFlashMode
Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
MODE_SLOW_READ
= 0xFE Not supported.
-
MODE_FAST_READ
= 0xFF Not supported.
-
MODE_QIO
= ESP_IMAGE_SPI_MODE_QIO
-
MODE_QOUT
= ESP_IMAGE_SPI_MODE_QOUT
-
MODE_DIO
= ESP_IMAGE_SPI_MODE_DIO
-
MODE_DOUT
= ESP_IMAGE_SPI_MODE_DOUT
-
MODE_FAST_READ
= ESP_IMAGE_SPI_MODE_FAST_READ
-
MODE_SLOW_READ
= ESP_IMAGE_SPI_MODE_SLOW_READ
-
-
enum
spi_flash
::
SPIFlashSpeed
Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
SPEED_40MHZ
= ESP_IMAGE_SPI_SPEED_40M
-
SPEED_26MHZ
= ESP_IMAGE_SPI_SPEED_26M
-
SPEED_20MHZ
= ESP_IMAGE_SPI_SPEED_20M
-
SPEED_80MHZ
= ESP_IMAGE_SPI_SPEED_80M
-
-
enum
spi_flash
::
SPIFlashSize
Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
SIZE_1MBIT
= 0xFF Not supported.
-
SIZE_1MBIT
= ESP_IMAGE_FLASH_SIZE_1MB
-
SIZE_2MBIT
= ESP_IMAGE_FLASH_SIZE_2MB
-
SIZE_4MBIT
= ESP_IMAGE_FLASH_SIZE_4MB
-
SIZE_8MBIT
= ESP_IMAGE_FLASH_SIZE_8MB
-
SIZE_16MBIT
= ESP_IMAGE_FLASH_SIZE_16MB
-
SIZE_32MBIT
= 0xFF Not listed.
-
-
enum
spi_flash
::
SPIFlashMode
Values:
-
MODE_QIO
= 0
-
MODE_QOUT
= 1
-
MODE_DIO
= 2
-
MODE_DOUT
= 15
-
MODE_SLOW_READ
= 0xFE Not supported.
-
MODE_FAST_READ
= 0xFF Not supported.
-
MODE_QIO
= ESP_IMAGE_SPI_MODE_QIO
-
MODE_QOUT
= ESP_IMAGE_SPI_MODE_QOUT
-
MODE_DIO
= ESP_IMAGE_SPI_MODE_DIO
-
MODE_DOUT
= ESP_IMAGE_SPI_MODE_DOUT
-
MODE_FAST_READ
= ESP_IMAGE_SPI_MODE_FAST_READ
-
MODE_SLOW_READ
= ESP_IMAGE_SPI_MODE_SLOW_READ
-
-
enum
spi_flash
::
SPIFlashSpeed
Values:
-
SPEED_40MHZ
= 0
-
SPEED_26MHZ
= 1
-
SPEED_20MHZ
= 2
-
SPEED_80MHZ
= 15
-
SPEED_40MHZ
= ESP_IMAGE_SPI_SPEED_40M
-
SPEED_26MHZ
= ESP_IMAGE_SPI_SPEED_26M
-
SPEED_20MHZ
= ESP_IMAGE_SPI_SPEED_20M
-
SPEED_80MHZ
= ESP_IMAGE_SPI_SPEED_80M
-
-
enum
spi_flash
::
SPIFlashSize
Values:
-
SIZE_4MBIT
= 0
-
SIZE_2MBIT
= 1
-
SIZE_8MBIT
= 2
-
SIZE_16MBIT
= 3
-
SIZE_32MBIT
= 4
-
SIZE_1MBIT
= 0xFF Not supported.
-
SIZE_1MBIT
= ESP_IMAGE_FLASH_SIZE_1MB
-
SIZE_2MBIT
= ESP_IMAGE_FLASH_SIZE_2MB
-
SIZE_4MBIT
= ESP_IMAGE_FLASH_SIZE_4MB
-
SIZE_8MBIT
= ESP_IMAGE_FLASH_SIZE_8MB
-
SIZE_16MBIT
= ESP_IMAGE_FLASH_SIZE_16MB
-
SIZE_32MBIT
= 0xFF Not listed.
-
-
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
-
struct
STORE_TYPEDEF_ATTR
- #include <esp_spi_flash.h>
SPI Flash memory information block. Stored at the beginning of flash memory.
-
struct
SPIFlashInfo
- #include <esp_spi_flash.h>
SPI Flash memory information block. Copied from bootloader header. See
esp_image_header_t
.
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 codePlace 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
-
IRAM_PRECACHE_START
(tag)
-
IRAM_PRECACHE_END
(tag)
Esp8266 Core Component Component
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Host Library ,Component
Sming (Host) ,Component
Sming Host Emulator¶
Summary¶
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.
Requirements¶
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 Windows Installation for further details.
Building¶
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
.
Components¶
Sming (Host)¶
This Component builds a library containing architecture-specific code, and defines dependencies for Sming to build for the Host Emulator.
Host Drivers Component
Host ESP HAL Component
GDB Stub for Host Component
Heap Component
Host Library Component
libc Component
SPI Flash Component
Virtual Flasher Component
rBoot Component
Sming (main) ,Component
References¶
Used by¶
Host Drivers ,Component
Submodule: seriallib¶
Serialib is a simple C++ library for serial communication. The library has been designed to work under Linux and Windows.
More details on Lulu’s blog
Host Drivers¶
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
-
virtual uint16_t
analogRead
(uint16_t pin)¶ Sample analogue input.
- Parameters
pin
: GPIO to read
- Return Value
uint16_t
: Sample value
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 socket, allowing terminal emulation using telnet, or directly to local host serial device (e.g. /dev/ttyUSB0, COM4, etc.)
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
.
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
.
Override HOST_UART_OPTIONS
adding the –device option. For example:
make run HOST_UART_OPTIONS="--uart=0 --device=/dev/ttyUSB0"
The --device
option must follow the --uart
option. Another example:
make run HOST_UART_OPTIONS="--uart=0 --device=/dev/ttyUSB0 --uart=1 --device=/dev/ttyUSB1"
The port is opened when uart_init()
gets called.
The default baud rate is whatever the application has requested. This can be overridden as follows:
make run HOST_UART_OPTIONS="--uart=0 --device=/dev/ttyUSB0 --baud=921600"
For Windows, substitute the appropriate device name, e.g. COM4
instead of /dev/ttyUSB0
.
Note
If necessary, add ENABLE_HOST_UARTID=
to prevent telnet windows from being created.
References Component
Arch Driver Component
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Host Library ,Component
Sming (Host) ,Component
Host ESP HAL¶
Provides implementations for various low-level functions similar to the Esp8266.
Task queues
Timer queues
System functions
Host Library Component
Sming (Host) ,Component
Host WiFi¶
Provides WiFi / network functions. The actual implementations are provided in LWIP
LWIP Component
Sming (Esp8266) ,Component
Host Library ,Component
Networking Support ,Component
HOST_NETWORK_OPTIONS
fatfs¶
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
GDB Stub for Host¶
This defines the command line to use when make gdb
is run. No additional code is required to debug for the Host.
If you want to debug your application while having a separate UART then make sure to send the following commands to your debugger:
handle SIGUSR1 nostop noprint
This component provides also gdbinit
file containing the optimal settings needed for debugging.
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Sming (Host) ,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.
malloc_count Component
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Sming (Host) ,Component
Host Library¶
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. Applications may pass parameters and access them using
the CommandLine
.
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.
-
HOST_PARAMETERS
¶ Set this value to pass additional parameters to a Host application. For example:
make run HOST_PARAMETERS='param1=12 param2="parameter with spaces"' make run HOST_PARAMETERS="param1=12 param2=\"parameter with spaces\""
See Basic Utility for a worked example.
-
class
CommandLine
¶ Provides access to the command line
Anything which doesn’t start with
-
is interpreted as an application parameter. For example:app param1=value
Parameters which start with
-
are handled by the Host Emulator. Anything after--
is passed directly to the application:app -- --debug --verbose
Public Functions
-
const Parameters &
getParameters
()¶ Fetch a reference to the list of command-line parameters.
-
const Parameters &
Host Drivers Component
Host WiFi Component
LWIP Component
SPI Flash Component
Host ESP HAL ,Component
Sming (Host) ,Component
libc¶
Contains implementations of any non-standard C library functions.
Esp32 Core Component ,Component
Sming (Esp32) ,Component
Sming (Esp8266) ,Component
Sming (Host) ,Component
LWIP¶
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
Networking Support ,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
SPI Flash¶
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
Virtual Flasher¶
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 Hardware configuration.
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
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
-
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.
-
template<typename
TimerApi
>
classDelegateCallbackTimer
: public CallbackTimer<TimerApi>¶ - #include <Timer.h>
Class template adding delegate callback method support to the basic CallbackTimer template.
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<TimeType
-
class
Timer
: public DelegateCallbackTimer<OsTimer64Api<Timer>>¶ - #include <Timer.h>
Callback timer class.
Subclassed by Profiling::MinMaxTimes< Timer >
-
class
AutoDeleteTimer
: public DelegateCallbackTimer<OsTimer64Api<AutoDeleteTimer>>¶ - #include <Timer.h>
Auto-delete callback timer class.
-
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.
Subclassed by CallbackTimer< OsTimerApi >
-
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 Functions
-
template<NanoTime::Unit
unit
, TimeTypetime
>
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
, TimeTypetime
>
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_ttime
>
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<PolledTimerClock, unit>¶
-
using
PeriodicElapseTimer
= PolledTimer::Periodic<PolledTimerClock, unit>¶
-
using
OneShotFastMs
= OneShotElapseTimer<NanoTime::Milliseconds>¶
-
using
PeriodicFastMs
= PeriodicElapseTimer<NanoTime::Milliseconds>¶
-
using
OneShotFastUs
= OneShotElapseTimer<NanoTime::Microseconds>¶
-
using
PeriodicFastUs
= PeriodicElapseTimer<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 PeriodicFastMs
periodicFastMs
¶
-
typedef OneShotFastUs
oneShotFastUs
¶
-
typedef PeriodicFastUs
periodicFastUs
¶
Defines
-
namespace
PolledTimer
¶ Typedefs
-
using
OneShot
= Timer<Clock, unit, false, uint32_t>¶
-
using
Periodic
= Timer<Clock, unit, true, uint32_t>¶
-
template<class
Clock
, NanoTime::Unitunit_
, boolIsPeriodic
, typenameTimeType
>
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 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
expired
()¶ Determine if timer has expired.
- Return Value
bool
:
-
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¶
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
, UnitunitsFrom
, UnitunitsTo
, typenameR
= 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
, UnitunitsTo
, typenameTimeType
>
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 NanoTime::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_tfrequency_
, typenameTickType_
, 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 >
-
struct
Frequency
¶ - #include <NanoTime.h>
Class to represent a frequency.
-
template<typename
Clock_
, typenameT
>
structTicks
¶ - #include <NanoTime.h>
Class to handle a tick value associated with a clock.
-
template<class
Clock_
, uint64_tticks_
>
structTicksConst
¶ - #include <NanoTime.h>
Class template representing a fixed clock tick count.
- Note
Includes compile-time range checking
- Template Parameters
Source_
:ticks_
:
-
template<typename
T
>
structTime
¶ - #include <NanoTime.h>
Class to handle a simple time value with associated unit.
-
template<class
Clock_
, Unitunit_
, uint64_ttime_
>
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_
:
-
template<class
Clock_
, Unitunit_
, typenameTimeType_
>
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
-
struct
TimeValue
¶ - #include <NanoTime.h>
A time time broken into its constituent elements.
- Note
Useful for analysing and printing time values
-
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
¶
-
isFlashPtr
(ptr)¶ Simple check to determine if a pointer refers to flash memory.
-
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
-
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¶
BitSet¶
The C++ STL provides std::bitset
which emulates an array of bool
elements.
The BitSet
class template provides similar support for sets of strongly-typed elements.
For example:
enum class Fruit {
apple,
banana,
kiwi,
orange,
passion,
pear,
tomato,
};
using FruitBasket = BitSet<uint8_t, Fruit, unsigned(Fruit::tomato) + 1>;
static constexpr FruitBasket fixedBasket = Fruit::orange | Fruit::banana | Fruit::tomato;
A FruitBasket
uses one byte of storage, with each bit representing an item of Fruit
.
If the basket contains a piece of fruit, the corresponding bit is set.
If it does not, the bit is clear.
Without BitSet you implement this as follows:
using FruitBasket = uint8_t;
static constexpr FruitBasket fixedBasket = _BV(Fruit::orange) | _BV(Fruit::banana) | _BV(Fruit::tomato);
To test whether the set contains a value you’d do this:
if(fixedBasket & _BV(Fruit::orange)) {
Serial.println("I have an orange");
}
With a BitSet, you do this:
if(fixedBasket[Fruit::orange]) {
Serial.println("I have an orange");
}
And you can add an element like this:
basket[Fruit::kiwi] = true;
Bit manipulation operators are provided so you can do logical stuff like this:
FruitBasket basket1; // Create an empty basket
// Add a kiwi fruit
basket1 = fixedBasket + Fruit::kiwi;
// Create a second basket containing all fruit not in our first basket
FruitBasket basket2 = ~basket1;
// Remove some fruit
basket2 -= Fruit::orange | Fruit::tomato;
And so on.
To display the contents of a BitSet, do this:
Serial.print(_F("My basket contains: "));
Serial.println(basket1);
You will also need to provide an implementation of toString(Fruit)
or whatever type you are using for the set elements.
-
template<typename
S
, typenameE
, size_tsize_
= sizeof(S) * 8>
classBitSet
¶ Manage a set of bit values using enumeration.
API is similar to a simplified std::bitset, but with added +/- operators.
- Note
It is important to specify size correctly when using enumerated values. In the
FruitBasket
example, we use auint8_t
storage type so can have up to 8 possible values. However, theFruit
enum contains only 7 values. The set operations will therefore be restricted to ensure that the unused bit is never set.- Template Parameters
S
: Storage type (e.g. uint32_t). This determines how much space to use, and must be an unsigned integer. It is safe to use this class in structures, where it will occupy exactly the required space.E
: Element type e.g. enum class. You can use any enum or unsigned integer for the elements. These must have ordinal sequence starting at 0.size_
: Number of possible values in the set. Defaults to maximum for given storage type. Number of possible values in the set. This must be at least 1, and cannot be more than the given Storage type may contain. For example, a :cpp:type:uint8_t
may contain up to 8 values.
Public Functions
-
constexpr
BitSet
()¶ Construct empty set.
-
template<typename
S2
>
constexprBitSet
(const BitSet<S2, E> &bitset)¶ Copy constructor.
- Parameters
bitset
: The set to copy
-
constexpr
BitSet
(S value)¶ Construct from a raw set of bits.
- Parameters
value
: Integral type whose bits will be interpreted as set{E}
-
constexpr
BitSet
(E e)¶ Construct set containing a single value.
- Parameters
e
: Value to place in our new BitSet object
-
bool
operator==
(const BitSet &other) const¶ Compare this set with another for equality.
-
bool
operator!=
(const BitSet &other) const¶ Compare this set with another for inequality.
-
constexpr BitSet
operator~
() const¶ Obtain a set containing all elements not in this one.
-
BitSet &
flip
()¶ Flip all bits in the set.
-
BitSet &
flip
(E e)¶ Flip state of the given bit.
-
size_t
count
() const¶ Get the number of elements in the set, i.e. bits set to 1.
-
BitSet &
operator+=
(const BitSet &rhs)¶ Union: Add elements to set.
-
BitSet &
operator-=
(const BitSet &rhs)¶ Remove elements from set.
-
template<>
BitSet &operator&=
(const BitSet &rhs)¶ Intersection: Leave only elements common to both sets.
-
BitSet &
operator|=
(const BitSet &rhs)¶ Union: Add elements to set.
-
BitSet &
operator^=
(const BitSet &rhs)¶ XOR - toggle state of bits using another set.
-
bool
test
(E e) const¶ Test to see if given element is in the set.
-
bool
operator[]
(E e) const¶ Read-only [] operator.
- Parameters
e
: Element to test for
- Return Value
bool
: true if given element is in the set
-
BitRef
operator[]
(E e)¶ Read/write [] operator.
This returns a temporary
BitRef object to support assignment operations such asset[x] = value
- Parameters
e
: Element to read or write
- Return Value
BitRef
: Temporary object used to do the read or write
-
bool
any
() const¶ Determine if set contains any values.
-
bool
any
(const BitSet &other) const¶ Determine if set contains any values from another set i.e. intersection != [].
-
bool
all
() const¶ Test if set contains all possible values.
-
bool
none
() const¶ Test if set is empty.
-
BitSet &
set
()¶ Add all possible values to the bit set.
-
BitSet &
set
(E e, bool state = true)¶ Set the state of the given bit (i.e. add to or remove from the set)
- Parameters
e
: Element to changestate
: true to add the element, false to remove it
-
BitSet &
reset
()¶ Remove all values from the set.
-
BitSet &
reset
(E e)¶ Clear the state of the given bit (i.e. remove it from the set)
-
bool
operator==
(E e) const¶ Determine if set consists of only the one given element.
-
constexpr
operator S
() const¶ Allow casts from the native storage type to get a numeric result for this set.
-
constexpr S
value
() const¶ Get stored bits for this bitset.
CString¶
Whilst use of char* pointers is very common in Sming code, it is generally advisable to avoid pointers in C++ where possible.
The STL provides class templates such as unique_ptr which deals with memory alllocation and de-allocation to avoid issues with memory leaks.
The CString class implements this on a char[] and adds some additional methods which are similar to the String
class.
String
objects each require a minimum of 24 bytes of RAM, and always contain a length field.
A CString is much simpler and contains only a char* pointer, so a NULL string is only 4 bytes.
When storing arrays or lists of strings (or objects containing those strings) which change infrequently, such as fixed configuration data, use a CString for memory efficiency.
-
class
CString
: public std::unique_ptr<char[]>¶ Class to manage a NUL-terminated C-style string When storing persistent strings in RAM the regular String class can become inefficient, so using a regular
char*
can be preferable. This class provides that with additional methods to simplify lifetime management and provide some interoperability with Wiring String objects.
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/Data/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
-
class
CStringArray
: private String¶ Class to manage a double null-terminated list of strings, such as “one\0two\0three\0”.
Concatenation operators
-
template<typename
T
>
CStringArray &operator+=
(T value)¶ Append numbers, etc. to the array.
- Parameters
value
: char, int, float, etc. as supported by String
Public Functions
-
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
-
template<typename
Streams¶
Sming provides a set of Stream class which extend Stream
methods.
IDataSourceStream
is used where read-only access is required.
It introduces the IDataSourceStream::readMemoryBlock()
method which
performs a regular read without updating the stream position.
This allows optimistic reading and re-sending, but cannot be handled by some stream
types and should be used with care.
ReadWriteStream
is used where read/write operation is required.
-
class
IDataSourceStream
: public Stream¶ Base class for read-only stream.
Subclassed by FSTR::Stream, IFS::FWFS::ArchiveStream, MultiStream, ReadWriteStream, SectionStream, StreamTransformer, TemplateStream, UrlencodedOutputStream
Public Functions
-
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
-
size_t
readBytes
(char *buffer, size_t length)¶ Read chars from stream into buffer.
Terminates if length characters have been read or timeout (see setTimeout). Returns the number of characters placed in the buffer (0 means no valid data found).
- Note
Inherited classes may provide more efficient implementations without timeout.
-
virtual uint16_t
readMemoryBlock
(char *data, int bufSize) = 0¶ 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
-
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, SeekOrigin 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
:
- 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.
-
virtual bool
isFinished
() = 0¶ Check if all data has been read.
- Return Value
bool
: True on success.
-
virtual int
available
()¶ Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
size_t
write
(uint8_t charToWrite)¶ From Stream class: We don’t write using this stream.
- Parameters
charToWrite
:
-
int
length
()¶ Return the total length of the stream.
- Return Value
int
: -1 is returned when the size cannot be determined
-
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
-
virtual MimeType
getMimeType
() const¶ Get MIME type for stream content.
- Return Value
MimeType
:
-
String
readString
(size_t maxLen)¶ Overrides Stream method for more efficient reading.
- Note
Stream position is updated by this call
-
virtual bool
moveString
(String &s)¶ Memory-based streams may be able to move content into a String.
If the operation is not supported by the stream,
s
will be invalidated and false returned.- Parameters
s
: String object to move data into
- Return Value
bool
: true on success, false if there’s a problem.
Because a String object must have a NUL terminator, this will be appended if there is sufficient capacity. In this case, the method returns true.
If there is no capacity to add a NUL terminator, then the final character of stream data will be replaced with a NUL. The method returns false to indicate this.
-
virtual StreamType
-
class
ReadWriteStream
: public IDataSourceStream¶ Base class for read/write stream.
Subclassed by CircularBuffer, EndlessMemoryStream, HardwareSerial, IFS::FileStream, LimitedMemoryStream, MemoryDataStream, OtaUpgrade::BasicStream, Storage::PartitionStream
Public Functions
-
size_t
write
(uint8_t charToWrite)¶ From Stream class: We don’t write using this stream.
- Parameters
charToWrite
:
-
virtual size_t
write
(const uint8_t *buffer, size_t size) = 0¶ Write chars to stream.
- Note
Although this is defined in the Print class, ReadWriteStream uses this as the core output method so descendants are required to implement it
- Parameters
buffer
: Pointer to buffer to write to the streamsize
: Quantity of chars to write
- Return Value
size_t
: Quantity of chars written to stream
-
virtual size_t
copyFrom
(IDataSourceStream *source, size_t size = SIZE_MAX)¶ 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
-
size_t
-
group
stream
Data stream classes.
Unnamed Group
-
using
StreamTransformerCallback
= Delegate<size_t(const uint8_t *in, size_t inLength, uint8_t *out, size_t outLength)>¶ Class that can be used to transform streams of data on the fly.
Callback specification for the stream transformers
- See
See
StreamTransformer::transform()
method for details
Typedefs
-
using
TemplateFlashMemoryStream
= FSTR::TemplateStream¶ Template stream using content stored in flash.
-
class
CircularBuffer
: public ReadWriteStream¶ - #include <CircularBuffer.h>
Circular stream class.
Base class for data source stream
-
class
Base64OutputStream
: public StreamTransformer¶ - #include <Base64OutputStream.h>
Read-only stream to emit base64-encoded content from source stream.
-
class
ChunkedStream
: public StreamTransformer¶ - #include <ChunkedStream.h>
Read-only stream to obtain data using HTTP chunked encoding.
Used where total length of stream is not known in advance
-
class
IDataSourceStream
: public Stream - #include <DataSourceStream.h>
Base class for read-only stream.
Subclassed by FSTR::Stream, IFS::FWFS::ArchiveStream, MultiStream, ReadWriteStream, SectionStream, StreamTransformer, TemplateStream, UrlencodedOutputStream
-
class
EndlessMemoryStream
: public ReadWriteStream¶ - #include <EndlessMemoryStream.h>
Memory stream that stores unlimited number of bytes.
Memory is allocated on write and released when all written bytes have been read out. This behaviour differs from a circular buffer as the size is not fixed.
-
class
FileStream
: public IFS::FileStream¶ - #include <FileStream.h>
File stream class.
-
class
GdbFileStream
: public IFS::FileStream¶ - #include <GdbFileStream.h>
GDB File stream class to provide access to host files whilst running under debugger.
-
class
DirectoryTemplate
: public SectionTemplate - #include <DirectoryTemplate.h>
Directory stream class.
Subclassed by IFS::HtmlDirectoryTemplate, IFS::JsonDirectoryTemplate
-
class
FileStream
: public IFS::FsBase, public ReadWriteStream - #include <FileStream.h>
File stream class.
Subclassed by FileStream, GdbFileStream, HostFileStream
-
class
HtmlDirectoryTemplate
: public IFS::DirectoryTemplate - #include <HtmlDirectoryTemplate.h>
Read-only stream access to directory listing with HTML output.
-
class
LimitedMemoryStream
: public ReadWriteStream¶ - #include <LimitedMemoryStream.h>
Memory stream operating on fixed-size buffer Once the limit is reached the stream will discard incoming bytes on write.
-
class
MemoryDataStream
: public ReadWriteStream¶ - #include <MemoryDataStream.h>
Read/write stream using expandable memory buffer.
This is intended to allow data to be streamed into it, then streamed back out at a later date.
It is not intended to have data continuously written in and read out; memory is not reclaimed as it is read.
Subclassed by IFS::FWFS::ObjectBuffer, JsonObjectStream
-
class
MultipartStream
: public MultiStream¶ - #include <MultipartStream.h>
Read-only stream for creating HTTP multi-part content.
-
class
MultiStream
: public IDataSourceStream¶ - #include <MultiStream.h>
Base class for read-only stream which generates output from multiple source streams.
Subclassed by MultipartStream, StreamChain
-
class
QuotedPrintableOutputStream
: public StreamTransformer¶ - #include <QuotedPrintableOutputStream.h>
Read-only stream that transforms bytes of data into quoted printable data stream.
-
class
ReadWriteStream
: public IDataSourceStream - #include <ReadWriteStream.h>
Base class for read/write stream.
Subclassed by CircularBuffer, EndlessMemoryStream, HardwareSerial, IFS::FileStream, LimitedMemoryStream, MemoryDataStream, OtaUpgrade::BasicStream, Storage::PartitionStream
-
class
TemplateFileStream
: public TemplateStream¶ - #include <TemplateFileStream.h>
Template stream using content from the filesystem.
-
class
TemplateStream
: public IDataSourceStream¶ - #include <TemplateStream.h>
Stream which performs variable-value substitution on-the-fly.
Template uses {varname} style markers which are replaced as the stream is read.
Subclassed by FSTR::TemplateStream, SectionTemplate, TemplateFileStream
-
class
HostFileStream
: public IFS::FileStream¶ - #include <HostFileStream.h>
Host File stream class.
-
class
TemplateStream
: public TemplateStream - #include <TemplateStream.hpp>
Template Flash memory stream class.
-
class
UrlencodedOutputStream
: public IDataSourceStream¶ - #include <UrlencodedOutputStream.h>
Represents key-value pairs as urlencoded string content.
-
class
PartitionStream
: public ReadWriteStream - #include <PartitionStream.h>
Stream operating directory on a Storage partition.
To support write operations, the target region must be erased first.
-
class
JsonObjectStream
: public MemoryDataStream¶ - #include <JsonObjectStream.h>
JsonObject stream class.
-
using
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
- See
Typedefs
-
using
ScanCompletedDelegate
= Delegate<void(bool success, BssList &list)>¶ Scan complete handler function.
-
using
SmartConfigDelegate
= Delegate<bool(SmartConfigEvent event, const SmartConfigEventInfo &info)>¶ Smart configuration handler function.
- Parameters
event
:info
:
- Return Value
bool
: return true to perform default configuration
-
using
WPSConfigDelegate
= Delegate<bool(WpsStatus status)>¶ 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 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 bool
setMacAddress
(const MacAddress &addr) const = 0¶ Set WiFi station MAC address.
Must be called from
init()
before activating station. Espressif place certain limitations on MAC addresses:- Parameters
addr
: The new MAC address
- Return Value
bool
: true on success
Bit 0 of the first byte of the MAC address can not be 1. For example:
OK: “1a:XX:XX:XX:XX:XX” NOT OK: “15:XX:XX:XX:XX:XX”
-
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
isLocal
(IpAddress address)¶ Determine if the given address is on the same subnet.
- Note
Use to prevent external access to services
- Parameters
address
:
- Return Value
bool
: true if address is local
-
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 void
-
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
- See
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 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 bool
setMacAddress
(const MacAddress &addr) const = 0¶ Set Access Point MAC address.
Must be called from
init()
before activating Access Point. Espressif place certain limitations on MAC addresses:- Parameters
addr
: The new MAC address
- Return Value
bool
: true on success
Bit 0 of the first byte of the MAC address can not be 1. For example:
OK: “1a:XX:XX:XX:XX:XX” NOT OK: “15:XX:XX:XX:XX:XX”
-
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
-
bool
isLocal
(IpAddress address)¶ Determine if the given address is on the same subnet.
- Note
Use to prevent external access to services
- Parameters
address
:
- Return Value
bool
: true if address is local
-
virtual void
-
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
-
using
StationConnectDelegate
= Delegate<void(const String &ssid, MacAddress bssid, uint8_t channel)>¶ 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
:
-
using
StationDisconnectDelegate
= Delegate<void(const String &ssid, MacAddress bssid, WifiDisconnectReason reason)>¶ 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.
- Parameters
ssid
: SSID from which we’ve disconnectedbssid
:reason
: Why the connection was dropped
-
using
StationAuthModeChangeDelegate
= Delegate<void(WifiAuthMode oldMode, WifiAuthMode newMode)>¶ 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
:
-
using
StationGotIPDelegate
= Delegate<void(IpAddress ip, IpAddress netmask, IpAddress gateway)>¶ 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
:
-
using
AccessPointConnectDelegate
= Delegate<void(MacAddress mac, uint16_t aid)>¶ 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
-
using
AccessPointDisconnectDelegate
= Delegate<void(MacAddress mac, uint16_t aid)>¶ 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
-
using
AccessPointProbeReqRecvedDelegate
= Delegate<void(int rssi, MacAddress mac)>¶ 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
-
using
WifiSnifferCallback
= Delegate<void(uint8_t *data, uint16_t length)>¶
-
using
WifiBeaconCallback
= Delegate<void(const BeaconInfo &beacon)>¶
-
using
WifiClientCallback
= Delegate<void(const ClientInfo &client)>¶
-
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.
-
class
ClientInfoList
: public Vector<ClientInfo>¶ - #include <WifiSniffer.h>
For applications to use to manage list of unique clients.
-
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
-
using
TaskCallback32
= void (*)(uint32_t param)¶ Task callback function type, uint32_t parameter.
- Note
Callback code does not need to be in IRAM
-
using
TaskCallback
= void (*)(void *param)¶ Task callback function type, void* parameter.
- Note
Callback code does not need to be in IRAM
-
using
TaskDelegate
= Delegate<void()>¶ Task Delegate callback type.
-
using
SystemReadyDelegate
= TaskDelegate¶ Handler function for system ready.
Enums
-
enum
CpuFrequency
¶ CPU Frequency.
Values:
-
eCF_80MHz
= 80¶ CPU 80MHz.
-
eCF_160MHz
= 160¶ CPU 160MHz.
-
eCF_240MHz
= 240¶ CPU 240MHz.
-
-
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
Public Functions
-
virtual void
onSystemReady
() = 0¶ Handle system ready events.
-
virtual void
-
class
SystemClass
¶ - #include <System.h>
System class.
Public Functions
-
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
:
-
bool
-
using
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¶
-
using
CommandFunctionDelegate
= Delegate<void(String commandLine, CommandOutput *commandOutput)>¶ 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
-
-
class
CommandHandler
¶ - #include <CommandHandler.h>
Command handler class.
Public Functions
-
CommandHandler
()¶ Instantiate a 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 produce useful results it requires a couple of seconds at startup to calibrate.
Use like this:
#include <Services/Profiling/CpuUsage.h>
// instantiate a single instance of :cpp:class:`Profiling::CpuUsage`
Profiling::CpuUsage cpuUsage;
// Will be called when CpuUsage calibration has completed
void onReady()
{
// Continue with application initialisation
}
void init()
{
// Begin clock calibration
cpuUsage.begin(onReady);
}
See RingTonePlayer for a more detailed 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¶
Wiring¶
The Wiring Framework is common to all Arduino platforms.
Some adaptations and improvements have been made for Sming which are documented here.
Vector¶
HashMap¶
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. 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).
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
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
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
Equality operator ==
- Return Value
bool
: true if Strings are identical
In-equality operator !=
- Return Value
bool
: Returns true if strings are not identical
Test for equality, without case-sensitivity
null strings are treated as empty.
- Return Value
bool
: true if strings are considered the same
Array operators
If index is invalid, returns NUL \0
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 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
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.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
Public Functions
-
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
-
bool
setBuffer
(const Buffer &buffer)¶ Set String content using move semantics from external memory buffer.
- Note
length MUST be <
size
- A NUL character is written at this location- Parameters
buffer
: We’ll take ownership of this buffer
- Return Value
bool
: true on success; on failure, ownership of buffer is not transferred
-
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
(char suffix) const¶ Compare the end of a String.
- Parameters
suffix
:
- 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
Public Static Attributes
-
constexpr size_t
SSO_CAPACITY
= STRING_OBJECT_SIZE - 2¶ Max chars. (excluding NUL terminator) we can store in SSO mode.
-
struct
Buffer
¶ Used with setBuffer and getBuffer methods.
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¶
Sming (main) Component
MMA-7455 Accelerometer Library
Arducam¶
A demonstration application for controlling ArduCAM camera modules via web or telnet interface.
References¶
Sming (main) Component
ArduCAM Library Library
Basic APA102¶
Demonstrates use of APA102 library for controlling smart LEDs via SPI.
References¶
Sming (main) Component
APA102 LED Library
Basic AWS¶
How to set up Amazon Web Services to use as an IOT gateway.
openssl rsa -in APP.private.key -out APP.private.key.der -outform DER openssl x509 -in APP.cert.pem -out APP.cert.der -outform DER
References¶
Sming (main) Component
Basic Audio¶
Demonstrates how to set up I2S driver to produce audio output.
References¶
Sming (main) Component
Signal Generator Library
Tone 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¶
Sming (main) Component
Basic Capsense¶
Simple demonstration showing raw output from a capacitive sensor.
References¶
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¶
Sming (main) Component
Basic Delegates¶
Demonstrates the various ways you can use callbacks within Sming.
References¶
Sming (main) Component
Basic Hardware PWM¶
Demonstrates how to generate PWM signals on multiple pins using Sming’s HardwarePWM class.
References¶
Sming (main) Component
Basic IFS¶
Simple Webserver demonstration using IFS.
View the filesystem using a web browser.
To see directory content in a different format, append ?format=XX
, one of:
json
text
html
Use the format archive
to retrieve an archive/backup of the directory tree as an FWFS image.
Building¶
By default, data is stored in a read-only FWFS (Firmware Filesytem) partition.
This sample also demonstrates how to store the data in a FlashString
object:
make config-clean
make ENABLE_FLASHSTRING_IMAGE=1
Because the data is linked into the program image this is only suitable for small filesystem images. This could be used to store default recovery data, especially with OTA updates because each program image is self-contained.
References¶
Sming (main) Component
LittleFS Component
Environment Variables¶
ENABLE_FLASHSTRING_IMAGE
Basic Interrupts¶
Simple example of how interrupts can be used within Sming.
References¶
Sming (main) Component
Basic NFC¶
Sample application to read an RFID tag using a suitable reader connected via SPI interface.
References¶
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¶
Sming (main) Component
Adafruit NeoPixel Library Library
Basic Ota¶
Introduction¶
This sample integrates Over-The-Air(OTA) Upgrader, Over-The-Air(OTA) Network Upgrader and Sming. It demonstrates dual rom booting, big flash support, OTA updates and dual spiffs filesystems. This sample should work on all supported architectures.
Esp8266¶
On Esp8266 we use rBoot as bootloader. 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
WIFI_SSID
&WIFI_PWD
environment variables with your wifi details.Edit the OTA server details defined in the application
component.mk
file.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).
Testing¶
For testing purposes we provide an Ota server that can be started on your desktop machine:
make otaserver
The server listens on port 9999 and all network interfaces. If your desktop has the following IP address 192.168.1.30
after connecting to your WIFI router then you can compile the sample to use this IP address and the testing OTA server:
make ROM_0_URL=http://192.168.1.30:9999/rom0.bin SPIFFS_URL=http://192.168.1.30:9999/spiff_rom.bin
make flash
Make sure to replace 192.168.1.30
with your WIFI IP address.
Flash layout considerations¶
Esp8266¶
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 rBoot for further details.
If using a very small flash (e.g. 512k) there may be no room for a spiffs fileystem, so use HWCONFIG = standard
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!
Configuration¶
-
RBOOT_TWO_ROMS
¶ Default: 1 (enabled)
Allows specifying two different URLs for ROM0 and ROM1.
If not set then only the URL defined in ROM_0_URL will be used.
-
ROM_0_URL
¶ Default: http://192.168.7.5:80/rom0.bin
The URL where the firmware for the first application partition can be downloaded.
-
ROM_1_URL
¶ Default: http://192.168.7.5:80/rom1.bin
Used when
RBOOT_TWO_ROMS
is set. The URL where the firmware for the second application partition can be downloaded.
-
SPIFFS_URL
¶ Default: http://192.168.7.5:80/spiff_rom.bin
The URL where the spiffs partition attached can be downloaded.
Credits¶
The initial sample was made possible with the assistance of piperpilot, gschmott and robotiko on the esp8266.com forum.
References¶
Sming (main) Component
Over-The-Air(OTA) Network Upgrader Component
Environment Variables¶
Basic ProgMem¶
This sample application demonstrates the various ways to access data stored in Flash memory.
References¶
Sming (main) Component
Basic I2C Scanner¶
Classic Arduino I2C scanner with adaptations for Sming framework.
References¶
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¶
Sming (main) Component
Basic Servo¶
Demonstrates use of the Servo library for controlling multiple servo actuators.
References¶
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 is ported from the C code that Espressif provides in their SDK examples.
You will need an App for your Smart Phone, such as:
ESP8266 SmartConfig (search on Android Play)
See also https://www.espressif.com/en/products/software/esp-touch/overview.
References¶
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¶
Sming (main) Component
malloc_count Component
Basic Storage¶
This sample application demonstrates various ways to manage and access flash memory using the Storage Management system.
It also shows how to create and partition custom storage devices.
References¶
Sming (main) Component
Basic Tasks¶
This sample demonstrates using the Task
class to efficiently perform intensive processing.
Let’s suppose we need to continuously sample an analogue input as fast as possible, do some processing and output the results.
This sample attempts to do some (very rough) fourier analysis on sampled ADC data, displaying the average amplitudes in a set of frequency ‘buckets’ (ranges).
The timing jitter using this approach is quite bad, so it attempts to correct but generally this form of processing is best done with more capable hardware (e.g. ESP32, FPGA).
In this sample application, we just write the results to the debug terminal, but a real application might stream this to waiting network clients.
References¶
Sming (main) Component
arduinoFFT Library
Signal Generator Library
Basic Utility¶
Demonstrates how to pass parameters to Host applications.
This allows creation of Host-only utility applications.
After building, try this:
make run HOST_PARAMETERS='command=testWebConstants'
To run the application directly, you can do this:
out/Host/debug/firmware/app --nonet command=testWebConstants
--nonet
is optional.
You may find --debug=0
useful to suppress all but host error messages.
Specify 1
to include warnings.
Use --help
to see available emulator options.
See HOST_PARAMETERS
for further details.
References¶
Sming (main) 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 HWCONFIG=standard ENABLE_FLASHSTRING_MAP=1
See webserver.cpp for the details.
References¶
Sming (main) Component
ArduinoJson Version 6 Library
Environment Variables¶
ENABLE_FLASHSTRING_MAP
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.In webserver.cpp, the onConfiguration() function uses request.getBody(). It is more efficient to use streams, so just replace with request.getBodyStream().
That’s it.
References¶
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¶
Sming (main) Component
CANBUS¶
Demonstrates communication with MCP2515-compatible devices via SPI interface.
References¶
Sming (main) Component
MCP_CAN Library for Arduino Library
CommandProcessing Debug¶
Demonstrates Sming’s command handling capability via HTTP, FTP and Telnet interfaces.
References¶
Sming (main) Component
HMC5883L Compass¶
HMC5883L sensor reader.

References¶
Sming (main) Component
HMC5883L Compass Library
DFPlayer Mini¶
Introduction¶
The DFPlayer Mini MP3 Player is a small and low-cost MP3 module with a 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/ESP32 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 files to your SD card. The example playes one file for some time and moves to the next one. * Insert your SD card in the slot of the DF Player module. * Flash and run the sample code.
References¶
Sming (main) Component
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¶
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¶
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¶
Sming (main) Component
Adafruit VL53L0X Library Library
DNS Captive Portal¶
Demonstrates how to use Sming to create a default landing page when configured as an Access Point.
References¶
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¶
Sming (main) Component
FTP Server Files¶
This example sets up an FTP server with a couple of files stored in SPIFFS. It mounts this on top of an FWFS volume (a hybrid filesystem).
The sample creates three users with different roles (guest, user and administrator).
User |
Password |
Role |
guest |
(none) |
Guest |
me |
“123” |
User |
admin |
“1234” |
Admin |
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.
Flash to your device:
make flash
You should be able to connect using an FTP client:
ftp ipaddress
and when prompted log in with one of the above usernames.
References¶
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¶
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¶
Sming (main) Component
HttpClient Instapush¶
Instapush is an event notification service created in 2014.
For details, see https://pushbots.com/.
References¶
Sming (main) Component
ArduinoJson Version 6 Library
ThingSpeak Http Client¶
Example of a HttpClient pushing data to ThingSpeak .

References¶
Sming (main) Component
AJAX Http Server¶
Demonstration of a simple web server with page updates using AJAX.
References¶
Sming (main) Component
ArduinoJson Version 6 Library
Bootstrap Http Server¶
Embedded web server.
This sample will download all requried files from a remote server.

References¶
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¶
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. See Hardware configuration.
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¶
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¶
Sming (main) Component
AM2321 Humidity Sensor¶
Example application demonstrating the use of the AM2321 Temperature/Humidity Sensor library.
References¶
Sming (main) Component
DHT22 Humidity Sensor¶
Example application demonstrating the use of the DHT ESP Temperature/Humidity Sensors library with a DHT22 humidity sensor.

References¶
Sming (main) Component
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¶
Sming (main) Component
IR Library¶
Example application demonstrating how to receive IR remote signals using the ESP8266.
References¶
Sming (main) Component
IRremoteESP8266 Library Library
WS2812 LEDs¶
Example application to demonstrate control of WS2812 RGB pixel-strip LEDs.
References¶
Sming (main) Component
WS2812 Neopixel Library
Yeelight LED bulbs¶
Demonstrates how to control Yeelight WiFi devices.
References¶
Sming (main) Component
Yeelight Library
BH1750 Light Sensor¶
ESP8266 BH1750 sensor reader.

References¶
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¶
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¶
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¶
Sming (main) Component
ArduinoJson Version 6 Library
Liquid Crystal Library
MeteoControl MQTT¶
Similar to MeteoControl sample without LCD interface and instead controlled via MQTT.
References¶
Sming (main) Component
MQTT Client Hello¶
Simple MQTT client example.
References¶
Sming (main) Component
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¶
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¶
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¶
Sming (main) Component
RCSwitch Library¶
Demonstration of how to control wireless (radio-controlled) devices such as switched mains sockets, TVs, etc.
References¶
Sming (main) Component
rc-switch Library
nRF24L01 Radio¶
Example application showing how to interface with the popular nRF24L01 2.4GHz radio transceivers.
References¶
Sming (main) Component
Arduino driver for nRF24L01 2.4GHz Wireless Transceiver 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¶
Sming (main) Component
Si4432 RF Transceiver Library
SD Card¶
SDCard/FAT file usage and write benchmark.
References¶
Sming (main) Component
SD Card Library
Used by¶
SD Card Sample
5110 LCD Screen¶
Demonstration of how to interface to Monochrome Nokia 5110 LCD Displays.
References¶
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¶
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¶
Sming (main) Component
ILI9163C TFT Display Library
ILI9340 and ILI9341 TFT Screens¶
Demonstration of how to interface with displays such as the Adafruit 2.8” Touch Shield V2 (SPI).
References¶
Sming (main) Component
Adafruit ILI9341 Display Library
ST7735 TFT Screen¶
Demonstration of how to interface with various SPI displays using the Adafruit ST7735 library.
References¶
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¶
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¶
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 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¶
Sming (main) Component
Telnet Server¶
Demonstrates a simple Telnet server application.
References¶
Sming (main) Component
DS1820 Temperature Sensor¶
DS1820/DS18B20 sensor reader.

References¶
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¶
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
Discover
This example just does Advertise. See Basic_Mdns for discovery example.
In short this code will advertise other machines about its ipaddress.
How to use mDNS:
ADD your WIFI_SSID / WIFI_PWD
Flash the Complied code to your ESP8266/ESP32 device
Open a web browser and go to “http://sming.local/” to open a sample webpage.
You should also be able to ping using the advertised name:
ping UDP_Server.local
Linux
You need to install Avahi mDNS/DNS-SD daemon.
In your browser type “http://sming.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://sming.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¶
Sming (main) Component
mDNS: Multicast Domain Name System 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 to 3.3v and should work without problems.
References¶
Sming (main) Component
Ultrasonic Library
WebcamServer sample¶
A sample providing access to webcams via HTTP server.
References¶
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¶
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¶
Sming (main) Component
Hosted RCP Server over Serial¶
Overview¶
This application creates a RPC server that will communicate over serial interface. To compile it for an Esp8266 microcontroller you can use the following command:
make SMING_ARCH=Esp8266
References¶
Sming (main) Component
HostEd Component
Hosted RCP Server over TCP¶
Overview¶
This application creates a RPC server that will communicate over TCP. You can either start an Access Point from the controller or connect the application to an existing WIFI Access point. The latter can be compiled using the following command:
make SMING_ARCH=Esp8266 CONNECT_TO_WIFI=1 WIFI_SSID="MySSID" WIFI_PWD="Secr3tP4Ssw0rd"
Configuration¶
-
CONNECT_TO_WIFI
¶ Default: 0 (disabled)
If set to 1 the application will try to connect to a WIFI access point. Make sure to provide also the WIFI_SSID and WIFI_PWD values.
If set to 0 the application will start an access point to which the Host application can connect.
-
WIFI_SSID
¶ Default: PleaseEnterSSID
WIFI Access Point name. If you have enabled CONNECT_TO_WIFI then make sure to set also WIFI_SSID and WIFI_PWD values.
-
WIFI_PWD
¶ Default: PleaseEnterPass
WIFI Access Point password. If you have enabled CONNECT_TO_WIFI then make sure to set also WIFI_SSID and WIFI_PWD values.
References¶
Sming (main) Component
HostEd Component
Environment Variables¶
TensorFlow_HelloWorld¶
The power of Machine Learning (ML) inside you microcontroller! This sample is a remake of the standard HelloWorld example from TensorFlowLite for Arduino. It demonstrated how a ML “model” can be used inside an ESP8266 mircocontroller with the help of Sming.
If you are not familiar with TensorFlow take a look at their documentation.
Compilation¶
This sample can be compiled and run on a ESP8266 microcontroller or on the Host architecture. In order to compile it for ESP8266 you must use ESP Quick Toolchain. The ESP Quick Toolchain is more feature-complete and allows the compilation to run without many modifications to the original library.
References¶
Sming (main) Component
Arduino TensorFlow Lite Library
CS5460 generic sample¶
The sample prints the measured RMS voltage each second (with CS5460 voltage and current filters enabled).
The default MISO pin (12) can be changed through the envvar:MISO variable. For example:
make MISO=13
These variables can be listed with:
make list-config
References¶
Sming (main) Component
CS5460 energy meter IC Library
Control your DIAL-enabled smart monitor/TV using Sming¶
Demonstrates starting of YouTube, playing a video and closing YouTube after a small period of time.
References¶
Sming (main) Component
DIscovery And Launch (DIAL) Library
Google Cast Client¶
Sample application that demonstrates how to send information directly from your application to your Smart TV using the Google Cast protocol.
A media file is started playing. From the terminal, you can control as follows:
‘f’: Skip forward 10 seconds ‘r’: Skip back 10 seconds space: Toggle between pause and play ‘q’: Quit playback
The chromecast device must be online at startup, or a connection error will result. Re-start the application to retry.
References¶
Sming (main) Component
GoogleCast Component
Basic Alexa¶
If you have an Echo Dot or other Amazon Alexa device, this shows how to provide simple support by emulating a Philips Hue lighting bridge.
Pairing is permanently enabled in this sample application so all you need to do is ask Alexa to discover devices and the lights should appear.
You can verify this is working by requesting a list of registered lights via HTTP:
http://IP_ADDRESS/api/user/lights
Turning the ESP LED on and off can be done by sending a POST
request to light 101.
The RESTED plugin for firefox is very useful for this sort of thing. The endpoint URL is:
http://IP_ADDRESS/api/user/lights/101/state
To turn the LED ON, the body of the request would contain:
{"on":true}
And to turn it off again:
{"on":false}
Remember to set the Content-Type
header to application/json
.
Here’s how to do it with CURL:
curl -X POST -H "Content-Type: application/json" -d "{on: true}" http://IP_ADDRESS/api/user/lights/101/state
References¶
Sming (main) Component
malloc_count Component
Hue Emulator Library
LittleFS inspector¶
Builds a basic filesystem and includes simple code to display commits by reading partition directly. Helps with understanding structure and evaluating performance.
References¶
Sming (main) Component
LittleFS Component
Basic MDNS¶
Demonstrates use of the MDNS library to discover local devices.
References¶
Sming (main) Component
mDNS: Multicast Domain Name System Component
ModbusMaster RTU generic sample¶
The generic sample calls mbLoop() each second. In mbLoop() the globalSeconds variable is incremented and sent to a slave device. Then the same register address of the same slave device is read and the result is output via debugf() using UART1.
The modbus response timeout can be changed using MB_RESPONSE_TIMEOUT
.
Check out my video.
References¶
Sming (main) Component
ModbusMaster RTU Library Library
OTA over MQTT¶
Introduction¶
This example demonstrates how you can create an application that updates its firmware Over The Air (OTA) using the MQTT protocol. This application uses OTA Firmware Upgrade via MQTT and follows the recommended versioning principles.
Based on ENABLE_OTA_ADVANCED
the firmware data can be either without any encoding or be signed and encrypted.
Tools¶
There are two tools that facilitate the packiging and deployment of a new firmware.
For more information read Firmware packaging
in the documentation of the OTA Firmware Upgrade via MQTT component.
Security¶
Depending on ENABLE_SSL
a standard SSL/TLS can be enabled. This way
The communication between the application and the server will be encrypted using standard SSL.
To prove that the server is the correct one: The MQTT clients should pin the public key fingerprint on the server. OR have a list of public key fingerprints that are allowed.
Depending on
ENABLE_CLIENT_CERTIFICATE
the application can send a client certificate that is signed by the server.
Configuration¶
-
APP_ID
¶ Default: “test”
This variable contains the unique application name.
-
APP_VERSION
¶ Default: not set
Contains the application major and minor versions separated by comma. Example “4.2”. If not set will use the current major and minor version from Sming.
-
APP_VERSION_PATCH
¶ Default: not set
Contains the application patch version as integer. For stable versions you can use 0 until 255. For unstable versions the current timestamp can be used as a patch version.
-
ENABLE_OTA_VARINT_VERSION
¶ Default: 1 (enabled)
If set to 1 the OTA upgrade mechanism and application will use a varint encoding for the patch version. Thus allowing unlimited number of patch versions. Useful for enumerating unstable/nightly releases. A bit more difficult to read and write but allows for unlimited versions.
If set to 0 the OTA upgrade mechanism and application will use one byte for the patch version which will limit it to 256 possible patch versions. Useful for enumarating stable releases. Easier to write and read but limited to 256 versions only.
-
ENABLE_OTA_ADVANCED
¶ Default: 0 (disabled)
If set to 1 the library will work with OtaUpgradeStream which supports signature and encryption of the firmware data itself. See Over-the-Air Firmware Upgrade for details.
-
ENABLE_SSL
¶ Default: unset (disable)
If set to 1 (highly recommended), OTA upgrade files will be trasnferred securely over TLS/SSL.
-
ENABLE_CLIENT_CERTIFICATE
¶ Default: 0 (disabled)
Used in combination with
ENABLE_SSL
. Set to 1 if the remote server requires the application to authenticate via client certficate.
-
MQTT_URL
¶ Default: depends on
ENABLE_SSL
andENABLE_CLIENT_CERTIFICATE
valuesUrl containing the location of the firmware update MQTT server.
References¶
Sming (main) Component
OTA Firmware Upgrade via MQTT Component
Environment Variables¶
MQTT_FINGERPRINT_SHA1
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
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¶
Sming (main) Component
malloc_count Component
ArduinoJson Version 6 Library
RingTone Library
Tone Generator Library
Screen TFT_S1D13781¶
This is a port of the demo from the Epson S1D13781 display controller. See TFT_S1D13781.
Evaluation boards are inexpensive and is a useful way to evaluate display modules with TFT interfaces.
References¶
Sming (main) Component
TFT_S1D13781 Library
VT100 Emulator Library
Basic ControlPoint¶
Demonstrates use of UPnP library to create and use control points.
References¶
Sming (main) Component
UPnP Schema Component
Basic UPnP¶
Demonstrates use of UPnP library.
The sample devices here can be fully enumerated over the network.
Services¶
UPnP devices may also provide services which can be enumerated and used to control it.
The Wemo device Wemo::Controllee
has two services for events and metadata.
The device and service descriptions are stored in the schema
directory.
This is used by UPnP to generate class code, so all we need to do is implement the action methods.
References¶
Sming (main) Component
UPnP Schema Component
Basic FlatBuffers Sample¶
Basic sample demonstrating encoding and decoding of data using flatbuffers. For more complicated examples take a look at the official flatbuffers tutorial.
References¶
Sming (main) Component
Flatbuffers Component
Modbusino RTU generic sample¶
The sample code provides three element uint16_t array used for the modbus slave registers. These values are printed each second through UART1. mbPrint() is triggered on valid write multiple registers (0x10) command.
Several environment variables (envvar:RS485_RE_PIN RS485_TX_LEVEL
) can be used for configuration.
The slave address is defined with envvar:MB_SLAVE_ADDR. For example:
make MB_SLAVE_ADDR=2
These variables can be listed with:
make list-config
References¶
Sming (main) Component
Environment Variables¶
MB_SLAVE_ADDR
Libraries¶
Sming comes with a number of ported libraries that cover many areas of embedded programming but for sure not all.
To reduce the size of the framework, some libraries are not included directly and must be retrieved if you wish to access any sample applications there.
For example, the Basic_UPnP sample application is contained in the UPnP library, which can be retrieved like this:
cd $SMING_HOME
make fetch UPnP
You should then get UPnP: found in ‘Libraries/UPnP’, so now we can build the sample:
cd Libraries/UPnP/samples/Basic_UPnP
make
Note
If your project references any libraries they will automatically be pulled in during the build.
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 Sming port of the 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
Configuration variables¶
-
TFT_CS_PIN
¶ Pin to use for SPI CS (Chip Select). Active low.
-
TFT_DC_PIN
¶ Pin for controlling DC (Data / Command) line
-
TFT_RESET_PIN
¶ Pin for resetting the display. Optional.
References¶
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¶
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
- The 1.44” TFT breakout
- as well as Adafruit raw 1.8” TFT display
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¶
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¶
Used by¶
Arducam Sample
arduinoFFT¶
Fast Fourier Transform for Arduino
This is a fork from https://code.google.com/p/makefurt/ which has been abandoned since 2011.
This is a C++ library for Arduino for computing FFT. Now it works both on Arduino and C projects.
Tested on Arduino 1.6.11
Installation on Arduino¶
Use the Arduino Library Manager to install and keep it updated. Just look for arduinoFFT. Only for Arduino 1.5+
Manual installation on Arduino¶
To install this library, just place this entire folder as a subfolder in your Arduino installation
When installed, this library should look like:
ArduinolibrariesarduinoFTT (this library’s folder) ArduinolibrariesarduinoFTTarduinoFTT.cpp (the library implementation file, uses 32 bits floats vectors) ArduinolibrariesarduinoFTTarduinoFTT.h (the library header file, uses 32 bits floats vectors) ArduinolibrariesarduinoFTTkeywords.txt (the syntax coloring file) ArduinolibrariesarduinoFTTexamples (the examples in the “open” menu) ArduinolibrariesarduinoFTTreadme.md (this file)
Building on Arduino¶
After this library is installed, you just have to start the Arduino application. You may see a few warning messages as it’s built.
To use this library in a sketch, go to the Sketch | Import Library menu and select arduinoFTT. This will add a corresponding line to the top of your sketch:
#include <arduinoFTT.h>
TODO¶
Ratio table for windowing function.
Document windowing functions advantages and disadvantages.
Optimize usage and arguments.
Add new windowing functions.
* Spectrum table?
API¶
arduinoFFT(void);
arduinoFFT(double *vReal, double *vImag, uint16_t samples, double samplingFrequency); Constructor
~arduinoFFT(void); Destructor
ComplexToMagnitude(double *vReal, double *vImag, uint16_t samples);
ComplexToMagnitude();
Compute(double *vReal, double *vImag, uint16_t samples, uint8_t dir);
Compute(double *vReal, double *vImag, uint16_t samples, uint8_t power, uint8_t dir);
Compute(uint8_t dir); Calcuates the Fast Fourier Transform.
DCRemoval(double *vData, uint16_t samples);
DCRemoval(); Removes the DC component from the sample data.
MajorPeak(double *vD, uint16_t samples, double samplingFrequency);
MajorPeak();
MajorPeakParabola(); Looks for and returns the frequency of the biggest spike in the analyzed signal.
Revision(void); Returns the library revision.
Windowing(double *vData, uint16_t samples, uint8_t windowType, uint8_t dir);
Windowing(uint8_t windowType, uint8_t dir); Performs a windowing function on the values array. The possible windowing options are:
FFT_WIN_TYP_RECTANGLE
FFT_WIN_TYP_HAMMING
FFT_WIN_TYP_HANN
FFT_WIN_TYP_TRIANGLE
FFT_WIN_TYP_NUTTALL
FFT_WIN_TYP_BLACKMAN
FFT_WIN_TYP_BLACKMAN_NUTTALL
FFT_WIN_TYP_BLACKMAN_HARRIS
FFT_WIN_TYP_FLT_TOP
FFT_WIN_TYP_WELCH
Exponent(uint16_t value); Calculates and returns the base 2 logarithm of the given value.
References¶
Source Code (submodule, may be patched).
Used by¶
Basic Tasks Sample
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
Compatibility¶
ArduinoJson works on the following hardware:
RedBearLab boards: BLE Nano, BLE Mini, WiFi Micro, LOLIN32…
Teensy boards
Intel boards: Edison, Galileo…
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¶
References¶
Used by¶
GoogleCast Library
Hue Emulator Library
RingTone Player Sample
Yeelight Library
Basic Web Skeleton Sample
HttpClient Instapush Sample
AJAX Http Server Sample
HttpServer Config Network Sample
MeteoControl 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
Compatibility¶
ArduinoJson works on the following hardware:
RedBearLab boards: BLE Nano, BLE Mini, WiFi Micro, LOLIN32…
Teensy boards
Intel boards: Edison, Galileo…
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!
Arduino TensorFlow Lite¶
This library runs TensorFlow machine learning models on microcontrollers, allowing you to build AI/ML applications powered by deep learning and neural networks.
With the included examples, you can recognize speech, detect people using a camera, and recognise “magic wand” gestures using an accelerometer.
The examples work best with the Arduino Nano 33 BLE Sense board, which has a microphone and accelerometer.
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¶
CS5460 energy meter IC¶
The CS5460(A) is a highly integrated power measurement solution which combines two Analog-to-digital Converters (ADCs), high-speed power calculation functions, and a serial interface on a single chip. It is designed to accurately measure and calculate: Real (True) Energy, Instantaneous Power, I RMS , and V RMS for single phase 2- or 3-wire power metering applications.
References¶
Used by¶
CS5460 generic sample Sample
Environment Variables¶
MISO
Submodule: CS5460¶
CS5460¶
Arduino library for CS5460
Using SPI interface to connect, tested on Arduino UNO.
Current functions include set config register arguments manually, read measurements in raw binary format and float number and calibrate gain and offset.
See detail information of CS5460: datasheet
Todo: Make full use of EOUT, EDIR and INT ports.
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
Usage¶
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
DIscovery And Launch (DIAL)¶
Introduction¶
DIAL—for DIscovery And Launch—is a simple protocol that second-screen devices can use to discover and launch apps on first-screen devices. For example, your can stream a video from your embedded device on your connected TV.
Using¶
Add
COMPONENT_DEPENDS += DIAL
to your application componenent.mk file.Add these lines to your application:
#include <Dial/Client.h> static UPnP::ControlPoint controlPoint; static Dial::Client* myClient; // Call when IP address has been obtained void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) { // ... /* Use UPnP to auto-discover all DIAL-enabled servers */ Dial::discover(controlPoint, [](Dial::Client& client) { // Are we looking for a specific device? Can match on friendlyName, UDN, etc. if(client.friendlyName() == F("FriendlyNameToFind")) { // Take a reference to the device myClient = &client; // Get an app and do something... auto& app = myClient->getApp("YouTube"); // Keep this device return true; } // Don't want this device, destroy it return false; }); // ... }
See the DIAL_Client sample application.
API Documentation¶
-
namespace
Dial
¶ -
-
class
Client
: public DeviceControl¶ - #include <Client.h>
Public Functions
-
App &
getApp
(const String &applicationId)¶ Get application object by name.
- Parameters
applicationId
: the unique application. A list of registered ids can be found here: http://www.dial-multiscreen.org/dial-registry/namespace-database#TOC-Registered-Names
- Return Value
App&
: Application object reference
-
App &
-
class
References¶
Source Code (submodule, may be patched).
UPnP Component
Used by¶
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¶
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
GoogleCast¶
This component allows you to communicate with Chrome Cast dongles or smart TVs that support the Google Cast Protocol.
Using¶
Add these lines to your application componenent.mk file:
COMPONENT_DEPENDS += GoogleCast ENABLE_SSL := Bearssl
Add these lines to your application:
#include <Network/GoogleCast/Client.h>
Basic example:
#include <Network/GoogleCast/Client.h> GoogleCast::Client castClient; void gotIp(IpAddress ip, IpAddress mask, IpAddress gateway) { // connect directly to the IP of the devise castClient.connect(IpAddress("192.168.10.15")); castClient.onConnect([](bool success) { Serial.print(F("Client connect: ")); Serial.println(success ? "OK" : "FAIL"); if(success) { // Starting YouTube on the device castClient.receiver.launch(APPID_YOUTUBE); } }); }
Re-Generating C files from proto file¶
You can re-generate the C files from the proto file. This can be useful if you want to use a newer version of the Google Cast proto file. Make sure to compile it using nanopb. The re-generation can be done with the commands below:
cd $SMING_HOME/Libraries/GoogleCast/samples/basic
make python-requirements # should be executed once to download and install the required python packages
make rebuild-cast-proto
Protocol¶
There are multiple documents in internet that describe the Google Cast protocol and its inner workings. As a start one can take a look at the presentation and documents below.
App-Ids¶
List of current APP-IDS https://clients3.google.com/cast/chromecast/device/baseconfig
Individual app configurations are obtained from this url: https://clients3.google.com/cast/chromecast/device/app?a={appid}
Where {appid} is the id of the app, and the output of this is JSON in the format of a receiver app defintion.
References¶
Source Code (submodule, may be patched).
ArduinoJson Version 6 Component
mDNS: Multicast Domain Name System Component
Nano Protocol-Buffer Component
Used by¶
Google Cast Client Sample
HMC5883L Compass¶
https://github.com/jrowberg/i2cdevlib.git
References¶
I2C Device Class Component
Used by¶
HMC5883L Compass Sample
HardwareSPI¶
Asynchronous SPI device stack for Sming.
Problem statement¶
The ESP8266 has limited I/O and the most useful way to expand it is using serial devices. There are several types available:
- I2C
Can be fast-ish but more limited than SPI, however slave devices generally cheaper, more widely available and simpler to interface as they only require 2 pins. The ESP8266 does have hardware support however, so requires a bit-banging solution. Inefficient.
- I2S
Designed for streaming audio devices but has other uses. See Esp8266 Drivers.
- RS232
Tied in with RS485, Modbus, DMX512, etc. Well-supported with asynchronous driver.
- SPI
Speed generally limited by slave device capability, can be multiplexed (‘overlapped’) onto SPI0 (flash memory) pins. The two SPI modules are identical, but the additional pins for quad/dual modes are only brought out for SPI0. In addition, three user chip selects are available in this mode; there is only one in normal mode although this can be handled using a regular GPIO.
The purpose of this driver is to provide a consistent interface which makes better use of the hardware capabilities.
Classes may inherit from
HSPI::Device
to provide support for specific devices such as Flash memory, SPI RAM, LCD controllers, etc.Device objects are attached to the stack via specified PinSet (overlapped or normal) and chip select.
Multiple concurrent devices are supported, limited only by available chip selects and physical constraints such as wire length, bus speeds.
2 and 4-bit modes are supported via overlap pins.
A
HSPI::Request
object supports transfers of up to 64K. The controller splits these into smaller transactions as required.Asynchronous execution so application does not block during SPI transfer. Application may provide a per-request callback to be notified when request has completed.
Blocking requests are also supported.
Support for moving data between Sming Streams and SPI memory devices using the
HSPI::StreamAdapter
.
SPI system expansion¶
A primary use-case for this driver is to provide additional resources for the ESP8266 using SPI devices such as:
MC23S017 SPI bus expander. Operates at 10MHz (regular SPI) and provides 16 additional I/O with interrupt capability.
High-speed shift registers. These can be wired directly to SPI busses to expand GPIO capability.
Epson S1D13781 display controller. See TFT_S1D13781. Evaluation boards are inexpensive and is a useful way to evaluate display modules with TFT interfaces. The Newhaven NHD-5.0-800480TF-ATXL#-CTP was used during development of this driver.
Bridgetek FT813 EVE TFT display controller. This supports dual/quad modes and clocks up to 30MHz.
NRF24L01 RF transceiver. Rated bus speed is 8MHz but it seems to work fine at 40MHz.
Serial memory devices. The library contains a driver for the IS62/65WVS2568GALL fast serial RAM, which clocks up to 45MHz and supports SDI/SQI modes.
Software operation¶
Overview¶
We have:
Controller: SPI hardware
Device: Slave device on the SPI bus
Request: Details of a transaction for a specific device
The Controller maintains an active list of requests (as a linked-list), but does not own the request objects. These will be allocated by the application, configured then submitted to the Controller for execution.
The Device specifies how a slave is connected to the bus, and that may change dynamically. For example, at reset an SPI RAM may be in SPI mode but can be switched into SDI/SQI modes.
This is device-specific so would be implemented by superclassing HSPI::Device
.
Requests¶
Each HSPI::Request
is split into transactions.
A transaction has four phases: command - address - MOSI - dummy - MISO.
All phases are optional.
The dummy bits are typically used in read modes and specified by the device datasheet.
No data is transferred during this phase.
The ESP8266 hardware FIFO is used for MOSI/MISO phases and is limited to 64 bytes, so larger transfers must be broken into chunks. The driver handles this automatically.
Requests may be executed asynchronously so the call will not block and the CPU can continue with normal operations. An optional callback is invoked when the request has completed. As an example, consider moving a 128KByte file from flash storage into FT813 display memory:
Read the first file chunk into a RAM buffer, submit an SPI request1 to transfer it asynchronously
Read the second file chunk into another RAM buffer, and prepare request2 for that (but do not submit it yet)
When request1 has completed, submit request2 (from the interrupt callback). Schedule a task to read the next chunk and prepare request1.
When request2 has completed, continue from step (2) to submit request1, etc.
Timing¶
A 64-byte data transfer (full hardware FIFO with 1 command byte and 3-byte address) at 26MHz would take 21us (5.25us in QIO mode) or 1680 (420) CPU cycles. To transfer 128Kbytes would take 2048 such transactions, 43ms (11ms for QIO), not including memory copy overheads.
In practice request sizes will be much smaller due to RAM constraints. Nevertheless, at high clock speeds the interrupt rate increases to the point where it consumes more CPU cycles than the actual transfer. The driver therefore disables interrupts in these situations and executes the request in task mode.
Bear in mind that issuing a blocking request will also require all queued requests to complete.
The driver does not currently support out-of-order execution, which might prioritise faster devices.
Pin Set¶
To avoid confusion, we’ll refer to the flash memory SPI bus as SPI0, and the user bus as SPI1. This driver doesn’t support direct use of SPI0 as on most devices it is reserved for flash memory. However, an overlap mode is supported which makes use of hardware arbitration to perform SPI1 transactions using SPI0 pins. This has several advantages:
Liberates three GPIO which would normally be required for MOSI, MISO and SCLK.
Only one additional pin is required for chip select.
Additional 2/4 bits-per-clock modes are available for supported devices.
For the ESP8266, these are the HSPI::PinSet
assignments:
- PinSet::normal
- MISO=GPIO12, MOSI=GPIO13, SCLK=GPIO14. One chip select:
GPIO15 (HSPI CS)
- PinSet::overlap
- MISO=SD0, MOSI=SD1, IO2=SD3, IO3=SD2, SCLK = CLK. Three chip selects:
GPIO15 (HSPI_CS)
GPIO1 (SPI_CS1 / UART0_TXD). This conflicts with the normal serial TX pin which should be swapped to GPIO2 if required.
GPIO0 (SPI_CS2)
- PinSet::manual
Typically a GPIO will be assigned to perform chip select (CS). The application should register a callback function via
HSPI::onSelectDevice()
which performs the actual switching. This MUST be in IRAM.
Note
The connections for IO2/3 look wrong above, but on two different models of SPI RAM chip these have been verified as correct by writing in SPIHD mode and reading in quad mode.
Multiplexed CS¶
Multiple devices can be supported on a single CS using, for example using a HC138 3:8 decoder. The CS line is connected to an enable input, with three GPIO outputs setting A0-2.
A custom controller should be created like this:
class CustomController: public HSPI::Controller
{
public:
bool startDevice(Device& dev, PinSet pinSet, uint8_t chipSelect) override
{
/*
* You should perform any custom validation here and return false on failure.
* For example, if we're only using 3 of the 8 available outputs.
*/
auto addr = chipSelect & 0x07;
if(addr > 3) {
debug_e("Invalid CS addr: %u", addr);
return false;
}
/*
*
*/
onSelectDevice(selectDevice);
/*
* Initialise hardware Controller
*/
auto cs = chipSelect >> 3;
return HSPI::Controller::startDevice(dev, pinSet, cs);
}
private:
void IRAM_ATTR selectDevice(uint8_t chipSelect, bool active)
{
// Only perform GPIO if CS changes as GPIO is expensive
if(active && chipSelect != activeChipSelect) {
auto addr = chipSelect & 0x07;
digitalWrite(PIN_MUXADDR0, addr & 0x01);
digitalWrite(PIN_MUXADDR1, addr & 0x02);
// As we only need 2 address lines, can leave this one
// digitalWrite(PIN_MUXADDR2, addr & 0x03);
activeChipSelect = chipSelect;
}
if(getActivePinSet() == HSPI::PinSet::manual) {
// Set CS output here
}
}
uint8_t activeChipSelect{0};
};
The application should register a callback function via HSPI::onSelectDevice()
allows 8 (or more) SPI devices to share the same bus.
Bits 0-2 of the chipSelect value might be assigned to the GPIO output pins setting
the multiplexer address, with bits 3-7 storing the hardware CS setting.
IO Modes¶
Not to be confused with HSPI::ClockMode
, the HSPI::IoMode
determines how
the command, address and data phases are transferred:
.
Bits per clock
.
IO Mode
Command
Address
Data
Duplex
SPI
1
1
1
Full
SPIHD
1
1
1
Half
DUAL
1
1
2
Half
DIO
1
2
2
Half
SDI
2
2
2
Half
QUAD
1
1
4
Half
QIO
1
4
4
Half
SQI
4
4
4
Half
Note
SDI and SQI are not supported directly by hardware, but is implemented within the driver using the data phase only. For 8-bit command and 24-bit address, this limits each transaction to 60 bytes.
This seems to be consistent with the ESP32 IDF driver, as in spi_ll.h
:
/** IO modes supported by the master. */
typedef enum {
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
SPI_LL_IO_MODE_DIO, ///< 2-bit mode for address and data phases, 1-bit mode for command phase
SPI_LL_IO_MODE_DUAL, ///< 2-bit mode for data phases only, 1-bit mode for command and address phases
SPI_LL_IO_MODE_QIO, ///< 4-bit mode for address and data phases, 1-bit mode for command phase
SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
} spi_ll_io_mode_t;
Somne devices (e.g. W25Q32 flash) have specific commands to support these modes, but others (e.g. IS62/65WVS2568GALL fast serial RAM) do not, and the SDI/SQI mode setting applies to all phases. This needs to be implemented in the driver as otherwise the user code is more complex than necesssary and performance suffers considerably.
Streaming¶
The HSPI::StreamAdapter
provides support for streaming of data to/from memory devices.
This would be used, for example, to transfer content to or from a FileStream
or FlashMemoryStream
to SPI RAM asynchronously.
Supported devices must inherit from HSPI::MemoryDevice
.
API¶
-
enum
HSPI
::
ClockMode
¶ SPI clock polarity (CPOL) and phase (CPHA)
Values:
-
mode0
= 0x00¶ CPOL: 0 CPHA: 0.
-
mode1
= 0x01¶ CPOL: 0 CPHA: 1.
-
mode2
= 0x10¶ CPOL: 1 CPHA: 0.
-
mode3
= 0x11¶ CPOL: 1 CPHA: 1.
-
-
enum
HSPI
::
IoMode
¶ Mode of data transfer.
Values:
-
SPI
¶ One bit per clock, MISO stage concurrent with MISO (full-duplex)
-
SPIHD
¶ One bit per clock, MISO stage follows MOSI (half-duplex)
-
DUAL
¶ Two bits per clock for Data, 1-bit for Command and Address.
-
DIO
¶ Two bits per clock for Address and Data, 1-bit for Command.
-
SDI
¶ Two bits per clock for Command, Address and Data.
-
QUAD
¶ Four bits per clock for Data, 1-bit for Command and Address.
-
QIO
¶ Four bits per clock for Address and Data, 1-bit for Command.
-
SQI
¶ Four bits per clock for Command, Address and Data.
-
-
enum
HSPI
::
PinSet
¶ How SPI hardware pins are connected.
Values:
-
none
¶ Disabled.
-
normal
¶ Standard HSPI pins.
-
manual
¶ HSPI pins with manual chip select.
-
overlap
¶ Overlapped with SPI 0.
-
Warning
doxygenclass: Cannot find class “HSPI::Request” in doxygen xml output for project “api” from directory: ../api/xml/
Warning
doxygenclass: Cannot find class “HSPI::Data” in doxygen xml output for project “api” from directory: ../api/xml/
-
class
Device
¶ Manages a specific SPI device instance attached to a controller.
Subclassed by HSPI::MemoryDevice
-
class
MemoryDevice
: public HSPI::Device¶ Base class for read/write addressable devices.
Subclassed by HSPI::RAM::IS62_65, HSPI::RAM::PSRAM64
Prepare a write request
-
virtual void
prepareWrite
(HSPI::Request &req, uint32_t address) = 0¶ - Parameters
request
:address
:
-
void
prepareWrite
(HSPI::Request &req, uint32_t address, const void *data, size_t len)¶ - Parameters
request
:address
:data
:len
:
Prepare a read request
-
virtual void
prepareRead
(HSPI::Request &req, uint32_t address) = 0¶ - Parameters
req
:address
:
-
void
prepareRead
(HSPI::Request &req, uint32_t address, void *buffer, size_t len)¶ - Parameters
req
:address
:data
:len
:
Public Functions
-
void
write
(uint32_t address, const void *data, size_t len)¶ Write a block of data.
- Note
Limited by current operating mode
- Parameters
address
:data
:len
:
-
void
read
(uint32_t address, void *buffer, size_t len)¶ Read a block of data.
- Note
Limited by current operating mode
- Parameters
address
:data
:len
:
-
virtual void
Warning
doxygenclass: Cannot find class “HSPI::SpiRam” in doxygen xml output for project “api” from directory: ../api/xml/
-
class
Controller
¶ Manages access to SPI hardware.
Public Types
-
using
SelectDevice
= void (*)(uint8_t chipSelect, bool active)¶ Interrupt callback for custom Controllers.
For manual CS (
PinSet::manual) the actual CS GPIO must be asserted/de-asserted.- Parameters
chipSelect
:active
: true when transaction is about to start, false when completed
Expanding the SPI bus using a HC138 3:8 multiplexer, for example, can also be handled here, setting the GPIO address lines appropriately.
Public Functions
-
void
end
()¶ Disable HSPI controller.
- Note
Reverts HSPI pins to GPIO and disables the controller
-
void
onSelectDevice
(SelectDevice callback)¶ Set interrupt callback to use for manual CS control (PinSet::manual) or if CS pin is multiplexed.
- Note
Callback MUST be marked IRAM_ATTR
-
virtual bool
startDevice
(Device &dev, PinSet pinSet, uint8_t chipSelect)¶ Assign a device to a CS# using a specific pin set. Only one device may be assigned to any CS.
Custom controllers should override this method to verify/configure chip selects, and also provide a callback (via
onSelectDevice()
).
-
void
configChanged
(Device &dev)¶ Devices call this method to tell the Controller about configuration changes. Internally, we just set a flag and update the register values when required.
-
using
-
class
StreamAdapter
¶ Helper class for streaming data to/from SPI devices.
References¶
Source Code (submodule, may be patched).
Used by¶
TFT_S1D13781 Library
Environment Variables¶
HSPI_ENABLE_STATS
HSPI_ENABLE_TESTPINS
HSPI_TESTPIN1
HSPI_TESTPIN2
Hue Emulator¶
A framework for emulating Hue smart light devices via the Hue::Bridge class.
A real bridge talks to Hue devices via ZigBee, however with Sming you can control anything you want using the published API. Refer to specifications available at https://developers.meethue.com (free account login required).
Setup¶
Refer to the Basic_Alexa sample for details of how to use this library. Here are a few key notes.
A HttpServer
object is required to allow the framework to respond to requests.
Note that Gen 3+ Hue Bridges listen on port 80 (standard HTTP), however older versions use port 1901.
This library has only been tested on port 80.
In your application, remember to add bodyparsers for JSON and XML:
server.setBodyParser(MIME_JSON, bodyToStringParser);
server.setBodyParser(MIME_XML, bodyToStringParser);
Without these, you’ll get empty bodies for incoming requests.
The sample demonstrates use of provided On/Off, Dimmable and Colour device types with a global callback function.
Ideally you should provide your own custom Hue devices by inheriting from Hue::Device
.
This is demonstrated using MyHueDevice. The device ID is 666.
API¶
-
class
Bridge
: public UPnP::schemas_upnp_org::device::Basic1Template<Bridge>¶ Public Types
-
using
ConfigDelegate
= Delegate<void(const Config &config)>¶ Called when a new user key is created.
The application should use this to store new users in persistent memory. At startup, these should be passed back via the
configure()
method.
-
using
StateChangeDelegate
= Delegate<void(const Hue::Device &device, Hue::Device::Attributes attr)>¶ A global callback may be provided to perform actions when device states change.
The callback is invoked only when all request actions have been completed. The current state may be quereied using
device::getAttribute
.- Parameters
device
: The device which has been updatedattr
: A set of flags indicating which attributes were changed
Public Functions
-
Bridge
(Hue::Device::Enumerator &devices)¶ Constructor.
- Parameters
devices
: List of devices to present
-
void
configure
(const Config &config)¶ Perform a configuration action.
- Parameters
config
: The action to perform
-
void
enablePairing
(bool enable)¶ Enable creation of new users.
This could be enabled via web page on local Access Point, or physical push-button. It should also be time limited, so exits pairing mode after maybe 30 seconds. If a user creation request is received then this is disabled automatically.
- Note
DO NOT leave this permanently enabled!
-
const Stats &
getStats
()¶ Get bridge statistics.
- Return Value
const
: Stats&
-
void
resetStats
()¶ Clear the bridge statistics.
-
const UserMap &
getUsers
() const¶ Access the list of users.
- Return Value
const
: UserMap&
-
void
getStatusInfo
(JsonObject json)¶ Get bridge status information in JSON format.
- Parameters
json
: Where to write information
-
struct
Config
¶
-
using
-
class
Device
: public Item¶ Subclassed by Hue::OnOffDevice
Public Types
-
using
Callback
= Delegate<void(Status status, int errorCode)>¶ Callback invoked when setAttribute() has completed.
- Note
Any status other than
success
is considered a failure- Parameters
status
: Result of the operationerrorCode
: Application-specific error code
Public Functions
-
virtual Status
setAttribute
(Attribute attr, unsigned value, Callback callback) = 0¶ Set a device attribute.
- Note
DO NOT invoke the callback directly: only use it if pended.
- Parameters
attr
: The attribute to changevalue
: Value for the attribute (exact type is attribute-specific)callback
: If you return Status::pending, invoke this callback when completed
- Return Value
Status
:
-
virtual bool
getAttribute
(Attribute attr, unsigned &value) const = 0¶ Get the (cached) device attribute value.
- Parameters
attr
:value
:
- Return Value
bool
: true on success, false if attribute not supported or value unknown
-
virtual String
getUniqueId
() const¶ Returns the unique device ID string.
- Note
Other forms of ID string may be used, however for maximum compatibility the standard format should be used. By default, this method uses the WiFi station MAC address, with 00:11 appended plus the 8-bit device ID.
- Return Value
String
: Unique ID of the form AA:BB:CC:DD:EE:FF:00:11-XX, consisting of a 64-bit Zigbee MAC address plus unique endpoint ID.
-
class
Enumerator
: public UPnP::Enumerator<Device, Enumerator>¶ Abstract class to manage a list of devices.
- Note
Applications must provide an implementation of this for the bridge. Returned device objects may only be considered valid for the duration of the current task call as they may be destroyed at any time.
Subclassed by Hue::DeviceListEnumerator
-
using
-
class
OnOffDevice
: public Hue::Device¶ Subclassed by Hue::DimmableDevice
-
class
DimmableDevice
: public Hue::OnOffDevice¶ Subclassed by Hue::ColourDevice
-
class
ColourDevice
: public Hue::DimmableDevice¶
-
enum
Hue
::
Status
¶ Status of a
setAttribute
request.Values:
-
success
¶ The action was performed immediately without error.
-
pending
¶ The action was accepted but requires further processing.
Use this to perform requests asynchronously. You MUST invoked the provided
Callback
function to complete the request.When controlling remote devices, for example connected via serial link, you might issue the command immediately and then return
pending
. When the serial response is received, or a timeout occurs, then the request can be completed. Note that the error code passed to the callback is optional and will be specific to your application: it will be output in verbose debug mode so may be useful.
-
error
¶ Action could not be completed.
If the Attribute not supported by your device, or an internal I/O error occured then return this value.
-
References¶
Source Code (submodule, may be patched).
ArduinoJson Version 6 Component
UPnP Component
UPnP Schema Component
Used by¶
Basic Alexa 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
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.
Supported Protocols¶
You can find the details of which protocols & devices are supported here.
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
Tell other people about this library
Contributors¶
Available here
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
).
Useful Links¶
http://blog.iteadstudio.com/nextion-tutorial-based-on-nextion-arduino-library/
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.
How do I get set up?¶
Please refer to the project’s wiki
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
LittleFS¶
Sming IFS integration of the LittleFS filesystem https://github.com/littlefs-project/littlefs.
References¶
Source Code (submodule, may be patched).
Used by¶
LittleFS inspector Sample
Basic IFS Sample
Submodule: `littlefs <>`__¶
littlefs¶
A little fail-safe filesystem designed for microcontrollers.
| | | .---._____
.-----. | |
--|o |---| littlefs |
--| |---| |
'-----' '----------'
| | |
Power-loss resilience - littlefs is designed to handle random power failures. All file operations have strong copy-on-write guarantees and if power is lost the filesystem will fall back to the last known good state.
Dynamic wear leveling - littlefs is designed with flash in mind, and provides wear leveling over dynamic blocks. Additionally, littlefs can detect bad blocks and work around them.
Bounded RAM/ROM - littlefs is designed to work with a small amount of memory. RAM usage is strictly bounded, which means RAM consumption does not change as the filesystem grows. The filesystem contains no unbounded recursion and dynamic memory is limited to configurable buffers that can be provided statically.
Example¶
Here’s a simple example that updates a file named boot_count
every time
main runs. The program can be interrupted at any time without losing track
of how many times it has been booted and without corrupting the filesystem:
#include "lfs.h"
// variables used by the filesystem
lfs_t lfs;
lfs_file_t file;
// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase,
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
};
// entry point
int main(void) {
// mount the filesystem
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
// read current count
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
}
Usage¶
Detailed documentation (or at least as much detail as is currently available) can be found in the comments in lfs.h.
littlefs takes in a configuration structure that defines how the filesystem operates. The configuration struct provides the filesystem with the block device operations and dimensions, tweakable parameters that tradeoff memory usage for performance, and optional static buffers if the user wants to avoid dynamic memory.
The state of the littlefs is stored in the lfs_t
type which is left up
to the user to allocate, allowing multiple filesystems to be in use
simultaneously. With the lfs_t
and configuration struct, a user can
format a block device or mount the filesystem.
Once mounted, the littlefs provides a full set of POSIX-like file and directory functions, with the deviation that the allocation of filesystem structures must be provided by the user.
All POSIX operations, such as remove and rename, are atomic, even in event of power-loss. Additionally, file updates are not actually committed to the filesystem until sync or close is called on the file.
Other notes¶
Littlefs is written in C, and specifically should compile with any compiler
that conforms to the C99
standard.
All littlefs calls have the potential to return a negative error code. The
errors can be either one of those found in the enum lfs_error
in
lfs.h, or an error returned by the user’s block device operations.
In the configuration struct, the prog
and erase
function provided by the
user may return a LFS_ERR_CORRUPT
error if the implementation already can
detect corrupt blocks. However, the wear leveling does not depend on the return
code of these functions, instead all data is read back and checked for
integrity.
If your storage caches writes, make sure that the provided sync
function
flushes all the data to memory and ensures that the next read fetches the data
from memory, otherwise data integrity can not be guaranteed. If the write
function does not perform caching, and therefore each read
or write
call
hits the memory, the sync
function can simply return 0.
Design¶
At a high level, littlefs is a block based filesystem that uses small logs to store metadata and larger copy-on-write (COW) structures to store file data.
In littlefs, these ingredients form a sort of two-layered cake, with the small logs (called metadata pairs) providing fast updates to metadata anywhere on storage, while the COW structures store file data compactly and without any wear amplification cost.
Both of these data structures are built out of blocks, which are fed by a common block allocator. By limiting the number of erases allowed on a block per allocation, the allocator provides dynamic wear leveling over the entire filesystem.
root
.--------.--------.
| A'| B'| |
| | |-> |
| | | |
'--------'--------'
.----' '--------------.
A v B v
.--------.--------. .--------.--------.
| C'| D'| | | E'|new| |
| | |-> | | | E'|-> |
| | | | | | | |
'--------'--------' '--------'--------'
.-' '--. | '------------------.
v v .-' v
.--------. .--------. v .--------.
| C | | D | .--------. write | new E |
| | | | | E | ==> | |
| | | | | | | |
'--------' '--------' | | '--------'
'--------' .-' |
.-' '-. .-------------|------'
v v v v
.--------. .--------. .--------.
| F | | G | | new F |
| | | | | |
| | | | | |
'--------' '--------' '--------'
More details on how littlefs works can be found in DESIGN.md and SPEC.md.
Testing¶
The littlefs comes with a test suite designed to run on a PC using the emulated block device found in the emubd directory. The tests assume a Linux environment and can be started with make:
make test
License¶
The littlefs is provided under the BSD-3-Clause license. See LICENSE.md for more information. Contributions to this project are accepted under the same license.
Individual files contain the following tag instead of the full license text.
SPDX-License-Identifier: BSD-3-Clause
This enables machine processing of license information based on the SPDX License Identifiers that are here available: http://spdx.org/licenses/
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).
Used by¶
CANBUS Sample
mDNS: Multicast Domain Name System¶
https://en.wikipedia.org/wiki/Multicast_DNS
Responder¶
Sming provides the mDNS::Responder
class to allow applications
to advertise themselves on the local network.
To use:
Add
COMPONENT_DEPENDS += MDNS
to your application componenent.mk file.Add these lines to your application:
#include <Mdns/Responder.h> static mDNS::Responder responder; // Call when IP address has been obtained void startmDNS() { responder.begin(F("myhostname"); }
This will advertise the device as myhostname.local
.
To provide a custom service, implement a mDNS::Service
class
and call mDNS::Responder::addService()
.
See the UDP Server mDNS sample application.
Discovery¶
This library also provides support for device discovery using a separate set of classes,
based on the mDNS::Server
.
See Basic_Mdns for an example.
Testing¶
For linux, you can use avahi to perform mDNS queries and confirm output is as expected:
sudo apt install avahi
avahi-browse --all -r
References¶
Multicast DNS RFC6762 https://tools.ietf.org/html/rfc6762
Zero-configuration networking (DNS-SD) https://en.wikipedia.org/wiki/Zero-configuration_networking
DNS-Based Service Discovery https://tools.ietf.org/html/rfc6763
DNS record types https://en.wikipedia.org/wiki/List_of_DNS_record_types
Domain Names: Implementation and Specification https://tools.ietf.org/html/rfc1035
API Documentation¶
-
namespace
mDNS
¶ -
Functions
Variables
-
constexpr uint32_t
MDNS_IP
= {0xFB0000E0}¶
-
constexpr uint16_t
MDNS_TARGET_PORT
= {5353}¶
-
constexpr uint16_t
MDNS_SOURCE_PORT
= {5353}¶
-
constexpr uint16_t
MDNS_TTL
= {255}¶
-
constexpr uint16_t
MAX_PACKET_SIZE
= {1024}¶
-
class
Handler
: public LinkedObjectTemplate<Handler>¶ - #include <Handler.h>
Virtual base class used for chaining message handlers.
Subclassed by mDNS::Responder
-
class
Message
¶ - #include <Message.h>
Encapsulates a message packet for flexible introspection.
Subclassed by mDNS::Request
-
class
Name
¶ - #include <Name.h>
Encoded DNS name.
mDNS-SD names are represented as instance.service.domain. See https://tools.ietf.org/html/rfc6763#section-4.1
Instance names should be friendly and not attempt to be unique. See https://tools.ietf.org/html/rfc6763#appendix-D
Example: “UDP Server._http._tcp.local” instance: “UDP Server” service: “_http._tcp” name: “http” protocol: Protocol::Tcp domain: “local”
-
class
Responder
: public mDNS::Handler¶ - #include <Responder.h>
Special name for querying list of services.
-
class
Server
: protected UdpConnection¶ - #include <Server.h>
Locates mDNS services by issuing queries.
-
class
Service
: public LinkedObjectTemplate<Service>¶ - #include <Service.h>
Describes a basic service.
The default methods translate to a DNS-SD name of “Sming._http._tcp.local”. See :cpp:class:
mDNS::Name
for a description of how names are defined.
-
namespace
Resource
¶ -
-
class
AAAA
: public mDNS::Resource::Record¶ - #include <Resource.h>
‘AAAA’ record containing 128-bit IPv6 address
-
class
HINFO
: public mDNS::Resource::Record¶ - #include <Resource.h>
‘HINFO’ record containing Host information
-
class
PTR
: public mDNS::Resource::Record¶ - #include <Resource.h>
‘PTR’ record containing pointer to a canonical name
-
class
Record
¶ - #include <Resource.h>
Resource Record with no specific type.
Subclassed by mDNS::Resource::A, mDNS::Resource::AAAA, mDNS::Resource::HINFO, mDNS::Resource::PTR, mDNS::Resource::SRV, mDNS::Resource::TXT
-
class
-
constexpr uint32_t
References¶
Source Code (submodule, may be patched).
Used by¶
GoogleCast Library
Basic MDNS Sample
UDP Server mDNS Sample
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:
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 |
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¶
Used by¶
Basic NFC Sample
MMA-7455 Accelerometer¶
Library for the MMA-7455 3-axis accelerometer
References¶
Used by¶
MMA7455 Accelerometer Sample
Mirf for NRF24L01¶
Arduino port of Mirf for the NRF24L01 modules
References¶
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>`_.
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.
-
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;
};
© 2012 Igor Afonov
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. |
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
-
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.
References¶
Over-The-Air(OTA) Upgrader Component
libsodium Component
Used by¶
HttpServer Firmware Upload Sample
Environment Variables¶
ENABLE_OTA_ENCRYPTION
OTA Firmware Upgrade via MQTT¶
Introduction¶
This library allows Sming applications to upgrade their firmware Over-The-Air (OTA) using the MQTT protocol. MTQTT has less overhead compared to HTTP and can be used for faster delivery of application updates.
Using¶
Add
COMPONENT_DEPENDS += OtaUpgradeMqtt
to your application componenent.mk file.Add these lines to your application:
#include <OtaUpgrade/Mqtt/RbootPayloadParser.h> #if ENABLE_OTA_ADVANCED #include <OtaUpgrade/Mqtt/AdvancedPayloadParser.h> #endif MqttClient mqtt; // Call when IP address has been obtained void onIp(IpAddress ip, IpAddress mask, IpAddress gateway) { // ... mqtt.connect(Url(MQTT_URL), "sming"); #if ENABLE_OTA_ADVANCED /* * The advanced parser suppors all firmware upgrades supported by the `OtaUpgrade` library. * `OtaUpgrade` library provides firmware signing, firmware encryption and so on. */ auto parser = new OtaUpgrade::Mqtt::AdvancedPayloadParser(APP_VERSION_PATCH); #else /* * The command below uses class that stores the firmware directly * using RbootOutputStream on a location provided by us */ auto parser = new OtaUpgrade::Mqtt::RbootPayloadParser(part, APP_VERSION_PATCH); #endif mqtt.setPayloadParser([parser] (MqttPayloadParserState& state, mqtt_message_t* message, const char* buffer, int length) -> int { return parser->parse(state, message, buffer, length); }); String updateTopic = "a/test/u/4.3"; mqtt.subscribe(updateTopic); // ... }
See the Upgrade sample application.
Versioning Principles¶
To simplify the OTA process we strongly recommend the following versioning principles for your application:
Use semantic versioning. If your current application version is 4.3.1 then 4 is the major, 3 is the minor and 1 is the patch version number.
Every application firmware knows its version.
An application with the same major and minor version should be compatible for update no matter what the patch number is. If the new firmware is not compatible then a new minor or major version should be used.
Theory Of Operation¶
On a period of time the application connects to check if there is a new version of the firmware. In your application this period has to be carefully selected so that OTA updates occur when the device has enough resources: memory, space on flash, power and time to complete such an update. Also there should be no critical task running at the moment. Depending on the size of the new firmware and the speed of the connection an update can take 10 to 20 seconds.
The application connects via MQTT to a remote server and subscribes to a special topic. The topic is based on the application id and its current version. If the current application id is
test
and version is4.3.1
then the topic that will be used for OTA isa/test/u/4.3
.If there is a need to support both stable and unstable/nightly builds then the topic name can have s or u suffix. For example all stable versions should be published and downloaded from the topic
a/test/u/4.3/s
. For the unstable ones we can use the topica/test/u/4.3/u
. If an application is interested in both stable and unstable versions then it can subscribe using the following patterna/test/u/4.3/+
.The application is waiting for new firmware. When the application is on battery than it makes sense to wait for a limited time and if there is no message coming back to disconnect.
Firmware packaging¶
The firmware update must come as one MQTT message. The MQTT protocol allows messages with a maximum size of 268435455 bytes approx 260MB. This should be perfectly enough for a device that has maximum 1MB available for an application ROM.
One MQTT message contains:
patch version of the firmware
followed by the firmware data itself
Based on the ENABLE_OTA_VARINT_VERSION
the patch version can be encoded either using one byte or a varint.
Based on ENABLE_OTA_ADVANCED
the firmware data can be either without any encoding or be signed and encrypted.
To simplify the packaging this library comes with a tool called deployer
. To create a package type the following from your application:
make ota-pack OTA_PATCH_VERSION=127
Replace 127 with the desired patch version.
If the option OTA_PATCH_VERSION
is omitted from the command line then the patch version will be generated automatically and it will contain the current unix timestamp.
Once a package is created it can be deployed to the firmware MQTT server using the command below:
make ota-deploy MQTT_FIRMWARE_URL=mqtt://relser:relpassword@attachix.com/a/test/u/4.3
The MQTT_FIRMWARE_URL
above specifies that
protocol is: mqtt without SSL. Allowed values here are
mqtt
andmqtts
. The latter uses SSL.user is: relser
password is: relpassword
host is: attachix.com
path is: /a/test/u/4.3. The path without leading and ending slashes is used to generate the topic name
a/test/u/4.3
.
Make sure to replace the MQTT_FIRMWARE_URL value with your MQTT server credentials, host and topic.
Security¶
For additional security a standard SSL/TLS can be used
The communication should be secured using standard SSL.
To prove that the server is the correct one: The MQTT clients should pin the public key fingerprint on the server. OR have a list of public key fingerprints that are allowed.
To prove that the clients are allowed to connect: Every MQTT client should also have a client certificate that is signed by the server.
Configuration¶
-
ENABLE_OTA_VARINT_VERSION
¶ Default: 1 (enabled)
If set to 1 the OTA upgrade mechanism and application will use a varint encoding for the patch version. Thus allowing unlimited number of patch versions. Useful for enumerating unstable/nightly releases. A bit more difficult to read and write but allows for unlimited versions.
If set to 0 the OTA upgrade mechanism and application will use one byte for the patch version which will limit it to 256 possible patch versions. Useful for enumarating stable releases. Easier to write and read but limited to 256 versions only.
-
ENABLE_OTA_ADVANCED
¶ Default: 0 (disabled)
If set to 1 the library will work with OtaUpgradeStream which supports signature and encryption of the firmware data itself. See Over-the-Air Firmware Upgrade for details. In the application the AdvancedPayloadParser can be used to do the MQTT message handling.
References¶
Over-The-Air(OTA) Upgrader Component
Used by¶
OTA over MQTT Sample
Environment Variables¶
rc-switch¶
Use your Arduino or Raspberry Pi to operate remote radio controlled devices
Download¶
Wiki¶
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
RapidXML¶
This is a port of https://github.com/dwd/rapidxml with minimal patch, and additional support code for Sming.
References¶
Source Code (submodule, may be patched).
Used by¶
UPnP Library
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.
numElements()¶
size_t numElements();
Returns number of elements in the buffer.
isFull()¶
bool isFull();
Returns true if buffer is full, otherwise false.
isEmpty()¶
bool isEmpty();
Returns true if buffer is empty, false otherwise.
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¶
Source Code (submodule, may be patched).
Used by¶
RingTone Player Sample
SD Card¶
Low-level support code for accessing SD Cards using FATFS.
References¶
Used by¶
SD Card Sample
SI7020/SI7021 Environmental Sensors¶
Arduino library for SI7020 and SI7021 environmental sensors
Examples:
References¶
Used by¶
SI7021 Humidity Sensor Sample
MeteoControl MQTT Sample
SSDP¶
https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol
Provides an SSDP server implementation aiming to be fully standards compliant.
Configuration Variables¶
-
SSDP_DEBUG_VERBOSE
¶ 0 (default)
1: Output details of all requests. Warning: This can produce a lot of output!
-
UPNP_VERSION
¶ UPnP standard to follow.
1.0: (default)
1.1: Incomplete
2.0: Incomplete
Versions 1.1 and 2.0 require
BOOTID.UPNP.ORG
andCONFIGID.UPNP.ORG
fields which are not currently implemented.
Key points from UPnP 2.0 specification¶
I’m choosing to avoid the issue of ‘multi-homed’ devices, where both IPv4 and IPv6 are being used, and probably also WiFi+Ethernet combinations. Basically whenever multiple IP stacks are involved.
Advertisement¶
Multicast using ssdp:alive
messages.
3 messages for each root device:
upnp:rootdevice
uuid:device-UUID
urn:<domain>:<deviceType:ver>
2 for each embedded device:
uuid:device-UUID
urn:<domain>:<deviceType:ver>
1 for each service type in each device:
urn<domain>:<serviceType:ver>
Initial advertisements ‘should be sent as quickly as possible’. Subsequent advertisements ‘are allowed to be spread over time’.
For orderly shutdown, multicast ssdp:byebye
messages as for ssdp:alive
.
Note that ssdp:update
messages are only mentioned in the spec. wrt. mult-homed devices.
Devices should wait a random interval (e.g. 0 - 100 ms) before sending an initial
set of advertisements in order to reduce the likelihood of network storms;
this random interval should also be applied on occasions where the device obtains
a new IP address or a new UPnP-enabled interface is installed.
Due to the unreliable nature of UDP, devices should send the entire set of discovery
messages more than once with some delay between sets e.g. a few hundred milliseconds.
To avoid network congestion discovery messages should not be sent more than three times.
The device shall re-send its advertisements periodically prior to expiration of the
duration specified in the CACHE-CONTROL header field; it is Recommended that such
refreshing of advertisements be done at a randomly-distributed interval of less than
one-half of the advertisement expiration time, so as to provide the opportunity
for recovery from lost advertisements before the advertisement expires, and to
distribute over time the advertisement refreshment of multiple devices on the network
in order to avoid spikes in network traffic.
Note that UDP packets are also bounded in length (perhaps as small as 512
Bytes in some implementations); each discovery message shall fit entirely in a single UDP
packet. There is no guarantee that the above 3+2d+k messages will arrive in a particular
order.
Search request¶
M-SEARCH: “Please tell me about yourselves, but don’t all shout at once.”
ssdp:all
Search for all devices and services.
upnp:rootdevice
Search for root devices only.
uuid:device-UUID
Search for a particular device.
urn:<domain>:device:deviceType:ver
Search for any device of this type.
urn:<domain>:service:serviceType:ver
Search for any service of this type.
Period characters in <domain> are always substituted with hyphens (RFC 2141).
Not clear on how to handle version numbers at present. The specs. say only minor versions
are backward compatible, which why perhaps we only see major numbers in interface
definitions. e.g. Basic:1
not Basic:1.0
.
Search reponse¶
Any device responding to a unicast M-SEARCH should respond within 1 second.
In response to an M-SEARCH request, if ST header in request was:
ssdp:all
Respond 3+2d+k times for a root device with d embedded devices and s embedded services
but only k distinct service types.
Value for ST header must be the same as for the NT header in NOTIFY messages with ssdp:alive.
upnp:rootdevice
Respond once for root device.
uuid:device-UUID
Respond once for each matching device, root or embedded.
urn:<domain>:device:deviceType:v
Respond once for each matching device, root or embedded.
Should specify the version of the device type contained in the M-SEARCH request.
urn:<domain>:service:serviceType:v
Respond once for each matching service type.
Should specify the version of the service type contained in the M-SEARCH request.
Descriptions¶
The LOCATION
field is for the device description or enclosing device in the case of a service.
This implies that we never respond with a service description, which makes sense:
The device description provides key information about its services
The service description contains action lists or state variable tables
Only the device description is required to learn about services, whilst the service description is only required if the Control Point needs to interact with that service.
Points arising¶
So we need a filter which then gets passed through the device stack. Each response must be sent on a schedule, not all together, so we’ll need to set up a timer. We’ll also need to track state something like the DescriptionStream. Actually, what we can do is create an enumerator which iterates through the entire device stack. That will take out the complexity from here and DescriptionStream. We’ll need an additional Item tag so we can differentiate. This can either be a virtual method or we could use a union with all the different Item types plus a separate tag field. That could also contain the search filter information as input.
Move all this stuff into an SsdpResponder class?
References¶
Source Code (submodule, may be patched).
Used by¶
UPnP Library
Environment Variables¶

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
- 4
References¶
Source Code (submodule, may be patched).
Used by¶
Basic Audio Sample
Basic Tasks 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¶
Source Code (submodule, may be patched).
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.
Products that use this Library¶
SEN-12787- Avago APDS-9960
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
SPIFFS IFS Library¶
This Component provides SPIFFS filesystem support for all architectures.
A single SPIFFS partition is defined using HWCONFIG
=spiffs
, which supports these build variables:
DISABLE_SPIFFS
¶[deprecated and removed]
This value is no longer supported. Please remove it from your project’s component.mk file.
SPIFF_SIZE
¶[deprecated and removed]
Size (in bytes) of the SPIFFS area in Flash memory. To change this, edit the Hardware configuration.
SPIFF_FILES
¶
SPIFF_FILES
¶default:
files
The SPIFFS image is built using files from this directory, which must exist or the build will fail.
If you set this to an empty value, then an empty filesystem will be created.
SPIFF_BIN
¶Filename to use for the generated SPIFFS filesystem image. The default is
spiff_rom
.
SPIFF_BIN_OUT
¶[read-only] Shows the full path to the generated image file.
For more control over the SPIFFS partition you can create your own partition definition in a custom Hardware configuration.
-
SPIFF_FILEDESC_COUNT
¶ Default: 7
Number of file descriptors allocated. This sets the maximum number of files which may be opened at once.
-
SPIFFS_OBJ_META_LEN
¶ Default: 16
Maximum size of metadata which SPIFFS stores in each file index header (after the filename). If this value is changed, existing SPIFFS images will not be readable.
The default value given here is provided to support Installable File System extended file attribute information.
The first 16 bytes are used for system attributes (e.g. modified time), so setting this to, say, 64 leaves 48 bytes for user metadata. Each attribute has a 2-byte header (tag + size) so a single user attribute can be stored of up to 46 bytes, or multiple tags up to this limit.
Note: LittleFS provides better support for user metadata.
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!
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
mkdir build; make
Otherwise, configure the builddir
variable towards the top of makefile
as something opposed to the default build
. Sanity check on the host via make 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.
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.
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
See the wiki for configuring, integrating, using, and optimizing spiffs.
For design, see docs/TECH_SPEC.
For a generic spi flash driver, see this.
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 file
New config defines:
SPIFFS_OBJ_META_LEN
- enable possibility to add extra metadata to files
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 length
New 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 cache
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)
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 offset
New config defines:
SPIFFS_READ_ONLY
SPIFFS_USE_MAGIC_LENGTH
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
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 gc
Removed two return warnings, was too triggerhappy on release
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 targets
New 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 mounted
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¶
Adafruit GFX Component
Used by¶
ILI9163C TFT Screen Sample
TFT_S1D13781¶
Introduction¶
This is a port of the driver from the Epson S1D13781 display controller using the HardwareSPI library.
Evaluation boards are inexpensive and is a useful way to evaluate display modules with TFT interfaces.
The Newhaven NHD-5.0-800480TF-ATXL#-CTP was used during development.

Video line: https://youtu.be/UgLX9gEdz6A
Notes¶
This library was developed as a stepping stone to the Bridgetek FT81x series EVE Embedded Video Engines.
These are more advanced and work by buffering graphics command primitives which are then executed in real time to construct each displayed frame.
These devices are used in the Gameduino. The author has an open source library.
This library is not fully asynchronous, but has couple of key improvements over the original source:
- Cached register values
These do not need to be read for every operation. Considerable increase in performance.
- Asynchronous writes
The HardwareSPI library can execute requests asynchronously, and this is used to provide some improvement in performance where no response is required from the display controller.
The next stage of development would be to build a generic graphics library to support multiple display controllers. Like the EVE controllers, it would incorporate a graphics instruction pipeline so that the application can buffer drawing requests in a fully asynchronous manner, eliminating any bottlenecks or wait states in the application.
References¶
Source Code (submodule, may be patched).
HardwareSPI Component
Used by¶
Screen TFT_S1D13781 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¶
Source Code (submodule, may be patched).
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¶
Source Code (submodule, may be patched).
Used by¶
RingTone Player Sample
Basic Audio Sample
UPnP Schema¶
This is a separate library for UPnP schema. It contains standard and reusable schema.
Code and header files are generated directly from schema to simplify the task of implementing hosted UPnP devices and controlling them.
You can find these under
Sming/out/{SMING_ARCH}/{debug|release}/build/UPnP-Schema/src
.
Controlling UPnP devices¶
Devices and services must be registered with the UPnP framework so that the correct objects can be constructed during discovery. This information is generated in groups, with one group for each domain. This means you only need to include one file in your project. For example:
#include <Network/UPnP/schemas-sming-org/ClassGroup.h>
void initUPnP()
{
UPnP::schemas_upnp_org::registerClasses();
}
This tells UPnP about all the standard devices and services.
Custom schema¶
Custom schema may be imported from the application or another Component.
Create a schema
sub-directory and arrange as:
schema/
{domain}/
device/
...
service/
...
Suitable schema are generated by the UPnP scan tool. These may be edited and customised with additional detail, comments, etc. as required.
References¶
Source Code (submodule, may be patched).
UPnP Component
Used by¶
Hue Emulator Library
Basic ControlPoint Sample
Basic UPnP Sample
Environment Variables¶
UPNP_SCHEMA
UPnP¶
Introduction¶
A C++ library for managing UPnP devices and services using the Sming framework.
If you’re not famililar with the mechanics of UPnP See UPnP for some background information.
Schema¶
A separate UPnP Schema is used to manage UPnP device and service schema. It generates C++ classes and sample code directly from these, which you can then use in your application.
Generation of suitable schema can be done using the scanner tool.
Controlling devices¶
The Basic_ControlPoint sample shows how this is done.
- Registration
To control UPnP-enabled devices on your local network they must first be located.
In order for this to happen, the framework must be able to match the C++ class implementation against the schema. You must therefore register all devices and services that you wish to control by calling
UPnP::ControlPoint::registerClasses()
.This method takes a
UPnP::ClassGroup
which typically defines all devices and services belonging to a specific domain. See UPnP Schema for further details about the available schema.Here’s an example from the ControlPoint sample:
#include <Network/UPnP/schemas-upnp-org/ClassGroup.h> // Let's make things a little easier for ourselves using namespace UPnP::schemas_upnp_org::device; using namespace UPnP::schemas_upnp_org::service; void initUPnP() { UPnP::schemas_upnp_org::registerClasses(); }
Discovery
This is done using a
UPnP::ControlPoint::beginSearch()
method, which takes two parameters: the first identifies what you are looking for, the second is a callback which gets invoked when a match has been found. You’ll typically implement this callback using a lambda function.For example, let’s find all
MediaRenderer1
devices:// Only one active search is permitted so be sure to cancel any existing ones first controlPoint.cancelSearch(); controlPoint.beginSearch(Delegate<bool(MediaRenderer1&)>([](auto& device) { // We can now do stuff with the located device // Return true to keep the device, false to destroy it return false; });This method takes a template parameter which is the C++ class type defining the device you are searching for. The framework will fetch the description for each corresponding device and construct a
DeviceControl
object with appropriate services and embedded devices.
- Control
Your search callback function gets a reference to a located device. These devices are created on the heap and owned by the
UPnP::ControlPoint
. If you want to keep the device, you should take a reference to it and returntrue
from the callback.To actually do anything useful typically requires use of a
UPnP::ServiceControl
object. You’ll usually get this by callingUPnP::DeviceControl::getService
or one of the generated helper methods. Note that this returns a pointer, which will benullptr
if the service isn’t available:auto render = device.getRenderingControl(); if(render != nullptr) { // ... }
Once you have a Service object, you can control it using action methods:
render->getVolume(0, RenderingControl1::Channel::fs_Master, [&device](auto response) { // Process response here });
Action methods take a list of zero or more input parameters, with the final argument for the response.
Note
The exact type of the response can be determined for you by the compiler. Here’s the explicit call:
render->getVolume(0, RenderingControl1::Channel::fs_Master, [&device](RenderingControl1::GetVolume::Response response response) {
// ...
});
OK, so handling the action method response. You can get the result values using methods of response
,
but you must first check that the device did not return a fault:
Serial.println();
Serial.println(_F("render->getVolume(0, Master):"));
// Sample uses a `checkResponse` helper function
if(auto fault = response.fault()) {
fault.printTo(Serial);
} else {
Serial.print(device.friendlyName());
Serial.print(_F(": Current Volume = "));
Serial.println(response.getCurrentVolume());
}
Serial.println();
Implementing devices¶
The Basic_UPnP sample contains a couple of examples of how to create your own hosted devices.
The TeaPot
device is the simplest possible implementation, with no services.
The Wemo
device is more elaborate and has two services.
Both of these are constructed using code generated from custom schema.
These are located in the project’s schema
directory which is picked up automatically
when the UPnP Schema library is built.
The framework generates a class template for each device and service.
For example, take a look in Wemo.h
:
class BasicEventService : public service::basicevent1Template<BasicEventService>
{
public:
// Need access to constructors
using basicevent1Template::basicevent1Template;
// Override methods if you need to customise any fields
String getField(Field desc) const override
{
switch(desc) {
case Field::serviceId:
// You could also put this in the schema
return F("urn:Belkin:serviceId:basicevent1");
default:
return basicevent1Template::getField(desc);
}
}
// Access to our device implementation
Controllee& controllee()
{
return reinterpret_cast<Controllee&>(device());
}
/* Here are the action methods */
Error getBinaryState(GetBinaryState::Response response)
{
response.setBinaryState(controllee().getState());
return Error::Success;
}
Error setBinaryState(bool state, SetBinaryState::Response response)
{
controllee().setState(state);
return Error::Success;
}
};
This perhaps slightly strange construction uses CRTP to use static polymorphism and avoid virtual method tables. This allows the compiler to generate more efficient code.
UPnP Tools¶
Windows:
Linux:
Under Ubuntu Linux you can install gupnp-tools:
sudo apt install gupnp-toolsAnd then discover devices on the local network using the following command:
gupnp-universal-cp
References¶
Source Code (submodule, may be patched).
RapidXML Component
SSDP Component
Used by¶
DIscovery And Launch (DIAL) Library
Hue Emulator Library
UPnP Schema Library
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
VT100 Emulator¶
This is a vt100 emulator written for devices with under 4kb of ram (for example the ATMega microcontroller). The emulator also uses ili9340 display by default, but can be compiled to use another display with only a few changes to the source code.
Note that because of the small size of the available memory and the slow speed of the microcontroller, it is a little tricky to implement all the escape sequences that are supported in vt100.

Examples¶
see demo.cpp for code that tests the terminal
Note: since vt100 is 80x24 lines, and our terminal only supports 40x40 lines, you need to run “stty cols 40 rows 40” command to tell terminal programs that only 40 columns are available.
Compiling¶
Don’t be put off by cmake. The CMakeLists.txt file is provided for convenience only. You can basically just compile using:
avr-gcc -O3 -std=c99 -mmcu=atmega328p -DF_CPU=16000000UL -c ili9340.c uart.c vt100.c
avr-g++ -O3 -std=c++11 -mmcu=atmega328p -DF_CPU=16000000UL -o demo.elf demo.cpp ili9340.o uart.o vt100.o
Compatibility¶
The aim of this project is to be a vt100 compliant terminal. However, at the moment it can not really be called a vt100 terminal because it is far from complete in terms of supporting all of the vt100 terminal sequences. But I do support a few and doing normal shell stuff works fine. But some functions require some more hacking to implement with only 2kb of ram (such as cursor blink and character deletion, to name a few).
Nonetheless, I’m proud to have come this far with it.
The driver currently supports the following escape sequences:
/======================================================\
| VT100 Escape sequences supported by the this driver |
\======================================================/
- ESC is the escape character "\e" or "\x1b"
- (yes) - the driver supports the sequence
- (no) - the driver currently does not support the sequence
- (?) - do we really need this function? Or: what does this do exactly?
VT52 Compatable Mode
--------------------
- (yes) ESC A Cursor up with scroll
- (yes) ESC B Cursor down with scroll
- (yes) ESC C Cursor right
- (yes) ESC D Cursor left
- (?) ESC F Special graphics character set
- (?) ESC G Select ASCII character set
- (yes) ESC H Cursor to home (but margins currently not supported!)
- (?) ESC I Reverse line feed
- (yes) ESC J Erase to end of screen
- (yes) ESC K Erase to end of line
- (no) ESC Ylc Direct cursor address (See note 1)
- (no) ESC Z Identify (See note 2)
- (?) ESC = Enter alternate keypad mode
- (?) ESC > Exit alternate keypad mode
- (?) ESC 1 Graphics processor on (See note 3)
- (?) ESC 2 Graphics processor off (See note 3)
- (?) ESC < Enter ANSI mode
ANSI Compatable Mode
--------------------
- (yes) ESC [ Pn A Cursor up Pn lines (without scroll)
- (yes) ESC [ Pn B Cursor down Pn lines
- (yes) ESC [ Pn C Cursor forward Pn characters (right)
- (yes) ESC [ Pn D Cursor backward Pn characters (left)
- (yes) ESC [ Pl;PcH Direct cursor addressing, where Pl is line#, Pc is column#
- NOTE: proper action is to move relative to margins. We don't support margins yet so the moves are absolute screen based character coordinates.
- (yes) ESC [ Pl;Pcf Same as above
- (yes) ESC D Index - moves cursor one line down and performs scroll if at bottom
- (yes) ESC M Reverse index - moves cursor up (with eventual scroll)
- (yes) ESC 7 Save cursor and attributes
- (yes) ESC 8 Restore cursor and attributes
- (?) ESC #3 Change this line to double-height top half
- (?) ESC #4 Change this line to double-height bottom half
- (?) ESC #5 Change this line to single-width single-height
- (?) ESC #6 Change this line to double-width single-height
- (yes) ESC [ Ps..Ps m
Ps refers to selective parameter. Multiple parameters are
Text attributes
0 All attributes off
1 Bold on
4 Underscore (on monochrome display adapter only)
5 Blink on
7 Reverse video on
8 Concealed on
Foreground colors
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White
Background colors
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White
- (yes) ESC [ K Erase from cursor to end of line
- (yes) ESC [ 0K Same
- (yes) ESC [ 1K Erase from beginning of line to cursor
- (yes) ESC [ 2K Erase line containing cursor
- (yes) ESC [ J Erase from cursor to end of screen
- (yes) ESC [ 0J Same
- (yes) ESC [ 2J Erase entire screen
- (?) ESC [ Ps..Ps q Programmable LEDs: Ps are selective parameters separated by
semicolons (073 octal) and executed in order, as follows:
0 or None All LEDs off
1 L1 On
2 L2 On
3 L3 On
4 L4 On
G0 designator G1 designator Character set
- (?) ESC ( A ESC ) A United Kingdom (UK)
- (?) ESC ( B ESC ) B United States (USASCII)
- (?) ESC ( 0 ESC ) 0 Special graphics/line drawing set
- (?) ESC ( 1 ESC ) 1 Alternative character ROM
- (?) ESC ( 2 ESC ) 2 Alternative graphic ROM
- (?) ESC K Pt;Pb r Set top scrolling window (Pt) and bottom scrolling window
(Pb). Pb must be greater than Pb.
- (no) ESC H Set tab at current column
- (no) ESC [ g Clear tab at current column
- (no) ESC [ 0g Same
- (no) ESC [ 3g Clear all tabs
Modes
-----
The following commands are currently not supported.
Mode Name Mode To set seq Mode To reset seq
- (no) Line feed/new New line ESC [20h Line feed ESC [20l
- (no) Cursor key Application ESC [?1h Cursor ESC [?1l
- (no) ANSI/VT52 ANSI n/a VT52 ESC [?2l
- (no) Column mode 132 col ESC [?3h 80 col ESC [?3l
- (no) Scrolling Smooth ESC [?4h Jump ESC [?4l
- (no) Screen mode Reverse ESC [?5h Normal ESC [?5l
- (yes) Origin mode Relative ESC [?6h Absolute ESC [?6l
- (yes) Wraparound On ESC [?7h Off ESC [?7l
- (?) Autorepeat On ESC [?8h Off ESC [?8l
- (?) Interface On ESC [?9h Off ESC [?9l
Reports
-------
- (no) ESC [ 6n Cursor position report
- (no) ESC [ Pl;PcR (response; Pl=line#; Pc=column#)
- (no) ESC [ 5n Status report
- (no) ESC [ c (response; terminal Ok)
- (no) ESC [ 0c (response; teminal not Ok)
- (no) ESC [ c What are you?
- (no) ESC [ 0c Same
- (no) ESC [?1;Ps c response; where Ps is option present:
0 Base VT100, no options
1 Preprocessor option (STP)
2 Advanced video option (AVO)
3 AVO and STP
4 Graphics processor option (GO)
5 GO and STP
6 GO and AVO
7 GO, STP, and AVO
- (no) ESC c Causes power-up reset routine to be executed
- (no) ESC #8 Fill screen with "E"
- (no) ESC [ 2;Ps y Invoke Test(s), where Ps is a decimal computed by adding the
numbers of the desired tests to be executed:
1 Power up test
2 Data loop back
4 EIA modem control signal test
8 Repeat test(s) indefinitely
TERMINAL COMMANDS
----------------
- (yes) ESC c Reset
- (no) [ ! p Soft Reset
- (yes) # 8 Fill Screen with E's
- (no) } 1 * Fill screen with * test
- (no) } 2 Video attribute test display
- (no) } 3 Character sets display test
KEYBOARD COMMANDS
-----------------
- (?) [ 2 h Keyboard locked
- (?) [ 2 l Keyboard unlocked
- (?) [ ? 8 h Autorepeat ON
- (?) [ ? 8 l Autorepeat OFF
- (?) [ 0 q Lights all off on keyboard
- (?) [ * q Light * on
PROGRAMMABLE KEY COMMANDS
-------------------------
- (?) ! pk Program a programmable key (local)
- (?) @ pk Program a programmable key (on-line)
- (?) % pk Transmit programmable key contents
SCREEN FORMAT (not supported)
-------------
- (?) [ ? 3h 132 Characters on
- (?) [ ? 3l 80 Characters on
- (?) [ ? 4h Smooth Scroll on
- (?) [ ? 4l Jump Scroll on
- (?) [ *t ; *b r Scrolling region selected, line *t to *b
- (?) [ ? 5 h Inverse video on
- (?) [ ? 5 l Normal video off
- (?) [ ? 7 h Wraparound ON
- (?) [ ? 7 l Wraparound OFF
- (?) [ ? 75 h Screen display ON
- (?) [ ? 75 l Screen display OFF
CHARACTER SETS AND LABELS
-------------------------
- (?) ( A British
- (?) ( B North American ASCII set
- (?) ( C Finnish
- (?) ( E Danish or Norwegian
- (?) ( H Swedish
- (?) ( K German
- (?) ( Q French Canadian
- (?) ( R Flemish or French/Belgian
- (?) ( Y Italian
- (?) ( Z Spanish
- (?) ( 0 Line Drawing
- (?) ( 1 Alternative Character
- (?) ( 2 Alternative Line drawing
- (?) ( 4 Dutch
- (?) ( 5 Finnish
- (?) ( 6 Danish or Norwegian
- (?) ( 7 Swedish
- (?) ( = Swiss (French or German)
[Note all ( may be replaced with )]
ATTRIBUTES AND FIELDS
-------
- (?) [ 0 m Clear all character attributes
- (?) [ 1 m Alternate Intensity ON
- (?) [ 4 m Underline ON
- (?) [ 5 m Blink ON
- (?) [ 7 m Inverse video ON
- (?) [ 22 m Alternate Intensity OFF
- (?) [ 24 m Underline OFF
- (?) [ 25 m Blink OFF
- (?) [ 27 m Inverse Video OFF
- (?) [ 0 } Protected fields OFF
- (?) [ 1 } Protected = Alternate Intensity
- (?) [ 4 } Protected = Underline
- (?) [ 5 } Protected = Blinking
- (?) [ 7 } Protected = Inverse
- (?) [ 254 } Protected = All attributes OFF
CURSOR COMMANDS
-------
- (?) [ ? 25 l Cursor OFF
- (?) [ ? 25 h Cursor ON
- (?) [ ? 50 l Cursor OFF
- (?) [ ? 50 h Cursor ON
- (yes) 7 Save cursor position and character attributes
- (yes) 8 Restore cursor position and character attributes
- (yes) D Line feed
- (yes) E Carriage return and line feed
- (yes) M Reverse Line feed
- (yes) [ A Cursor up one line
- (yes) [ B Cursor down one line
- (yes) [ C Cursor right one column
- (yes) [ D Cursor left one column
- (yes) [ * A Cursor up * lines
- (yes) [ * B Cursor down * lines
- (yes) [ * C Cursor right * columns
- (yes) [ * D Cursor left * columns
- (yes) [ H Cursor home
- (yes) [ *l ; *c H Move cursor to line *l, column *c
- (yes) [ *l ; *c f Move curosr to line *l, column *c
- (no) Y nl nc Direct cursor addressing (line/column number)
- (no) H Tab set at present cursor position
- (no) [ 0 g Clear tab at present cursor position
- (no) [ 3 g Clear all tabs
EDIT COMMANDS
-------
- (no) [ 4 h Insert mode selected
- (no) [ 4 l Replacement mode selected
- (no) [ ? 14 h Immediate operation of ENTER key
- (no) [ ? 14 l Deferred operation of ENTER key
- (no) [ ? 16 h Edit selection immediate
- (no) [ ? 16 l Edit selection deffered
- (no) [ P Delete character from cursor position
- (no) [ * P Delete * chars from curosr right
- (no) [ M Delete 1 char from cursor position
- (no) [ * M Delete * lines from cursor line down
- (yes) [ J Erase screen from cursor to end
- (yes) [ 1 J Erase beginning of screen to cursor
- (yes) [ 2 J Erase entire screen but do not move cursor
- (yes) [ K Erase line from cursor to end
- (yes) [ 1 K Erase from beginning of line to cursor
- (yes) [ 2 K Erase entire line but do not move cursor
- (no) [ L Insert 1 line from cursor position
- (no) [ * L Insert * lines from cursor position
LICENSE
-------
- Multilicense: GNU GPL free for all, by default.
For anything else, drop me an email. :)
.............................................................................
: INTERNET: info@fortmax.se :: Tel: 0733-387694 Int: +46-733-387694 :
: AUTHOR: Martin K. Schröder COPYRIGHT: 2014 SWEDEN :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
References¶
Source Code (submodule, may be patched).
Used by¶
Screen TFT_S1D13781 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¶
ArduinoJson Version 6 Component
Used by¶
Yeelight LED bulbs Sample
Flatbuffers¶
FlatBuffers is an efficient cross platform serialization library for C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, Rust and Swift. It was originally created at Google for game development and other performance-critical applications.
It is available as Open Source on GitHub under the Apache license, v2 (see LICENSE.txt).
Using¶
Step 1. Add these lines to your application componenent.mk file:
COMPONENT_DEPENDS += flatbuffers
Step 2. Add these lines to your application:
#include <flatbuffers/flatbuffers>
Or directly use the header file generated from the flatc compiler.
Step 3. Basic example:
#include "monster.h"
using namespace MyGame::Example;
void init()
{
Serial.begin(SERIAL_BAUD_RATE);
// demonstration how to encode data into a flatbuffer
flatbuffers::FlatBufferBuilder builder;
auto name = builder.CreateString("Sming Monster");
MonsterBuilder monster_builder(builder);
monster_builder.add_name(name);
auto orc = monster_builder.Finish();
// Call `Finish()` to instruct the builder that this monster is complete.
// Note: Regardless of how you created the `orc`, you still need to call
// `Finish()` on the `FlatBufferBuilder`.
builder.Finish(orc);
// and then decode it
uint8_t *buffer = builder.GetBufferPointer();
auto monster = GetMonster(buffer);
Serial.printf("Monster name: %s\n", monster->name()->c_str());
}
Further reading¶
Take a look at the official flatbuffers tutorial.
References¶
Used by¶
Basic FlatBuffers Sample Sample
Submodule: src¶
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¶
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 :)
Nano Protocol-Buffer¶
Introduction¶
This component adds support for Nano Protocol-Buffer implementation.
Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is especially suitable for use in microcontrollers, but fits any memory restricted system.
C file generation from Proto files¶
Once this component is installed you can use it to add Nano Protocol-Buffer support to your project and generate C and header files from Proto files. One possible way to call the generator is to go to the directory where the proto file is located and run the generator. As shown below:
make -C $SMING_HOME fetch nano-pb
cd <folder-with-proto-file>
python $SMING_HOME/Libraries/nanopb/nanopb/generator/nanopb_generator.py <desired-proto-file>.proto
After the generator tool is run you will have newly generated C and header files that can be used in your Sming application.
Using¶
Add
COMPONENT_DEPENDS += nanopb
to your application componenent.mk file.Add these lines to your application:
#include <PbUtils.h> // The line below should be replaced with the generated header file #include "cast_channel.pb.h"
Example:
#include <PbUtils.h> #include "cast_channel.pb.h" void doSomething(const uint8_t* data, size_t length) { // ... extensions_api_cast_channel_CastMessage message = extensions_api_cast_channel_CastMessage_init_default; message.protocol_version = extensions_api_cast_channel_CastMessage_ProtocolVersion_CASTV2_1_0; message.source_id.funcs.encode = &pbEncodeData; message.source_id.arg = new PbData(sourceId); message.destination_id.funcs.encode = &pbEncodeData; message.destination_id.arg = new PbData(destinationId); message.nameSpace.funcs.encode = &pbEncodeData; message.nameSpace.arg = new PbData(ns); message.payload_type = extensions_api_cast_channel_CastMessage_PayloadType_STRING; message.payload_utf8.funcs.encode = &pbEncodeData; message.payload_utf8.arg = new PbData((uint8_t*)data, length); // ... }
References¶
Used by¶
GoogleCast Library
Submodule: nanopb¶
Nanopb - Protocol Buffers for Embedded Systems¶
Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is especially suitable for use in microcontrollers, but fits any memory restricted system.
Homepage: https://jpa.kapsi.fi/nanopb/
Documentation: https://jpa.kapsi.fi/nanopb/docs/
Downloads: https://jpa.kapsi.fi/nanopb/download/
Nightly builds: https://jpa.kapsi.fi/jenkins/job/nanopb/
To use the nanopb library, you need to do two things:
Compile your .proto files for nanopb, using
protoc
.Include pb_encode.c, pb_decode.c and pb_common.c in your project.
The easiest way to get started is to study the project in “examples/simple”. It contains a Makefile, which should work directly under most Linux systems. However, for any other kind of build system, see the manual steps in README.txt in that folder.
Protocol Buffers messages are defined in a .proto
file, which follows a standard
format that is compatible with all Protocol Buffers libraries. To use it with nanopb,
you need to generate .pb.c
and .pb.h
files from it:
python generator/nanopb_generator.py myprotocol.proto # For source checkout
generator-bin/nanopb_generator myprotocol.proto # For binary package
(Note: For instructions for nanopb-0.3.9.x and older, see the documentation of that particular version here)
The binary packages for Windows, Linux and Mac OS X should contain all necessary
dependencies, including Python, python-protobuf library and protoc. If you are
using a git checkout or a plain source distribution, you will need to install
Python separately. Once you have Python, you can install the other dependencies
with pip install protobuf grpcio-tools
.
You can further customize the header generation by creating an .options
file.
See documentation for details.
If you want to perform further development of the nanopb core, or to verify
its functionality using your compiler and platform, you’ll want to run the
test suite. The build rules for the test suite are implemented using Scons,
so you need to have that installed (ex: sudo apt install scons
or pip install scons
).
To run the tests:
cd tests
scons
This will show the progress of various test cases. If the output does not end in an error, the test cases were successful.
Note: Mac OS X by default aliases ‘clang’ as ‘gcc’, while not actually
supporting the same command line options as gcc does. To run tests on
Mac OS X, use: scons CC=clang CXX=clang
. Same way can be used to run
tests with different compilers on any platform.
For embedded platforms, there is currently support for running the tests
on STM32 discovery board and simavr
AVR simulator. Use scons PLATFORM=STM32
and scons PLATFORM=AVR
to run
these tests.
Nanopb C code itself is designed to be portable and easy to build
on any platform. Often the bigger hurdle is running the generator which
takes in the .proto
files and outputs .pb.c
definitions.
There exist build rules for several systems:
Makefiles:
extra/nanopb.mk
, seeexamples/simple
CMake:
extra/FindNanopb.cmake
, seeexamples/cmake
SCons:
tests/site_scons
(generator only)Bazel:
BUILD
in source rootConan:
conanfile.py
in source rootPlatformIO: https://platformio.org/lib/show/431/Nanopb
PyPI/pip: https://pypi.org/project/nanopb/
And also integration to platform interfaces:
You can download and install nanopb using the vcpkg dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install nanopb
The nanopb port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.
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
References¶
Used by¶
HostEd ,Component
Submodule: simpleRPC¶
Simple RPC implementation for Arduino.¶
This library provides a simple way to export Arduino functions as remote procedure calls. The exported method definitions are communicated to the host, which is then able to generate an API interface.
Features:
For each method, only one line of code is needed for exporting.
Automatic parameter- and return type inference.
Support for all native C types and strings.
Support for arbitrary functions and class methods.
Optional function and parameter naming and documentation.
Support for PROGMEM’s
F()
macro to reduce memory footprint.Support for compound data structures like Tuples, Objects (Tuples with internal structure), Vectors and arbitrary combinations of these.
Support for reading multidimensional C arrays (e.g.,
int**
).Support for different types of I/O interfaces via plugins, e.g.,
Bluetooth.
Ethernet (untested).
Hardware serial.
RS485 serial.
Software serial (untested).
USB serial.
WiFi.
Wire (untested).
Support for using multiple interfaces at the same time.
The Arduino library is independent of any host implementation, a Python API client library is provided as a reference implementation.
Please see ReadTheDocs for the latest documentation.
Quick start¶
Export any function e.g., digitalRead()
and digitalWrite()
using the
interface()
function.
#include <simpleRPC.h>
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
interface(Serial, digitalRead, "", digitalWrite, "");
}
These functions are now available on the host under names method0()
and
method1()
.
The documentation string can be used to name and describe the method.
interface(
Serial,
digitalRead,
"digital_read: Read digital pin. @pin: Pin number. @return: Pin value.",
digitalWrite,
"digital_write: Write to a digital pin. @pin: Pin number. @value: Pin value.");
This is reflected on the host, where the methods are now named
digital_read()
and digital_write()
and where the provided API
documentation is also available. In the client reference implementation
documentation, contains an example on how this works.
Further reading¶
Please read usage for more information about exporting normal functions, class member functions and documentation conventions.
If you want to create your own host library implementation for other programming languages, the section protocol should help you on your way.
API Documentation¶
This is a separate section built using DOXYGEN, which will replace this file when built.
Information¶
Developing for Sming¶
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.
Install other required packages:
pip3 install -r requirements.txt
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
Component Building Guide¶
Introduction¶
This section will take you through creating a Sming Component from start to finish, based on a real example from Pull Request #1992.
The aim here is to make an existing library, https://github.com/nomis/ModbusMaster, available for applications to use within the framework.
Various options and settings are only mentioned here, but are linked through to Sming build system where you can find full details of what they are and how they work.
You will need to be familiar with GIT and the use of submodules.
Structure¶
You should carefully consider how to incorporate third-party code. The choices are:
Add an existing third-party library directly as a Component, patching if required;
Add the a submodule as a sub-directory within a Component;
Copy code from an existing library (honouring any license agreement conditions) and modify/rewrite as necessary;
Start from scratch. If drawing on ideas from other implementations those should be attributed.
We could use (a), but that is appropriate only for very simple libraries, or those written for Sming but stored in an external repository (e.g. FlashString). You can find more details on this process in Adding External Sources.
Note
Bear in mind that the asynchronous architecture of Sming can be at odds with code written for Arduino.
In this example, the main ModbusMasterTransaction
code incorporates a loop which
effectively halts program execution until a timeout occurs or a response is received.
Fixing that could require extensive patching, so option (c) or (d) may be more appropriate.
For now we are using option (b), so we’ll start by creating the Component directory:
cd $SMING_HOME/Libraries
mkdir ModbusMaster
cd ModbusMaster
Note
Do not use $SMING_HOME/Components
. This is reserved for framework libraries.
Now add the submodule:
git submodule add --name Libraries.ModbusMaster https://github.com/nomis/ModbusMaster
This does three things:
Clones the external repository to the
ModbusMaster
sub-directory;Adds an entry to the
.gitmodules
file with the URL, local path and specified name;Stages both changes, with a link indicating which commit should be used.
Note
The dotted name format is a Sming convention.
Before committing, we need to edit the .gitmodules
file. Open in a text editor and
follow the instructions therein.
You should now re-stage and commit the changes before proceeding.
Patching¶
Where minor changes are required to third-party code then these can be applied automatically as patches. See Adding External Sources and GIT Submodules for details.
For ModbusMaster, we want to make a slight change to how the timeout is configured,
so this is provided in a file called ModbusMaster.patch
.
Supported architectures¶
Unless there are specific reasons not to do so, Components should work on all supported architectures. In particular, it should build and run under the Host Emulator.
In order to do this, you should remove any low-level code from the library by:
Using Sming support classes or drivers (see Esp8266 Drivers); or
Placing low-level code into separate code modules or header files.
If a Component is intended only to work with specific hardware then ensure appropriate checks are incorporated so that building fails gracefully on un-supported architectures. You can do this in the component.mk file:
ifneq ($(SMING_ARCH),Esp8266)
$(error MyComponent currently only supports the ESP8266 architecture)
endif
Component configuration¶
For very simple Components the default settings are adequate:
Source code must be in the base directory or a sub-directory called
src
Public header files must be in a sub-directory called
include
The source files will be compiled into a library, in this case clib-ModbusMaster.a
.
To change the defaults, provide a component.mk
file and set entries as required:
- Submodules
We need to tell Sming about the submodules:
COMPONENT_SUBMODULES := ModbusMaster
- Source code
Put the source code into a separate directory (or directories) and add those to
COMPONENT_SRCDIRS
.You can also use
COMPONENT_SRCFILES
.For ModbusMaster, all the source code is in the submodule so we set this to
COMPONENT_SRCDIRS := ModbusMaster/src
.- Header files
Keep public and private
.h
or.hpp
files in separate directories.Add the public ones to
COMPONENT_INCDIRS
.Any private headers can be set in
EXTRA_INCDIR
.For ModbusMaster, we set this to
COMPONENT_INCDIRS := ModbusMaster/src
- Configuration options
ModbusMaster provides the
MB_RESPONSE_TIMEOUT
variable.This is mapped onto a
#define
value with the same name usingCOMPONENT_CXXFLAGS
.Note: Don’t confuse this with
COMPONENT_CFLAGS
which is only used when building.c
source files.If the value changes we want Sming to rebuild both the library and any code which uses it, so we assign it to the
COMPONENT_VARS
variable list. Users can check the value by runningmake list-config
.- Dependencies
If your library depends on other libraries to build, these must be declared in the
component.mk
file by settingCOMPONENT_DEPENDS
variable.ModbusMaster doesn’t have any so this entry is not required.
Documentation¶
A Component MUST have a README.md
(markdown) or README.rst
(reStructuredText) file
with a level 1 heading and brief introduction at an absolute minimum.
Note
You may not be familiar with .rst
files but they are a considerably improvement on markdown
and well worth investing a little time to learn.
See Contributing for further 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 in
Sming/Components
. Otherwise, use the appropriateSming/Arch/*/Components
directory.
Code for general use
Create a new Library in
Sming/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_HOME git submodule add \ --name ESP8266.new-pwm \ https://github.com/StefanBruens/ESP8266_new_pwm.git \ Arch/Esp8266/Components/driver/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.
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¶
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
-
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.
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 projectCopy 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.
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 emulatorType
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
.
The appropriate hardware configuration should be selected in the project’s component.mk file. Use one of the standard configurations or create your own. See Hardware configuration.
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
to flash the project andtest-rom
SPIFFS image using the provided flash memory settingsNext 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_RELEASE=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.
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.
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.
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
.
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.
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).
This value changes depending on the build variant.
-
COMPONENT_BUILD_BASE
¶ This value does not change with build variant.
If the Component generates source code, for example, it can be placed here (in a sub-directory).
-
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 IFS Library for an example.
-
COMPONENT_PREREQUISITES
¶ These targets will be built before anything else. If your library generates source code, for example, then it should be done by setting this value to the appropriate targets.
-
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_SRCFILES
¶ Individual source files. Useful for conditional includes.
-
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.
-
PIP_ARGS
¶
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.
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.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
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
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.
Clang Tools¶
clang-format is a tool that implements automatic source code formatting. It can be used to automatically enforce the layout rules for Sming.
clang-tidy is a C++ “linter” tool to assist with diagnosing and fixing typical programming errors such as style violations, interface misuse, or bugs that can be deduced via static analysis. It is provided as part of
You can find details for the current release at https://releases.llvm.org/download.html. Note that clang-format is part of the main Clang project, whilst clang-tidy can be found in clang-tools-extra.
Installation¶
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.
Important
Different versions of clang-format can produce different results, despite using the same configuration file.
We are using version 8.0.1 of clang-format and clang-tidy on our Continuous Integration (CI) System.
You should install the same version on your development computer.
Configuration¶
The coding rules are described in the .clang-format file, located in the root directory of the framework.
You should not edit this file unless it is a discussed and agreed coding style change.
There are multiple existing integrations for IDEs. You can find details in the ClangFormat documentation.
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.
Usage¶
Single File
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.
All files
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 csThe 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 csfrom your project directory.
If you have installed CppStyle as described above you can configure Eclipse to auto-format your files on Save.
Alternatively, 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).
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 as described in this guide. The coding style rules are mandatory for most of the framework, and Pull Request that does not adhere to the coding style rules will not be merged until those rules are applied.
The rules are optional for libraries, but recommended.
Tools will help you adhere to these coding standards without the need to know them by heart. See Clang Tools for further details.
Please also bookmark the C++ Core Guidelines. This is an invaluable reference for writing good code and making the best use of this powerful language.
Indentation¶
We use tabs for indentation. Configure your editor to display a tab as long as 4 spaces. For reference, the corresponding settings in clang-format are:
TabWidth: 4
UseTab: Always
IndentWidth: 4
Naming¶
Classes, Structures, type aliases
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).
Examples:
class HttpClient {} class HttpClientConnection {} using LargeValue = uint32_t; struct MyStruct { ... }; enum MyEnum { a, ///< Comment if required b, c, };Note
The trailing , on the final item in an enumeration declaration will ensure that clang-format places each item on a separate line. This makes for easier reading and the addition of line comments if appropriate.
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.
Examples:
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.
Examples:
int i; char c; WebsocketClient* client;
Pre-processor definitions
#defined macros must be written in uppercase characters separated by underscores. Names may contain digits if appropriate, but not as the first character. For example:
#define MAX_PARTICIPANTS 10
Constants
Typically declared using
const
orconstexpr
and, like variables, should be lower-camelcase. Names MUST NOT be all-uppercase as these may be confused with #defined values.See C++ Core Guidelines.
Use of typedef
in C++¶
Use of typedef
in C++ code is not recommended.
The using keyword has been available since C++11 and offers a more natural way to express type definitions. It is also necessary in certain situations such as templating.
For example:
using ValueType = uint32_t;
is more readable than:
typedef uint32_t ValueType;
Especially in multiple type declarations the subject is always immediately after the using
keyword
and makes reading much easier.
enum/struct declarations¶
This:
typedef struct _MyStructTag {
...
} MyStruct;
typedef enum _MyEnumTag {
...
} MyEnum;
is overly verbose and un-necessary. It’s a hangover from ‘C’ code and should generally be avoided for readability and consistency. This is the preferred definition:
struct MyStruct {
...
};
enum MyEnum {
.............
};
It’s also un-necessary to qualify usage with enum. i.e. MyEnum e; is sufficient, don’t need enum MyEnum e;.
C++ Standard¶
For the moment we recommend the use of C++11. The corresponding settings in clang-format are:
Standard: Cpp11
Cpp11BracedListStyle: true
Starting and ending spaces¶
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.
Line length¶
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
Empty Lines¶
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
Braces¶
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
Pointer Alignment¶
Always on the left:
PointerAlignment: Left
Includes¶
We don’t re-sort includes although it is highly recommended to order the headers alphabetically whenever possible:
SortIncludes: false
Spaces¶
For readability put always spaces before assignment operators:
SpaceBeforeAssignmentOperators: true
Standard file headers¶
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.
Deprecating code¶
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.
Virtual Classes¶
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
Common issues¶
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
:members:
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 :library:`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/DateTime.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
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¶
Map¶
You can find a map for the ESP8266 memory layout in the Wiki.
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.
Sming version 4.3 introduced partition tables to support multiple architectures, different hardware variants and custom flash layouts without restriction.
See Hardware configuration for details.
A typical layout for a 4MByte device might look like this:
Address
Config variable
Size
Source filename
Description
(hex)
(if any)
(KB)
(if applicable)
000000
1
rboot.bin
Boot loader
001000
4
rBoot configuration
002000
4
Partition table
003000
4
esp_init_data_default.bin
PHY configuration data
004000
12
blank.bin
System parameter area
006000
4
blank.bin
RF Calibration data (Initialised to FFh)
006000
4
Reserved
008000
ROM_0_ADDR
rom0.bin
First ROM image
100000
RBOOT_SPIFFS_0
208000
ROM_1_ADDR
rom1.bin
Second ROM image
300000
RBOOT_SPIFFS_1
Note
This was the previous layout for 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 |
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
CString for efficient storage of C-style char* RAM strings
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 handlerDon’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.
The BasicTask class¶
This class uses the task queue plus a timer to provide an easy way to write a background task. All you need to is define a loop() function which does the work. The task has three states:

Task states¶
To see this in operation, have a look at the Basic Tasks sample.
Task Schedulers¶
If you want to read further about schedulers, there are various 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.
This can be done using next
:
(gdb) next
67 digitalWrite(LED_PIN, ledState);
The command to see a value is print
followed by the name of the
value. For example to see the value of the ledState
variable inside
the blink
function we could type:
(gdb) print ledState
$1 = true
You can see more useful commands here.
Or watch the following short video

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.
This can be done using next
:
(gdb) next
67 digitalWrite(LED_PIN, ledState);
The command to see a value is print
followed by the name of the
value. For example to see the value of the ledState
variable inside
the blink
function we could type:
(gdb) print ledState
$1 = true
You can see more useful commands here.
Or watch the following short video

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
nodeMCU Pin
USB Blaster
JTAG Signal
1
VCC
3V3
4
VCC
2
MTDO / GPIO15
D15
3
TDO
3
MTDI / GPIO12
D12
9
TDI
4
MTCK / GPIO13
D13
1
TCK
5
MTMS / GPIO14
D14
5
TMS
6
GND
GND
2
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 target/esp32.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:
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.
This can be done using next
:
(gdb) next
10 digitalWrite(LED_PIN, state);
The command to see a value is print
followed by the name of the
value. For example to see the value of the ledState
variable inside
the blink
function we could type:
(gdb) print state
$1 = true
You can see more useful commands here.
Or watch the following short video

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. You can accommodate this by setting the appropriate hardware configuration in your project’s component.mk file:
.. code-block:: make
HWCONFIG = two-rom-mode
See Sming/Arch/Esp8266/two-rom-mode.hw
for details.
You can copy this and customise it in your project.
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. This is the behaviour when you
set HWCONFIG = spiffs
in your project’s component.mk file.
If you have 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();
// Find the n'th SPIFFS partition
auto part = PartitionTable().find(Partition::SubType::Data::spiffs, slot);
if(part) {
//debugf("trying to mount SPIFFS at %x, length %d", part.address(), part.size());
spiffs_mount(part);
} else {
debug_e("SPIFFS partition missing for slot #%u", slot);
}
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.
For details, refer to the OtaUpdate() function in the Basic_rBoot sample.
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()
Tips and Tricks¶
Reading VCC on ESP8266¶
If you are running on a battery operated device then function system_get_vdd33() from the official ESP8266 NONOS SDK can help you read the power voltage. For the latter to work properly you should make a small change in your application component.mk file and add vdd to the HWCONFIG_OPTS configuration variable.
If you cannot see such a variable in your component.mk file then append the following line to it:
HWCONFIG := vdd
You can have multiple options selected. They should be separated by comma. For example the command below will add 4MB flash, spiffs and vdd support:
HWCONFIG := 4m,spiffs,vdd
You can check the final hardware configuration using the command below:
make hwconfig
If a custom hardware configuration is needed then read Storage Management.
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.3 to v4.4¶
4.3.1¶
Network support¶
The core network code has been moved out of Sming/Core/Network
and into a separate component at Components/Network
.
This is to extend the use of the DISABLE_WIFI
setting to reduce the code required to be built for applications which
do not require networking.
Some support code has been moved into Core/Data/WebHelpers
: applications should still build OK but you will get
a compiler warning advising of the changes.
Note that Network/WebHelpers/aw-sha1.h
has been removed in favour of the Cryptographic Support library.
From v4.2 to v4.3¶
Storage Management¶
The layout of flash memory has been revised and is now managed via partition table. Hardware configuration is stored in a JSON file (with .hw extension).
If your project has minimal customisation then you may only need to change
the HWCONFIG
setting.
You can find full details in the Storage Management library. See also background on Flash memory.
- Removed build targets
- spiffs-image-update
Use the new
buildpart
target instead- spiffs-image-clean
Use the new
part-clean
target instead
- New and updated build targets
- hwconfig
Displays the current configuration in JSON format
- hwconfig-list
Show available hardware configs
- hwconfig-options
Show available hardware configuration options
- map
Display the current flash memory map
- readmap
Read partition table from device and display the map
- readpart
Read contents of partition into a file, e.g.
make readpart PART=spiffs0
will createout/Esp8266/debug/spiffs0.read.bin
- flash
Flash partition table and all partitions. Previously it was necessary to run
make flashinit
to write system parameter information. Failure to do this was a common problem and should now be a thing of the past.- flashinit
This now just erases the flash memory. The ESP8266 initialisation data gets written when running
make flash
.- flashmap
Flash just the partition map
- flashpart
Flash a single partition, e.g.
make flashpart PART=spiffs0
- erasepart
Erase a partition, e.g.
make erasepart PART=spiffs0
- buildpart
Re-builds images associated with partitions, such as SPIFFS or other filesystem images.
- part-clean
Removes any partition images with build information. This is done as part of a normal project clean.
- Configuration variables
A number of configuration variables have been removed or made read-only, as these are now generated from the Hardware configuration.
SPI_MODE
,SPI_SIZE
,SPI_SPEED
The variables are still used internally but are read-only; they cannot be set at the command line. Values are read from the hardware configuration under
/devices/spiFlash
.RBOOT_ROM0_ADDR
,RBOOT_ROM1_ADDR
,RBOOT_ROM2_ADDR
Used by rBoot, and are now read-only. Values are read from the
address
property ofrom0-2
in the hardware configuration.RBOOT_SPIFFS_0
,RBOOT_SPIFFS_1
Removed.
SPIFF_SIZE
Removed. Attempting to set this automatically within a hardware configuration is liable to cause more problems than it solves, so updating the hardware config is the now only way to change this setting.
SPIFF_FILES
[deprecated]
You can still use this to specify the source location for the primary SPIFFS partition (spiffs0). The preferred method is to set the
files
property in a partitionbuild
key.The default SPIFFS partition settings can be overridden in a custom profile. For example:
{ ... "base_config": "spiffs", "partitions": { "spiffs0": { "size": "128K", "build": { "files": "some/other/folder" } } } }
Installable File System (IFS)¶
Sming now supports multiple filesystems via Installable File System.
See Basic IFS for a demonstration.
Core/FileSystem.h has been modified to use IFS but the API remains largely unchanged, although somewhat expanded. Functions are now mainly just wrappers around filing system calls.
A single global IFileSystem instance is used.
- SPIFFS
All access is now managed via the
IFS::SPIFFS::FileSystem
implementation.Applications should not use SPIFFS functions directly.
Important
SPIFFS is now built with
SPIFFS_OBJ_META_LEN=16
to store extended attribute information. Existing volumes built with other values will not be directly compatible; the file listing may be correct but file contents will not.To accommodate use of existing pre-built SPIFFS images,
SPIFFS_OBJ_META_LEN
has been added:make SPIFFS_OBJ_META_LEN=0
You will, however, lose the additional file information (such as modification time).
- File open flags
e.g. eFO_ReadOnly. These will still work but are now deprecated and should be replaced with their C++ equivalent such as
File::ReadOnly
.
From v4.1 to v4.2¶
Summary¶
Stream methods¶
The Stream::readBytes()
has been virtualised and overriden for IDataSourceStream
descendents for more efficient operation, especially with ArduinoJson.
For normal read operations where the stream position is to be updated, applications should use
this method in preference to IDataSourceStream::readMemoryBlock()
.
An addition method IDataSourceStream::moveString()
has been added to support extracting
the content of a memory-based stream into a String object without duplicating the data.
This is supported by LimitedMemoryStream
and MemoryDataStream
.
Stream / file seeking¶
To provide a consistent interface SeekOrigin
is now used with all seek methods for streams,
and also by file system functions. Mappings are:
SeekOrigin::Start instead of eSO_FileStart
SeekOrigin::Current instead of eSO_CurrentPos
SeekOrigin::End instead of eSO_FileEnd
These map to the standard C SEEK_SET, SEEK_CUR and SEEK_END but as SeekOrigin is strongly typed it offers compile-time checking, and has a toString(SeekOrigin) overload.
getBody methods¶
The HttpRequest::getBody()
and HttpResponse::getBody()
methods have been revised to use
move semantics. Previously, the data was copied into a new String which effectively doubled memory usage.
If you have set a non-memory stream type (e.g. FileStream
) which does not implement IDataSourceStream::moveString()
then an invalid String will be returned. In this situation you should use HttpResponse::getBodyStream()
instead.
ContentType / MIME types¶
toString(MimeType)()
has been moved out of the ContentType
namespace,
so no longer requires the ContentType::
qualifier.
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 |
---|---|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
flesh memory |
|
|
C compatible types |
|
|
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 };
struct MyHdr {
u8 prefix[PREFIX_SIZE];
u8 signature[SIGNATURE_SIZE];
};
//-----------------------------------------------------------------------------
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.
See Developing for Sming for details.
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¶
Details of Sming support for Integrated Development Environments (IDEs).
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
thereEdit
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¶
Microsoft Visual Studio Code is a free (as in “free beer”) and Open Source code editor for Windows, Linux and Mac.
For easier integration make sure you have both ESP_HOME
and
SMING_HOME
exported in your working environment.
Software involved¶
Installation¶
Install VS Code, extensions and tools
Navigate to project folder and create configuration as described below
Open workspace. If vscode is in your system path you can do this:
code .
Configuration¶
One of the strengths of vscode is the use of well-documented configuration files. You can find comprehensive documentation for these online.
However, setting these up is time-consuming so the build system can create them for you. The vscode workspace root directory is your project directory.
Change to your project directory (e.g. samples/Basic_Blink
) and run these commands:
make ide-vscode SMING_ARCH=Esp8266
make ide-vscode SMING_ARCH=Host
Now open the workspace in vscode, and open a source file (.c, .cpp, .h). You should now be able to select the architecture from the icon in the bottom-right corner:

VS Code language selection¶
A selection of tasks are provided which you can view via Terminal
-> Run Task
.
To debug your application, follow these steps:
Select the appropriate architecture (e.g. Host, Esp8266)
Select
Terminal
->Run Task
->Full rebuild (with debugging)
Confirm that the baud rate (
COM_SPEED_GDB
) and port (COM_PORT_GDB
) are set correctly:make gdb SMING_ARCH=Esp8266 COM_PORT_GDB=/dev/ttyUSB0 COM_SPEED_GDB=115200
Update the vscode configuration:
make ide-vscode
In vscode, select the require ‘Run’ task:

VS Code debug selection¶
Manual configuration changes¶
When you run make ide-vscode
the configuration files are actually generated using a python script
Tools/vscode/setup.py
. Configuration variables are passed from the project makefile.
If you make any changes to the configuration files, please note the following behaviour:
The
Host
,Esp32
orEsp8266
intellisense settings will be overwritten.The
Esp8266 GDB
andHost GDB
launch configurations will be overwrittenThe
sming.code-workspace
and.vscode/tasks.json
files will be created if they do not already exist. To re-create these they must first be deleted.
Ideally the vscode configuration files should not need to be kept under configuration control, but generated when required.
Some settings are necessarily configured via the setup.py
script, however most settings can
be changed by editing the files in Tools/vscode/template
.
If you do this, remember to keep a copy as they’ll be overwritten otherwise.
And, please consider contributing any changes or suggestions to the community!
Known issues / features¶
The vscode configuration files are only updated when you manually run
make ide-vscode
. If you update change critical build variables or add/remove Components to your project, you may need to run it again to update them.When running
make ide-vscode
, comments in the configuration files will be discarded.make ide-vscode
may overwrite parts of your configuration: be warned!When debugging for esp8266 output in the console is not formatted correctly. Lines appear with @ in front of them.
A debugging configuration is not currently provided for ESP32.
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:
Check the Hardware configuration especially
flash_size
setting.Run
flashinit
:cd $SMING_HOME/../samples/Basic_Blink make flashinit
This resets the flash memory to a default state, erasing any existing application, configuration or data stored there.
Re-program your device:
make flash
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¶
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.
The project was started in 2015 and is actively developed.
Arduino¶
Arduino is an open-source electronics platform based on easy-to-use hardware and software. Sming is compatible with (most) standard Arduino libraries, which means that you can use any popular hardware in few lines of code.
ESP8266¶
ESP8266 is a microcontroller with Wi-Fi, manufactured by Espressif Systems. It is the first microcontroller that was supported from Sming. Sming provides access to all ESP8266 functions such as GPIO, timers, WiFi configuration, etc.
ESP32¶
ESP32 is the second microcontroller by Espressif Systems. At the moment Sming provides partial support for ESP32 functions.
Licenses¶
- Sming Core
LGPL v3
- Espressif SDK
ESPRESSIF MIT License (with some closed-source blobs)
- Libraries
See each library for details of its own open source license
Comments¶
We try not to split comment lines into smaller ones and also we add one space between code and trailing comment: