Appearance
API Reference (Telemetry-Relevant Subset)
This section summarizes the parts of the Coldwave and flake::Service APIs that are most relevant for telemetry. The public Coldwave surface is split across two headers: coldwave.h (core lifecycle, OTA, power, signing, optional Wi-Fi commissioning when libcoldwave is built with router support) and coldwave_ble_config.h (optional BLE-bound local config service). Everything not declared in those two headers is internal and may change without notice.
Result codes (coldwave_result_t)
All Coldwave entry points return a signed integer compatible with libflake's E_OK / E_FAILED constants. CW_OK is 0, so existing if (rc != E_OK) checks remain valid; new code should prefer the CW_* names.
| Code | Value | Meaning |
|---|---|---|
CW_OK | 0 | Success. |
CW_ERR_FAILED | -1 | Generic failure (compatible with E_FAILED). |
CW_ERR_NOT_INITIALIZED | -10 | coldwave_init() has not completed successfully. |
CW_ERR_ALREADY_ATTACHED | -11 | coldwave_backend_attach() called while already attached. |
CW_ERR_NOT_ATTACHED | -12 | Operation requires an attached backend. |
CW_ERR_INVALID_ARG | -13 | A required parameter was null or out of range. |
CW_ERR_NO_BACKEND | -14 | Backend FQDN missing or could not be resolved. |
CW_ERR_NO_NETWORK_IF | -15 | No suitable network interface for the backend. |
CW_ERR_TRANSPORT | -16 | Wire/transport setup failed. |
CW_ERR_NOT_SUPPORTED | -17 | Feature compiled out (e.g. router disabled, BLE config off-target). |
Initialization parameters
coldwave_init_t
| Field | Type | Description |
|---|---|---|
node_type | coldwave_node_t | cwClient (endpoint) or cwRouter (gateway). Telemetry devices use cwClient. |
app_semver | const char* | SemVer string of the currently running firmware. Surfaced as the installed-version FU property for slot 0. |
device_id | const char* | Globally unique device identifier (IMEI, serial, …). Required. |
product_id | const char* | 4-character alphanumeric product identifier. |
hw_id | const char* | Hardware / SoC identifier used by OTA to pick the right image. |
backend | coldwave_backend_t | Backend connection parameters (see below). Mandatory for cwClient. |
net_device_handle | int | Open handle for the primary network device (open("modem0"), open("wlan0"), open("eth0")). -1 if none. |
net_device_type | coldwave_net_device_type_t | cwNetNone, cwNetEthernet, cwNetWiFi or cwNetLte. Drives MAC/LTE readout. |
opt.client | coldwave_client_options_t | Client-only options (see below). Used when node_type == cwClient. |
opt.router | coldwave_router_options_t | Router-only options (see below). Used when node_type == cwRouter. |
Use COLDWAVE_INIT_DEFAULT as the initializer:
cpp
coldwave_init_t cw_init = COLDWAVE_INIT_DEFAULT;coldwave_backend_t
| Field | Type | Description |
|---|---|---|
fqdn | const char* | Fully-qualified backend host name. Required for cwClient. |
ca_cert | unsigned char* | DER-encoded CA certificate. nullptr falls back to unencrypted UDP (PTP). |
ca_cert_len | unsigned | Byte length of ca_cert. |
coldwave_client_options_t
| Field | Type | Description |
|---|---|---|
monthly_data_limit_bytes | unsigned | If non-zero, monthly volume is tracked for reporting (see coldwave_get_remaining_budget()); does not throttle syncing. |
remaining_data_budget_bytes | unsigned | If non-zero, the budget tracker starts with this much budget left this month. |
desired_sync_interval_s | int | Deprecated, ignored — syncs are no longer paced on-device; rate limiting is enforced by the backend. |
coldwave_router_options_t
| Field | Type | Description |
|---|---|---|
no_local_tls | int | If non-zero, local client connections are unencrypted. |
local_tcp_port | uint16_t | TCP port for local clients. 0 uses the default (9986/9987). |
local_network_interface | const char* | Name of the interface to bind to; nullptr binds to all interfaces. |
auth_callback | coldwave_auth_callback_t | Called on every new local connection. nullptr disables authentication. |
auto_update_disabled | int | If non-zero, the backend will not start OTA when new versions are available. |
max_clients | int | Maximum number of concurrent local clients. 0 means unlimited. |
coldwave_auth_callback_t has signature int (*)(const flake::PropArray& rops) and must return CW_OK to accept the client.
Coldwave core C API (coldwave.h)
Lifecycle
| Function | Description |
|---|---|
int coldwave_init(const coldwave_init_t* init, const char* srv_uuid, flake::Service** srv) | Initialize Coldwave. For cwClient, creates the wire from init->backend and calls flakeInitialize(); no traffic until coldwave_backend_attach(). For cwRouter, brings up the local server. If *srv is null a default ServiceWrapper is allocated. |
int coldwave_register_service(const char* srv_uuid, flake::Service** srv, const PropArray& initial_props = PropArray()) | Register an additional service on the same node. |
int coldwave_backend_attach(void) | Attach to the configured backend and start syncing. Backend FQDN/CA come from coldwave_init_t::backend. Non-blocking — the connection is established asynchronously. |
int coldwave_backend_detach(void) | Disconnect from the backend but keep the flake CoreWorker and the connection object alive. coldwave_backend_attach() can be called again without re-initializing. |
bool coldwave_backend_attached(void) | Whether the Coldwave backend is currently attached and online. |
int coldwave_suspend(void) | Suspend the connection management thread. Disconnects from the backend but keeps the CoreWorker and connection object alive. |
int coldwave_resume(void) | Resume after coldwave_suspend(). If the user previously attached, reconnection is triggered automatically. |
int coldwave_uninit(void) | Tear down Coldwave. Disconnects the backend (if attached), stops internal threads, uninitializes flake and frees all owned resources. |
Data budget (client only)
| Function | Description |
|---|---|
unsigned coldwave_get_remaining_budget(void) | Remaining monthly data budget in bytes. Returns 0 if not initialized or no budget configured. |
void coldwave_reset_budget(void) | Reset the monthly budget manager. |
OTA
| Function | Description |
|---|---|
int coldwave_ota_autoupdate_enable(bool e) | Enable or disable automatic OTA updates. |
bool coldwave_ota_autoupdate_enabled(void) | Whether OTA autoupdate is currently enabled. |
int coldwave_register_hw_ota_target(const cw_hw_ota_target_t* t) | Register a per-slot OTA target so libcoldwave can observe the lifecycle (DOWNLOADING/INSTALLING/SUCCESS/FAILED) on the OS-side OTA flow. Slot 0 is reserved for libcoldwave's own SW-OTA. |
cw_hw_ota_target_t fields:
| Field | Type | Description |
|---|---|---|
slot | uint8_t | 1..(COLDWAVE_HW_SLOTS_MAX-1). Slot 0 is reserved. |
ota_target_id | int | Value used in ota_t::target / ota_register_target_handler. |
ctx | void* | Opaque context forwarded to the integrator callbacks. |
on_begin | cw_hw_ota_begin_t | Optional. Called when the OS-side OTA flow starts the target. |
on_append | cw_hw_ota_append_t | Required. Called for every chunk of bytes. |
on_finalize | cw_hw_ota_finalize_t | Optional. Called on successful completion. |
on_abort | cw_hw_ota_abort_t | Optional. Called on abort/failure. |
Power & temperature push
For values that have no portable platform binding (battery rail, on-die temperature, ...), the integrator samples them and pushes them via:
cpp
int coldwave_set_power_info(const cw_power_info_t* info);cw_power_info_t fields:
| Field | Type | Description |
|---|---|---|
fields | uint32_t | OR'd bitmask: CW_POWER_INFO_BATTERY_MV, CW_POWER_INFO_BATTERY_PCT, CW_POWER_INFO_TEMPERATURE. Only fields whose bit is set are read. |
battery_mv | uint16_t | Battery rail voltage in millivolts. Use UINT16_MAX (with the bit set) to mark the value as unknown. |
battery_pct | uint8_t | Estimated battery state-of-charge in percent (0–100). |
temperature_c10 | int16_t | On-die / ambient temperature in deci-Celsius (°C × 10). |
libcoldwave caches the values and the connection loop publishes them at the next sync.
Signing
cpp
int coldwave_sign (const char* message, size_t message_len,
const char signature_buf[COLDWAVE_SIGNATURE_LEN]);
int coldwave_verify(const char* message, size_t message_len,
const char signature_buf[COLDWAVE_SIGNATURE_LEN]);Sign / verify a buffer using the device's key. COLDWAVE_SIGNATURE_LEN is the required output buffer size (64 bytes for the portable build; on __COLDWAVE_OS__ / __CXOS__ builds it is PSA_ECDSA_SIGNATURE_SIZE(256)).
Wi-Fi commissioning (router builds only)
These entry points are only available when libcoldwave is built with router support (COLDWAVE_HAS_ROUTER). On other builds they are not declared at all — guard call sites with #if COLDWAVE_HAS_ROUTER.
| Function | Description |
|---|---|
int coldwave_start_ap_wifi_commissioning(int wifi_dev, const char* ssid, const char* pass, uint32_t timeout_ms, wifi_commissioning_data_callback_t cb) | Start AP-mode Wi-Fi commissioning. |
int coldwave_start_ble_wifi_commissioning(int wifi_dev, int ble_dev, const char* ble_name, uint32_t timeout_ms, wifi_commissioning_data_callback_t cb) | Start BLE-mediated Wi-Fi commissioning. |
void coldwave_end_wifi_commissioning(void) | Stop the in-progress commissioning flow. |
Optional BLE-bound local config service (coldwave_ble_config.h)
A cwClient can additionally expose a single integrator-defined config service on a local Flake router that is bound to a BLE wire. The cloud-facing client connection is unaffected; the two stacks run in parallel.
This feature requires libcoldwave to be built with __COLDWAVE_OS__ / __CXOS__ (OS-side BLE driver + libflake router). On other targets both entry points return CW_ERR_NOT_SUPPORTED.
Functions
| Function | Description |
|---|---|
int coldwave_start_ble_config_service(const cw_ble_config_init_t* init) | Open a local router on a BLE wire and register a single config service on it. Spawns the app thread, which installs handlers before BLE advertising starts. |
void coldwave_stop_ble_config_service(void) | Idempotent. Stops advertising, signals the app thread to exit, waits for it to join, then tears down the local router. Safe from inside a service handler. |
int coldwave_ble_config_should_stop(void) | True while a stop has been requested but the local router has not yet been torn down. App threads poll this and return when it flips to true. |
cw_ble_config_init_t
| Field | Type | Description |
|---|---|---|
srv_uuid | const char* | UUID of the local config service. |
ble_uart_dev | int | open("uart0") result — caller-owned. |
ble_local_name | const char* | BLE advertised name, max 22 chars. nullptr leaves it unchanged. |
auto_reconnect | int | Non-zero toggles BLE_IOCTL_AUTO_RECONNECT. |
auth_callback | coldwave_auth_callback_t | Optional. When set, the local router runs with authentication; invoked on every new client connection. |
user_ctx | void* | Forwarded as-is to thread_fn and on_stopped. |
thread_fn | cw_ble_config_thread_fn_t | Required. Registers Property/customMessage handlers on srv and drives the update loop until coldwave_ble_config_should_stop() returns true. |
thread_stack_size | uint32_t | 0 = libcoldwave default (4096). |
thread_name | const char* | nullptr = "cw_ble_cfg". |
on_stopped | void (*)(void* user_ctx) | Optional. Called after teardown finishes. |
Lifecycle inside coldwave_start_ble_config_service():
flakeInitializeWithRouter()(or…AndAuth()ifauth_callbackis set).- A fresh
ServiceWrapperis registered underinit->srv_uuid. - The app thread is started — its first job is handler registration.
- The BLE local name is set, the BLE server wire is added, advertising starts, and
auto_reconnectis applied.
Step 3 runs before step 4 so a peer cannot connect to a service whose handlers have not been installed yet.
flake::Service (excerpt)
All methods are declared in <flake/Service.h>.
Core methods for telemetry:
| Member | Description |
|---|---|
template<uint32_t PropTag, typename T> int set(T value) | Set the value of a property identified by PropTag. Returns E_OK on success, E_REFUSED if the value cannot be converted or if called from within a forbidden callback context. |
template<uint32_t PropTag> PropType<PropTag> get(PropType<PropTag> defval = ...) | Get the value of a property, or defval if not available. |
template<uint32_t PropTag> int on(PropCallback<PropTag> cb) | Register a property callback for a tag (called when the property is written by the backend). |
template<uint32_t PropTag> int on(PropCallback<PropTag & ~TAG_ACTIONABLE> cb, PropType<PropTag> min, PropType<PropTag> max) | Register a property callback with range validation for actionable properties. |
template<uint32_t PropTag> int onRead(PropCallBackStreamRead cb) | Register stream read callback for a stream property. |
template<uint32_t PropTag> int onWrite(PropCallBackStreamWrite cb) | Register stream write callback for a stream property. |
template<uint32_t PropTag> int onOpenClose(PropCallBackStreamOpenClose cb) | Register stream open/close callback. |
int openProperty(const uint32_t propTag, Stream** stream) | Open a stream for the given property tag (for large or streaming telemetry). |
int sync(int timeout_ms = FLAKE_DEFAULT_TIMEOUT_MS) | Exchange pending property updates and messages with the backend. |
void defer() / int syncDeferred(unsigned timeout_ms, bool block) / bool hasDeferred() | Low-level control of deferred sync batches. |
unsigned pendingBytes() | Get the number of pending bytes waiting to be sent. |
void reset() | Reset the service state. |