C SDK
Contributing a HAL

Contributing a HAL

The Plexus C SDK uses a Hardware Abstraction Layer (HAL) to decouple core logic from platform-specific code. Adding support for a new board or RTOS means implementing a small set of functions — no changes to the SDK core required.

Overview

A HAL is a single .c file (or .cpp for Arduino-like platforms) that implements platform-specific operations:

  • HTTP POST (send telemetry)
  • Time functions (timestamps, monotonic ticks, delays)
  • Optional: logging, persistent storage, mutex

The SDK ships with HALs for ESP32/Arduino, STM32, and POSIX (Linux/macOS). Your contribution adds another.

Getting Started

  1. Copy the template:

    cp hal/template/plexus_hal_template.c hal/your_platform/plexus_hal_your_platform.c
  2. Add a platform guard at the top:

    #include "plexus.h"
     
    #if defined(YOUR_PLATFORM_MACRO)
    // ... your implementation ...
    #endif
  3. Implement the required functions (see below).

  4. Add to CMakeLists.txt (see Build Integration).

Required Functions

These four functions must be implemented. Without them, the SDK cannot compile.

plexus_hal_http_post

plexus_err_t plexus_hal_http_post(
    const char* url,
    const char* api_key,
    const char* user_agent,
    const char* body,
    size_t body_len
);

Send an HTTP POST request with JSON body. Must set:

  • Content-Type: application/json
  • x-api-key: {api_key}
  • User-Agent: {user_agent} (if non-NULL)

Return values:

ReturnMeaning
PLEXUS_OK2xx response
PLEXUS_ERR_NETWORKConnection failed or non-2xx
PLEXUS_ERR_AUTH401 response
PLEXUS_ERR_RATE_LIMIT429 response
PLEXUS_ERR_SERVER5xx response
PLEXUS_ERR_NULL_PTRNULL argument

TLS: Use HTTPS with certificate verification in production. If your platform lacks TLS, emit a compile-time #warning and document the limitation.

plexus_hal_get_time_ms

uint64_t plexus_hal_get_time_ms(void);

Return wall-clock time in milliseconds since Unix epoch (1970-01-01). Used for metric timestamps. Return 0 if no RTC is available — the server will assign timestamps.

plexus_hal_get_tick_ms

uint32_t plexus_hal_get_tick_ms(void);

Return a monotonic tick counter in milliseconds. Used for flush intervals and backoff timing. Must not jump backwards. Wraparound at UINT32_MAX is handled by the SDK.

plexus_hal_delay_ms

void plexus_hal_delay_ms(uint32_t ms);

Block for at least ms milliseconds. On RTOS platforms, yield the CPU (e.g., osDelay(ms) or vTaskDelay()). On bare-metal, busy-wait is acceptable.

Optional Functions

Implement these for better diagnostics and reliability. If not implemented, the SDK uses no-op stubs.

Logging

void plexus_hal_log(const char* fmt, ...);

Printf-style debug logging. Only called when PLEXUS_DEBUG is enabled. Typical implementation: format to buffer, write to UART.

Persistent Storage

plexus_err_t plexus_hal_storage_write(const char* key, const void* data, size_t len);
plexus_err_t plexus_hal_storage_read(const char* key, void* buf, size_t buf_size, size_t* out_len);
plexus_err_t plexus_hal_storage_clear(const char* key);

Key-value storage for offline buffering. When the network is down, the SDK persists unsent batches and retries later. Typical backends: NVS (ESP32), flash sectors (STM32), filesystem (Linux).

Mutex (Thread Safety)

void* plexus_hal_mutex_create(void);
void  plexus_hal_mutex_lock(void* mutex);
void  plexus_hal_mutex_unlock(void* mutex);
void  plexus_hal_mutex_destroy(void* mutex);

Required only if PLEXUS_ENABLE_THREAD_SAFE is set. Implement using your platform's mutex primitive (FreeRTOS semaphore, pthread mutex, etc.).

Build Integration

Add your HAL to CMakeLists.txt:

# In hal/CMakeLists.txt
if(PLEXUS_HAL STREQUAL "your_platform")
    target_sources(plexus PRIVATE
        hal/your_platform/plexus_hal_your_platform.c
    )
    target_compile_definitions(plexus PUBLIC YOUR_PLATFORM_MACRO)
endif()

For Arduino, add the file to your sketch folder — the Arduino IDE compiles all .cpp files automatically.

Verification Checklist

Before submitting your HAL:

  • All 4 required functions compile without warnings (-Wall -Wextra)
  • http_post sends correct headers and returns appropriate error codes
  • get_tick_ms is monotonic and doesn't block
  • delay_ms actually delays (verify with scope or log timestamps)
  • get_time_ms returns valid epoch time (or 0 if no RTC)
  • Platform guard #if defined(...) prevents compilation on other targets
  • TLS is used for HTTPS, or a #warning documents the limitation
  • Memory usage documented (stack, heap, flash)
  • Tested on real hardware (not just compilation)

Reference Implementations

Study these existing HALs:

HALFileNotes
ESP32/Arduinohal/arduino/plexus_hal_arduino.cppWiFiClientSecure + HTTPClient, FreeRTOS mutex, NVS storage
STM32hal/stm32/plexus_hal_stm32.cLwIP sockets, raw HTTP, CMSIS-OS mutex, RTC timestamps
POSIXhal/posix/plexus_hal_posix.clibcurl, pthread mutex, filesystem storage

The ESP32 HAL is the most complete reference — it implements all optional functions including persistent storage and thread safety.