ESP Device Board Adaptation

[中文]

Overview

brookesia_hal_adaptor is the board-level HAL adaptor of ESP-Brookesia. Based on the device/interface model in HAL Interface, it initialises real peripherals via esp_board_manager and ESP-IDF drivers, then registers system, network, audio, display, storage, power, video, expansion module, and Wi-Fi capabilities into the global HAL table for upper layers to discover by name.

Features

Built-In Devices

The component ships multiple board-level devices, each registered as a singleton; after initialisation they publish their interfaces into the global table:

Device class (logical name)

Registered interface implementations

Notes

SystemDevice ("System")

BoardInfoIface (BOARD_INFO_IMPL_NAME)

Reads static board metadata and publishes system-level board information.

NetworkDevice ("Network")

SntpClientIface (SNTP_CLIENT_IFACE_NAME), HttpClientIface (HTTP_CLIENT_IFACE_NAME)

Provides platform SNTP and HTTP/HTTPS client capabilities for services.

AudioDevice ("Audio")

AudioCodecPlayerIface (CODEC_PLAYER_IMPL_NAME), AudioCodecRecorderIface (CODEC_RECORDER_IMPL_NAME)

Playback via board Audio DAC; recording via Audio ADC. Each sub-implementation can be disabled in Kconfig; requires board capability ESP_BOARD_DEV_AUDIO_CODEC_SUPPORT.

DisplayDevice ("Display")

DisplayBacklightIface (LEDC_BACKLIGHT_IMPL_NAME), DisplayPanelIface (LCD_PANEL_IMPL_NAME), DisplayTouchIface (LCD_TOUCH_IMPL_NAME)

LEDC backlight, LCD panel, and I2C touch can each be disabled; require ESP_BOARD_DEV_LEDC_CTRL_SUPPORT, ESP_BOARD_DEV_DISPLAY_LCD_SUPPORT, ESP_BOARD_DEV_LCD_TOUCH_I2C_SUPPORT respectively.

StorageDevice ("Storage")

FileSystemIface (GENERAL_FS_IMPL_NAME), KeyValueIface (KV_IMPL_NAME)

General filesystem implementation for LittleFS, optional SPIFFS, flash FATFS, and SD card / FATFS; KV implementation backed by ESP-IDF NVS. Filesystem backends are enabled per Kconfig, and LittleFS / flash FATFS are mounted directly by the adaptor.

PowerDevice ("Power")

PowerBatteryIface (BATTERY_IMPL_NAME)

Battery and charger capability implementation. Supports ADC voltage estimation or AXP2101 power-management-chip backends; can query level, voltage, power source, and charge state, and control charger configuration when supported by the underlying hardware.

VideoDevice ("Video")

CameraIface and video processor interfaces

Publishes camera and video processing interfaces when the selected board exposes them.

ExpansionDevice ("Expansion")

expansion::ModuleManagerIface ("ExpansionModuleManager")

Optionally publishes stable expansion-slot state, queries, and change events. Board-specific providers identify and claim the actual modules.

WifiDevice ("WiFi")

BasicIface (BASIC_IMPL_NAME), StationIface (STA_IMPL_NAME), SoftApIface (SOFTAP_IMPL_NAME)

ESP-IDF Wi-Fi backend for single-shot lifecycle, STA, scan, SoftAP, and provisioning actions. Retry, fallback, and auto-connect policy are owned by brookesia_service_wifi.

Configuration

Each device and sub-interface can be enabled or disabled individually under ESP-Brookesia: Hal Adaptor Configurations in menuconfig; default capability parameters (volume range, recording format, backlight range, battery low-level thresholds, ADC voltage conversion parameters, etc.) are also adjustable in menuconfig, and are mapped to compile-time macros by macro_configs.h.

To override default capability parameters before initialisation, call set_codec_player_info, set_codec_recorder_info, or set_ledc_backlight_info on the corresponding device singleton. Calls after initialisation typically have no effect.

Expansion Module Support

CONFIG_BROOKESIA_HAL_ADAPTOR_ENABLE_EXPANSION_MODULES controls the generic expansion framework. It defaults to disabled, so boards without expansion hardware do not create an expansion device, provider, scanner, or background task. A capable board may enable the option in its board defaults.

When enabled, hal::expansion::ModuleManagerIface is available as Expansion:ModuleManager:0. get_module_infos() returns ModuleInfo snapshots containing the provider, slot, type, board identity, generation, and ModuleState. add_event_listener() and remove_event_listener() subscribe to stable changes; callbacks receive the complete updated snapshot.

Module states are defined as follows:

State

Meaning

Unknown

No stable scan result is available yet.

Empty

No module is detected in the slot.

Invalid

The module descriptor is invalid.

Unsupported

The descriptor is valid, but the module type or slot is unsupported.

Ready

The module is ready to open.

Active

The module is claimed.

Error

Detection or a resource operation failed.

Scanning only identifies modules; functional hardware is initialized when the corresponding HAL interface is opened. The board implementation handles detection protocols and resource ownership, while the generic layer provides state queries and events.

When using the event interfaces:

  • Events are delivered asynchronously in order. Claim and release operations do not invoke user callbacks inline.

  • Keep callbacks short and do not wait for other event callbacks.

  • Removing a listener cancels callbacks that have not started and waits for a running callback to finish; a listener may also remove itself from its callback.

  • Subscribe before reading state snapshots, and use each slot's generation to ignore older events.

The Device Service exposes GetExpansionModuleInfos and ExpansionModuleChanged for applications that should not access HAL directly. Board-specific support and hot-plug limitations are documented with the board; see Brookesia Adaptation Guide.

Lifecycle and Error Handling

Brookesia serializes the Board Manager calls it manages. Third-party code that calls Board Manager directly is outside this guarantee and should avoid accessing the same device concurrently with HAL operations.

  • Camera: Opening checks that the video device is available and attempts to release resources acquired by a failed attempt. Cleanup failures are logged; HAL retains responsibility for unfinished cleanup after interface destruction.

  • Frame callbacks: Encoder state queries are allowed. Call stop() and close() from another task. During a stop or close operation, open() and start() fail.

  • Recoverable errors: When resources remain valid, cleanup can continue during a later open operation.

  • Uncertain release state: The affected peripheral is isolated and the original error is retained. Its handle cannot be acquired or released again until a manual restart.

  • SPI drawing: After a synchronous draw fails or times out, it still waits for submitted DMA transfers to finish. The actual return time can therefore exceed the configured timeout. If the transfers cannot be drained safely, the call remains blocked until a manual restart.

Dependency Patches

The component applies patches from hal/brookesia_hal_adaptor/tools according to the enabled features and dependency components. The Mosaico integration uses Board Manager 0.5.15; other dependency versions are managed by component manifests and the project's dependency lock file.

Patch

Purpose

esp_board_manager_periph_deinit_retry

Isolate handles after an uncertain peripheral release to prevent double release or reuse.

esp_board_manager_dvp_camera_deinit

Report camera close errors and release video and I2C resources in order.

esp_video_dvp_deinit_order

Check whether the video device is still open before destroying its sensor.

av_processor_frame_mode_stop

Stop the capture pipeline in frame mode.

esp_capture_v4l2_uyvy_support

Support UYVY/YUYV format negotiation and cleanup after negotiation failure.

media_lib_sal_esp_tls_idf6

Adapt to the ESP-IDF 6 TLS interface.

Note

Configuration fails if a required patch cannot be applied or an incompatible older patch is detected. Check dependency versions and local changes; when restoring a dependency, use the version recorded in the lock file.

API Reference

Header File

Classes

class SystemDevice : public esp_brookesia::hal::Device

Header File

Classes

class NetworkDevice : public esp_brookesia::hal::Device

Header File

Classes

class DisplayDevice : public esp_brookesia::hal::Device

Board-backed display device: registers panel, touch, and backlight HAL interfaces after board bring-up.

Obtained via get_instance(). Not copyable or movable.

Public Static Functions

static inline DisplayDevice &get_instance()

Returns the process-wide singleton display device.

Returns

Reference to the unique DisplayDevice instance.

Public Static Attributes

static constexpr const char *DEVICE_NAME = "Display"

Logical device name passed to the base Device constructor.

static constexpr const char *LEDC_BACKLIGHT_IMPL_NAME = "Display:LedcBacklight"

Registry key for the LEDC-based backlight HAL implementation ("Display:LedcBacklight").

static constexpr const char *LCD_PANEL_IMPL_NAME = "Display:LcdPanel"

Registry key for the LCD panel HAL implementation ("Display:LcdPanel").

static constexpr const char *LCD_TOUCH_IMPL_NAME = "Display:LcdTouch"

Registry key for the LCD touch HAL implementation ("Display:LcdTouch").

static constexpr const char *LCD_GROUP_ID = "display_lcd"

Group ID.

Header File

Classes

class AudioDevice : public esp_brookesia::hal::Device

Board-backed audio device: registers codec player and recorder HAL interfaces after board bring-up.

Obtained via get_instance(). Not copyable or movable.

Public Functions

bool set_codec_recorder_info(audio::CodecRecorderIface::Info info)

Overrides default static recording capability information used when constructing the codec recorder implementation.

Parameters

info -- [in] Codec recorder capability descriptor (format, channels, gains, etc.).

Returns

true if the value was stored; false on invalid input or if the recorder is already initialized.

bool set_processor_config(AudioProcessorConfig config)

Set the ESP audio processor backend configuration.

This must be called before the audio processor playback, encoder, or decoder HAL interfaces are initialized.

Parameters

config -- [in] Complete processor configuration.

Returns

true if the value was stored; false after processor initialization.

Public Static Functions

static inline AudioDevice &get_instance()

Returns the process-wide singleton audio device.

Returns

Reference to the unique AudioDevice instance.

Public Static Attributes

static constexpr const char *DEVICE_NAME = "Audio"

Logical device name passed to the base Device constructor.

static constexpr const char *CODEC_PLAYER_IMPL_NAME = "Audio:CodecPlayer"

Registry key for the codec player HAL implementation ("Audio:CodecPlayer").

static constexpr const char *CODEC_RECORDER_IMPL_NAME = "Audio:CodecRecorder"

Registry key for the codec recorder HAL implementation ("Audio:CodecRecorder").

static constexpr const char *PLAYBACK_IMPL_NAME = "Audio:Playback"

Registry key for the audio playback HAL implementation.

static constexpr const char *ENCODER_IMPL_NAME = "Audio:Encoder:0"

Registry key for the audio encoder HAL implementation.

static constexpr const char *DECODER_IMPL_NAME = "Audio:Decoder:0"

Registry key for the audio decoder HAL implementation.

Header File

Classes

class StorageDevice : public esp_brookesia::hal::Device

Board-backed storage device: publishes filesystem and key-value HAL interfaces after bring-up.

Obtained via get_instance(). Not copyable or movable.

Public Static Functions

static inline StorageDevice &get_instance()

Returns the process-wide singleton storage device.

Returns

Reference to the unique StorageDevice instance.

Public Static Attributes

static constexpr const char *DEVICE_NAME = "Storage"

Logical device name passed to the base Device constructor.

Header File

Classes

class PowerDevice : public esp_brookesia::hal::Device

Power-backed metadata device: publishes a power HAL interface.

Obtained via get_instance(). Not copyable or movable.

Public Static Functions

static inline PowerDevice &get_instance()

Returns the process-wide singleton power device.

Returns

Reference to the unique PowerDevice instance.

Public Static Attributes

static constexpr const char *DEVICE_NAME = "Power"

Logical device name passed to the base Device constructor.

static constexpr const char *BATTERY_IMPL_NAME = "Power:Battery"

Registry key for the power HAL interface ("Power:Battery").

Header File

Classes

class VideoDevice : public esp_brookesia::hal::Device

Header File

Classes

class ModuleManagerIface : public esp_brookesia::hal::Interface

Expansion module discovery and state-event interface.

Public Functions

virtual std::vector<ModuleInfo> get_module_infos() const = 0

Get stable snapshots for all registered provider slots.

virtual EventListenerId add_event_listener(EventListener listener) = 0

Subscribe to stable slot-state changes.

Callbacks are serialized asynchronously on an event worker independent of scanning. A callback receives the snapshot captured at the transition; newer state may already be available from get_module_infos(). Callbacks may wait for scans or claim modules. The application must keep captured objects alive until their listener is removed.

Returns

Non-zero listener id on success, or zero when the callback is empty.

virtual bool remove_event_listener(EventListenerId id) = 0

Remove a previously registered listener.

When called outside the event worker, return waits for any in-flight callback to finish. Queued invocations that have not entered the callback are suppressed. A listener may remove itself or another listener; its current invocation then completes normally, and no later invocation is made.

Public Static Functions

static inline std::string get_default_instance_name(size_t id = 0)

Get the conventional instance name.

Header File

Classes

class ExpansionDevice : public esp_brookesia::hal::Device

HAL device publishing the generic expansion module manager.

Header File

Classes

class ModuleProvider

Board-specific expansion-slot provider.

Providers perform one physical sample per scan() call. Periodic scheduling, debounce, state publication, serialization, and ownership are handled by the adaptor runtime.

Public Functions

virtual std::string_view get_name() const = 0

Return a process-wide unique provider name.

virtual std::vector<std::string> get_slots() const = 0

Return stable provider-local slot names.

inline virtual std::expected<void, std::string> start()

Acquire provider resources before the first consumer starts scanning.

inline virtual std::expected<void, std::string> stop()

Release provider resources after the last consumer or lease exits.

virtual std::expected<ScanInfo, std::string> scan(std::string_view slot) = 0

Take one physical sample of a slot.

virtual std::expected<ClaimOptions, std::string> claim(const ModuleInfo &module, uint64_t scan_identity) = 0

Transfer a ready module from scanning to a consumer.

virtual std::expected<void, std::string> release(const ModuleInfo &module) = 0

Return a claimed module to a scan-safe state.

The provider must restore a scan-safe hardware state before returning, including when it reports a secondary cleanup error.

class ModuleLease

Move-only ownership token for one claimed expansion module.

Public Functions

explicit operator bool() const noexcept

Test whether this object owns an active module.

const ModuleInfo &get_info() const noexcept

Get the active module snapshot owned by this lease.

bool reset(std::string *error_message = nullptr)

Release the module now; the destructor performs the same operation.

Macros

Header File

Classes

class WifiDevice : public esp_brookesia::hal::Device