-
Notifications
You must be signed in to change notification settings - Fork 3
SysTypes
Raft applications enable targeting different hardware iterations, device types and other variations using the SysType mechanism.
SysTypes allow different configurations of Raft applications depending on hardware variations or user choice. When a Raft application is built a SysType must be selected and this determines the system configuration. Subsequently the specific settings in a SysType can be overridden using an API which places amendments in non-volatile storage. SysTypes can also be parameterized at run-time to permit, for instance, small hardware variations between different revisions to be handled without defining an entirely new SysType.
SysTypes are defined by a set of one or more folders inside the systypes folder at the root of the project. For instance, to target two different variations on an embedded project (for example called "TypeA" and "TypeB"), sub-folders named "TypeA" and "TypeB" can be created under the systypes folder.
The name of the sub-folder defines the name of the SysType. Note that SysType names need to be valid folder names on the OS that you are using.
The Raft command line interface is the best way to generate an initial SysType and then additional SysTypes can be created by duplicating the folder of that SysType (and its contents) and naming the copy according to your desired name for the SysType.
In addition to the folders used to define each SysType, there is a folder called Common inside the systypes folder. SysTypes which share features can use the Common folder to make configuration management simpler. For instance, if the file system contents should be the same for each SysType then this information can be held in the Common folder and the path set in the features.cmake file (see below) set to indicate this.
The build system automatically merges several configuration files from the Common/ folder with their counterparts in the active SysType folder. This means you can put settings that apply to every variant in Common/ and only override the ones that differ in the SysType-specific folder. The merge is run by scripts/MergeSysTypeConfigs.py at the start of every build, and merged outputs are written under build/<SysType>/raft/.
| File | How Common/ and <SysType>/ are combined |
|---|---|
SysTypes.json |
Shallow merge at the top-level key level. Top-level keys present in the SysType file replace (do not deep-merge) those from Common/. Result: build/<SysType>/raft/SysTypes.json.merged. |
sdkconfig.defaults |
Line-by-line merge keyed on CONFIG_* names. SysType lines override Common values for the same key; comments and unrelated lines from both files are preserved. Result: build/<SysType>/raft/sdkconfig.defaults.merged. |
DevTypes.json |
Both files are passed through to ProcessDevTypeJsonToC.py, so device type records can be defined in either folder; Common/DevTypes.json is processed first, then <SysType>/DevTypes.json. |
features.cmake |
Not merged — the SysType file is include()-d by CMake, and a SysType features.cmake typically calls include(...) on the Common file itself before adding overrides. |
partitions.csv |
Not merged — the SysType's file is used if present, otherwise the Common one. The chosen file is copied to build/raft/partitions.csv so sdkconfig.defaults can reference it portably. See Partitions and Flash Layout. |
FSImage/ and WebUI/
|
Not merged — paths are resolved per-SysType via the FS_IMAGE_PATH and UI_SOURCE_PATH variables in features.cmake. Multiple SysTypes can point at the same Common folder (e.g. "../Common/FSImage") to share content. |
Key consequences:
-
Top-level keys are atomic in
SysTypes.json. The merge is a singledict.update()— ifCommon/SysTypes.jsondefines a"NetMan"block and a SysType wants to change justwifiSTAEn, the SysType file must repeat the whole"NetMan"block. There is no nested deep merge, and arrays are never element-wise merged. -
sdkconfig.defaultsdoes per-key override. You can override a singleCONFIG_*value in a SysType without restating the rest of the file. -
Anything you put only in
Common/is automatically inherited. A SysType with an empty (or absent)SysTypes.jsonwill still build usingCommon/SysTypes.jsonverbatim. -
Inspect the merged output at
build/<SysType>/raft/SysTypes.json.mergedandbuild/<SysType>/raft/sdkconfig.defaults.mergedif you are unsure which key won.
Suppose Common/SysTypes.json contains a fully-populated bus configuration:
To use different pins for a variant, the SysType SysTypes.json must repeat the whole HWDevMan block:
{
"HWDevMan": {
"Buses": {
"buslist": [
{ "name": "I2CA", "type": "I2C", "i2cPort": 0, "sdaPin": 4, "sclPin": 5 }
]
}
}
}A SysType file that contains only {"HWDevMan": {"Buses": {"buslist": [{"sdaPin": 4, "sclPin": 5}]}}} would replace the whole HWDevMan value — losing name, type, i2cPort and any other top-level config in HWDevMan — and the bus would fail to register.
If a single nested value really does need to vary per device (rather than per variant), prefer runtime configuration layering via NVS: see Configuration and Advanced RaftJson. RaftJson's NVS overrides are path-aware, so a single key like HWDevMan/Buses/buslist[0]/sdaPin can be persisted without restating the rest of the document.
For the full pipeline, including how the merged files feed into the ESP-IDF build, see Raft Build Process.
Each folder for a specific SysType (and the Common folder) contains the following files and folders ...
This file is a JSON document which specifies the configuration for your app.
The general structure of a SysTypes.json file is as follows:
{
"SystemName": "A name you define",
"SysManager": {
... configuration settings for the SysManager
},
"SysModA" : {
... configuration for SysModA
},
"SysModB" : {
... configuration for SysModB
}
}SysManager settings are described in Raft SysManager and SysManager Settings
SysModA and SysModB are names that are defined when SysMods are registered in the startup code for the app. The name may be the same as the name of the SysMod class but also may be different to allow multiple instances of a SysMod, for instance.
The settings available to configure specific SysMods are described in Raft SysMods and SysMod Settings
For example, a newly created app might have the following SysType.json contents (note that this is a shortened version of the file for illustration only):
{
"SystemName": "MySystem",
"Manufacturer": "MyCompany",
"SysManager": {
"monitorPeriodMs":10000,
"slowSysModMs": 50
},
"NetMan": {
"wifiSTAEn": 1,
"NTPServer": "pool.ntp.org",
"logLevel": "D"
},
"SerialConsole": {
"enable": 1
},
"WebServer": {
"enable": 1,
"webServerPort": 80,
"stdRespHeaders": [
"Access-Control-Allow-Origin: *"
],
"apiPrefix": "api/",
},
"Publish": {
"enable": 1
},
"MainAppSysMod": {
"exampleGroup": {
"exampleKey": "Welcome to Raft!"
}
}
}
Most of the top-level keys refer to the names of SysMods which they configure. For instance the "NetMan" key defines information to configure the network manager (NetMan) SysMod.
The user defined SysMod "MainAppSysMod" is configured using the information referred to by the last key in this object.
To add configuration settings simply add JSON key:value pairs to the "MainAppSysMod" object as you would normally do in a JSON document.
When inside the C++ source code for the setup() function in the MainAppSysMod class, you can use the functions specified in RaftJson to access these values.
sdkconfig is a file used by the ESP IDF to configure a project. The conventional way to use the ESP IDF is to run a utility called menuconfig but this is unnecessary for a Raft application. Instead an sdkconfig.defaults file is used to specify deviations from the normal default values used to generate an sdkconfig file.
For example, an sdkconfig.defaults file generated by the raft cli new function might look something like this:
# Define configuration
# Remove/repace these comments to set level to debug/info
# Default log level
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=n
# Serial Baud-Rate
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
# Flash size
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# Partition Table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="build/raft/partitions.csv"
# Ethernet
CONFIG_ETH_USE_ESP32_EMAC=n
CONFIG_ETH_USE_OPENETH=n
CONFIG_ETH_USE_SPI_ETHERNET=n
# Common ESP-related
CONFIG_ESP_MAIN_TASK_STACK_SIZE=10000
# FreeRTOS
CONFIG_FREERTOS_HZ=1000
# SPIRAM
CONFIG_SPIRAM=nSo, for instance, to change the flash-size for the device you are using you would need to remove the CONFIG_ESPTOOLPY_FLASHSIZE_4MB and insert, for example, CONFIG_ESPTOOLPY_FLASHSIZE_8MB
For more details on the settings in sdkconfig files see the ESP IDF documentation
This is a standard file in an ESP IDF project. It defines the layout of the flash memory used to store persistent information including program binaries, file systems and non-volatile settings.
For more information on partitions.csv see the ESP IDF documentation
The features.cmake file in a SysType folder is included by CMake (via include()), not text-merged. Most SysTypes start with a one-liner that pulls in the Common file and then add or override variables:
# systypes/MyVariant/features.cmake
include(${CMAKE_CURRENT_LIST_DIR}/../Common/features.cmake)
# Variant-specific overrides go here
set(IDF_TARGET "esp32s3")
add_compile_definitions(VARIANT_HAS_OLED=1)Individual settings can be promoted from Common/features.cmake into the SysType features.cmake simply by re-set()ing them after the include() line.
The Common folder features.cmake may look like this:
# Set the target Espressif chip
set(IDF_TARGET "esp32")
# System version
add_compile_definitions(SYSTEM_VERSION="1.0.0")
# Raft components
set(RAFT_COMPONENTS
RaftSysMods@main
RaftWebServer@main
RaftI2C@main
)
# File system
set(FS_TYPE "littlefs")
set(FS_IMAGE_PATH "../Common/FSImage")These settings are processed by the ESP IDF CMake build system (which is extended by the Raft build system).
Many of these settings are self-explanatory and can be changed to alter the build process.
Note that IDF_TARGET values are lower-case so esp32, esp32s3 and esp32c3 are valid values.
Raft components are added by the RAFT_COMPONENTS build variable. A specific version of a Raft component can be specified by placing a tag after the @ symbol in each line. For instance to specify the v1.5.9 release of the RaftSysMods component, the following could be used:
# Raft components
set(RAFT_COMPONENTS
RaftSysMods@v1.5.9
RaftWebServer@main
RaftI2C@main
)The FSImage folder contains file to place on the file system of the device (assuming there is one). If a WebUI is specified then files will be added to a temporary copy of this folder before flashing to the device.
Simply copy files you want on the file system into this folder.
Note that littlefs (the default file system for raft) supports folders.
For details of the file system itself (LittleFS vs SPIFFS, SD support, runtime API) see File System.
Used to declare custom I²C device type records that should be compiled into the firmware in addition to those shipped with RaftI2C. The file is auto-discovered: if Common/DevTypes.json exists it is processed first, then <SysType>/DevTypes.json if present. Both contribute records to the generated DeviceTypeRecords_generated.h and DevicePollRecords_generated.h. See Adding an I2C Device Type and Device Type Record Format.
This folder is used for the web user-interface. Currently the build system assumes that npm install followed by npm run build will be used to build the web UI. This has been used successfully for web UIs built using react and packaged using parcel (which has quite a low output file-size).
For a detailed description of how the build system processes SysType folders, merges Common and SysType-specific files, and generates the file system image, see Raft Build Process and WebUI Build Pipeline.
To enable this build process, uncomment lines at the bottom of the features.cmake file in the systypes/Common folder ...
... rest of features.cmake file ...
# Web UI
# This assumes an app is built using npm run build
# it also assumes that the web app is built into a folder called "dist" in the UI_SOURCE_PATH
set(UI_SOURCE_PATH "../Common/WebUI")
# Uncomment the following line if you do NOT want to gzip the web UI
# set(WEB_UI_GEN_FLAGS ${WEB_UI_GEN_FLAGS} --nogzip)
# Uncomment the following line to include a source map for the web UI - this will increase the size of the web UI
# set(WEB_UI_GEN_FLAGS ${WEB_UI_GEN_FLAGS} --incmap)-
Top-Level SysType Configuration — keys at the root of
SysTypes.json. - Raft Build Process — full pipeline including the merge stages.
-
WebUI Build Pipeline — what
UI_SOURCE_PATHandFS_IMAGE_PATHdrive. -
File System — runtime view of
FSImage/content and thelocal/sdmounts. -
Partitions and Flash Layout —
partitions.csvrules and OTA layout. -
Configuration — how the merged
SysTypes.jsonis layered with NVS and runtime overrides at run time.
Getting Started
- Quick Start
- Architecture at a Glance
- Writing Your First SysMod
- Adding a Comms Channel
- Adding an I2C Device Type
- PlatformIO / Arduino
Scaffolding & Building
- Raft CLI
- SysTypes
- Top-Level SysType
- Build Process
- WebUI Build Pipeline
- File System
- Partitions & Flash
- Local Dev Libraries
- Library Developer Guide
Architecture
Built-in SysMods
- NetworkManager
- BLEManager
- WebServer
- MQTTManager
- SerialConsole
- CommandSerial
- CommandSocket
- CommandFile
- FileManager
- LogManager
- ESPOTAUpdate
- StatePublisher
- Remote Logging
- Data Source Registration
Comms & Protocols
- Stack Overview
- Comms Channels
- ProtocolExchange
- RICREST Protocol
- Real-Time Streams
- Adding REST Endpoints
- Built-in REST Endpoints
- File Download (OKTO)
- OTA Update Flow
Devices & Buses
- DeviceManager
- Device Manager REST API
- Device Factory & Classes
- Device Type Records
- Adding an I2C Device Type
- Device Data Publishing
- Data Logger
- I2C Bus
- I2C Device Scanning
- I2C ID & Polling
- MotorControl Overview
- MotorControl Config
- MotorControl Commands
Helpers
Reference
{ "HWDevMan": { "Buses": { "buslist": [ { "name": "I2CA", "type": "I2C", "i2cPort": 0, "sdaPin": 21, "sclPin": 22 } ] } } }