Skip to content

File espos.h

File List > espos_core > include > espos.h

Go to the documentation of this file

/*
 * SPDX-FileCopyrightText: 2026 Dirk Wahrheit
 * SPDX-License-Identifier: Apache-2.0
 *
 * espos — one call brings espOS up.
 *
 *     #include "espos.h"
 *     void app_main(void) { ESP_ERROR_CHECK(espos_start(NULL)); ... }
 *
 * espos_start() runs the component starts in the one order that works
 * (docs/concepts.md): the log ring first so the boot log is kept for
 * /api/v1/logs; the config store next because everything else reads it;
 * the HTTP server before the network seam (espos_net) so /net/status and
 * the provisioning portal have a page to serve the moment there is a link
 * or an access point; espos_net before WiFi because it owns the hostname
 * the station's DHCP request carries and the mDNS responder; WiFi before
 * SignalK because discovery is mDNS; then OTA and BLE, which need all of
 * the above. Each espos_*_start() checks its own prerequisites and fails
 * with ESP_ERR_INVALID_STATE when called out of order — espos_start() is
 * how an application never sees that error.
 *
 * Optional components (espos_sk, espos_ota, espos_ble) are started only
 * when the project builds them. That is decided at configure time from the
 * component list, not by the application. espos_wifi is built wherever the
 * chip has a radio (or, ESP32-P4, a co-processor) and left out on the
 * 802.15.4-only H-series; CONFIG_ESPOS_WIFI (default y) is the switch for a
 * firmware that links it but does not want the station started.
 *
 * Threading: call once, from app_main() or any task. The calls block until
 * every component has started its own tasks, then return; before_network
 * runs on the caller's task. Thread-safe against a second caller.
 */
#pragma once

#include <stdbool.h>
#include "esp_err.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    /* The name the device presents: the SignalK access-request description
     * and the hostname prefix. NULL = the project name (PROJECT_NAME). */
    const char *app_name;
    /* Runs after espos_init() — log and config are up — and before the
     * network stack: bring a display up here so it can show the portal
     * SSID. A non-OK return aborts espos_start() with that error. */
    esp_err_t (*before_network)(void *arg);
    void *arg; /* handed to before_network */
    /* Restart on health conditions the device cannot recover from. Default
     * true; also gated by the espOS core Kconfig option. The policy sink
     * is armed in espos_init() via espos_health_policy_start(); see docs/health.md. */
    bool health_watchdog;
    /* The physical board, for a human reading /api/v1/system/info: "Waveshare
     * ESP32-P4-WIFI6-Touch-LCD-7B". NOTHING can discover this -- IDF knows the
     * chip, not what it is soldered to; the MAC's OUI is Espressif's, not the
     * board vendor's; and the USER_DATA efuse a vendor could burn an id into is
     * blank on every board we have seen. The firmware is the only thing that
     * knows, and it usually already does: a Kconfig `choice` selecting the
     * board has a prompt string that is exactly this. NULL = omit the field
     * rather than guess.
     *
     * APPENDED, not inserted next to app_name where it reads better: a caller
     * using positional initialisers would otherwise have every field after the
     * insertion point silently shift by one. Nothing in this repo does that,
     * but the whole point of a public ABI is the callers that are not in it. */
    const char *board;
} espos_start_opts_t;

#define ESPOS_START_OPTS_DEFAULT { .app_name = NULL, .before_network = NULL, .arg = NULL, .health_watchdog = true, .board = NULL }

esp_err_t espos_start(const espos_start_opts_t *opts);

esp_err_t espos_init(void);

esp_err_t espos_start_network(void);

const char *espos_version(void);

const char *espos_app_name(void);

const char *espos_board(void);

#define ESPOS_ABI_VERSION 5
/* History, so that a binding pinned to an older value can tell what moved:
 *   5  espos_httpd_auth_policy_t gained recovery_until_s and recovery
 *      (appended, sizeof) -- espOS #154. The portal exemption narrowed with
 *      it, which is a behaviour change rather than an ABI one.
 *   4  espos_health_policy_cfg_t gained internal_trough_warn_kb (appended, so
 *      sizeof changed, which is what a caller bakes in) -- espOS #129.
 *   3  espos_wifi_sm_t gained connect_in_flight (appended, sizeof) -- #146.
 *   2  espos_start_opts_t gained board (appended, sizeof) -- #113.
 *   1  the first value, introduced with the rule itself -- #36.
 */

int espos_abi_version(void);

#ifdef __cplusplus
}
#endif