A small library made to try libNIMA on, and a starting point for making your own library installable into an ESP-IDF project.
It does one useful thing. example_due() says yes once every CONFIG_EXAMPLE_PERIOD_MS milliseconds and never blocks, so a loop can blink an LED, read a sensor or print a line on a rhythm without sleeping. example_hello() prints CONFIG_EXAMPLE_GREETING. Both settings are Kconfig symbols, in idf.py menuconfig. Its uptime option adds example_uptime(), the time since start up in hours, minutes and seconds.
It also uses what libnima.yml gained in 2.0.0, 2.1.0 and 4.0.0, so you can see each of them work:
- A file made once. Its settings come in
example.defaults, made in your project's folder and yours from then on. No install writes over it. - Lines of CMake by place. Under
esp32.project.cmake, lines in yourCMakeLists.txt, aboveinclude(project.cmake), addexample.defaultstoSDKCONFIG_DEFAULTS. Underesp32.library.cmake, two put your project's folder on the library's include path. - A symbol it needs.
FREERTOS_HZ=1000, fromesp32.project.conf, goes into its block of yoursdkconfig.defaults, sovTaskDelay(1)in the loop below waits one millisecond, not ten. A line of yours there wins. - Titles and notes. Its lists are in groups under their titles, and the symbol has a note. Both land in the files as comments, so whoever opens
sdkconfig.defaultsor aCMakeLists.txtsees why each line is there. - A step it runs.
make-idmakesexample_id.h, this device's own ID, a random number. libNIMA shows what it runs and asks first. Its script,tools/make_id.py, comes into your project's folder as the library's own.
Get libNIMA once per machine from its releases page: the installer for Windows, macOS or Linux, which puts the libnima command on your PATH as well.
Then, from your project's folder, the one holding CMakeLists.txt and main/:
libnima nimaltd/libnima-example-esp32Press Enter at its questions, and the library goes into components/example/ as an ESP-IDF component, with a CMakeLists.txt and a Kconfig libNIMA writes for it. Your CMakeLists.txt gets the block that adds example.defaults, your sdkconfig.defaults the block with CONFIG_FREERTOS_HZ=1000, and example.defaults is made. When your main lists the components it uses, or your project builds only what main names, as ESP-IDF's examples do, example is added to main's list too. Last, it asks about its step:
Run
make-id Make this device's own ID, example_id.h
python tools/make_id.py example_id.h
Run it? [Y/n]:
Made example_id.h: device C6E43235.
done
Enter runs it, and example_id.h is in your project's folder, with a number of its own.
Then use it in main/main.c:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "example.h"
void app_main(void)
{
example_t tick;
example_init(&tick);
while (1)
{
if (example_due(&tick))
{
example_hello(&tick);
}
vTaskDelay(1);
}
}Build it, flash it and watch it as always:
idf.py build flash monitorHello from example 1, device C6E43235
Hello from example 2, device C6E43235
Hello from example 3, device C6E43235
Change a setting. The settings are Kconfig symbols. Set them in idf.py menuconfig, under example, and build again. Or set them in example.defaults, the file the install made, which ESP-IDF reads after sdkconfig.defaults when it makes a fresh sdkconfig:
CONFIG_EXAMPLE_PERIOD_MS=100
CONFIG_EXAMPLE_GREETING="Hi"
Run the install command again, and your settings are still there: the output says kept example.defaults yours, and libNIMA never touches sdkconfig.
Its device ID. Run the install again, and the step is not asked about: make-id skipped, example_id.h is already there, so the ID never changes under you. Delete example_id.h, and the next install asks again and makes a new one. Answer for it on the command line instead, with --run make-id to run it or --no-run make-id to leave it, and --yes takes every answer offered, for a script. Nobody to answer, and it is not run; then example_id() is 0.
Look at what it wrote. The lines of each place sit between two lines naming it, so you can find them, and the next install writes them again. Each group has its title above it, between two lines of stars:
# >>> libnima: example/before-project >>>
# From example's libnima.yml, and written again on every install.
# ******************************************************************************
# Your settings in example.defaults, read after sdkconfig.defaults
# ******************************************************************************
if(NOT SDKCONFIG_DEFAULTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.defaults")
set(SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.defaults")
endif()
list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_SOURCE_DIR}/example.defaults")
# <<< libnima: example/before-project <<<Once SDKCONFIG_DEFAULTS is set, ESP-IDF reads only the files it names, which is why these lines name sdkconfig.defaults first. The component's, example/component, are in components/example/CMakeLists.txt, and put your project's folder on the library's include path, which is how example.c finds example_id.h.
A note is a comment above its line, as in the block of your sdkconfig.defaults:
# >>> libnima: example >>>
# Added by libnima, and written again on every install, so set
# example's symbols below this block rather than in it.
# ******************************************************************************
# A tick of one millisecond
# ******************************************************************************
# vTaskDelay(1) in the loop waits 1 ms, not 10
CONFIG_FREERTOS_HZ=1000
# <<< libnima: example <<<
A line of yours below the block, CONFIG_FREERTOS_HZ=100, wins, and the next install leaves the library's line out, with its note above it.
Add a part, and take it out. --with uptime adds example_uptime.h and example_uptime.c to the component. --without uptime takes them out again.
libnima nimaltd/libnima-example-esp32 --with uptimeexample_uptime_t up = example_uptime(); /* up.hours, up.minutes, up.seconds */Uninstall it. Whatever libNIMA added to your files goes, so they are back as they were, and the library's files go, tools/make_id.py with them. example.defaults and example_id.h stay, since they are yours, and example.defaults is no longer read. A setting of its you set yourself in sdkconfig.defaults is named, for you to take out:
libnima --uninstall exampleWithout internet. Download this repository as a zip, from the green Code button, Download ZIP, and give libNIMA the zip instead of the name:
libnima D:/Downloads/libnima-example-esp32-main.zipCopy libnima.yml to the root of your library's repository, and change what is yours: its name, its description, its repository, its files and its settings. Every key libNIMA reads is in it, with a comment saying what it does; the ones this library has no use for are commented out. Only name and its headers or sources are required.
Then anyone installs your library with:
libnima yourname/yourlibraryEach entry under esp32.settings becomes a Kconfig symbol in menuconfig, and your code reads it as CONFIG_<name> from sdkconfig.h. What the library writes sits under where it goes: esp32.project for your project's files, its conf in sdkconfig.defaults and its cmake in CMakeLists.txt by place, and esp32.library for its component, its requires the ESP-IDF components your code uses, as this one lists esp_timer, and its cmake the component's lines. once lists files for the project's own folder, and run the steps run after the install, with the script in tools/make_id.py. The libNIMA README has the rest.
| Function | What it does |
|---|---|
void example_init(example_t *handle) |
Start a period of CONFIG_EXAMPLE_PERIOD_MS from now |
bool example_due(example_t *handle) |
Whether the period has passed. Returns at once, and starts the next one when it has |
uint32_t example_count(const example_t *handle) |
How many times example_due() has said yes |
uint32_t example_id(void) |
This device's own ID, from example_id.h, or 0 when the step was not run |
void example_hello(const example_t *handle) |
Print CONFIG_EXAMPLE_GREETING, how many periods have passed, and the device's ID |
example_uptime_t example_uptime(void) |
With the uptime option: hours, minutes and seconds since start up |
Declare one example_t for each thing that repeats on its own rhythm. A loop that comes back late is caught up, so the rhythm does not drift.
Apache License 2.0. See LICENSE.md.