Skip to content

File syn_sensor.c

File List > sensor > syn_sensor.c

Go to the documentation of this file

#if __has_include("syn_config.h")
#include "syn_config.h"
#endif

#if !defined(SYN_USE_SENSOR) || SYN_USE_SENSOR

#include "../util/syn_assert.h"
#include "syn_sensor.h"

#include <string.h>

/* ── API ────────────────────────────────────────────────────────────────── */

void syn_sensor_init(SYN_Sensor *sensor, const char *name, SYN_SensorReadFunc read_func, void *ctx)
{
    SYN_ASSERT(sensor != NULL);
    SYN_ASSERT(read_func != NULL);

    memset(sensor, 0, sizeof(*sensor));
    sensor->name = name;
    sensor->read_func = read_func;
    sensor->read_ctx = ctx;
    sensor->enabled = true;
}

void syn_sensor_set_interval(SYN_Sensor *sensor, uint32_t interval_ms)
{
    SYN_ASSERT(sensor != NULL);
    sensor->interval_ms = interval_ms;
    sensor->last_poll_tick = syn_port_get_tick_ms();
}

void syn_sensor_enable(SYN_Sensor *sensor, bool enable)
{
    SYN_ASSERT(sensor != NULL);
    sensor->enabled = enable;
    if (enable) {
        sensor->last_poll_tick = syn_port_get_tick_ms();
    }
}

/* ── Filter setup ───────────────────────────────────────────────────────── */

void syn_sensor_set_filter_ma(SYN_Sensor *sensor, SYN_FilterMA *f)
{
    SYN_ASSERT(sensor != NULL);
    sensor->filter_type = (uint8_t)SYN_SENSOR_FILTER_MA;
    sensor->filter = f;
}

void syn_sensor_set_filter_ema(SYN_Sensor *sensor, SYN_FilterEMA *f)
{
    SYN_ASSERT(sensor != NULL);
    sensor->filter_type = (uint8_t)SYN_SENSOR_FILTER_EMA;
    sensor->filter = f;
}

void syn_sensor_set_filter_median(SYN_Sensor *sensor, SYN_FilterMedian *f)
{
    SYN_ASSERT(sensor != NULL);
    sensor->filter_type = (uint8_t)SYN_SENSOR_FILTER_MEDIAN;
    sensor->filter = f;
}

void syn_sensor_clear_filter(SYN_Sensor *sensor)
{
    SYN_ASSERT(sensor != NULL);
    sensor->filter_type = (uint8_t)SYN_SENSOR_FILTER_NONE;
    sensor->filter = NULL;
}

/* ── Threshold setup ────────────────────────────────────────────────────── */

void syn_sensor_set_threshold(SYN_Sensor *sensor, int32_t threshold, int32_t band,
                              SYN_SensorThresholdCallback on_high,
                              SYN_SensorThresholdCallback on_low, void *ctx)
{
    SYN_ASSERT(sensor != NULL);
    sensor->threshold_enabled = true;
    syn_hyst_init(&sensor->hyst, threshold, band, false);
    sensor->on_high = on_high;
    sensor->on_low = on_low;
    sensor->threshold_ctx = ctx;
}

void syn_sensor_clear_threshold(SYN_Sensor *sensor)
{
    SYN_ASSERT(sensor != NULL);
    sensor->threshold_enabled = false;
}

static int16_t apply_filter(SYN_Sensor *sensor, int16_t raw)
{
    switch ((SYN_SensorFilterType)sensor->filter_type) {
    case SYN_SENSOR_FILTER_MA:
        return syn_filter_ma_update((SYN_FilterMA *)sensor->filter, raw);
    case SYN_SENSOR_FILTER_EMA:
        return syn_filter_ema_update((SYN_FilterEMA *)sensor->filter, raw);
    case SYN_SENSOR_FILTER_MEDIAN:
        return syn_filter_median_update((SYN_FilterMedian *)sensor->filter, raw);
    default:
        return raw;
    }
}

/* ── Update ─────────────────────────────────────────────────────────────── */

static void do_read(SYN_Sensor *sensor)
{
    if (sensor == NULL || sensor->read_func == NULL)
        return;
    sensor->raw = sensor->read_func(sensor->read_ctx);

    /* Filter */
    if (sensor->filter != NULL) {
        sensor->filtered = apply_filter(sensor, sensor->raw);
    } else {
        sensor->filtered = sensor->raw;
    }

    /* Threshold check */
    if (sensor->threshold_enabled) {
        bool was_high = syn_hyst_state(&sensor->hyst);
        bool now_high = syn_hyst_update(&sensor->hyst, sensor->filtered);

        if (now_high && !was_high) {
            if (sensor->on_high != NULL) {
                sensor->on_high(sensor, sensor->filtered, sensor->threshold_ctx);
            }
        } else if (!now_high && was_high) {
            if (sensor->on_low != NULL) {
                sensor->on_low(sensor, sensor->filtered, sensor->threshold_ctx);
            }
        }
    }

    /* Push to statistics window (if attached) */
    if (sensor->stats != NULL) {
        syn_signal_push(sensor->stats, (int32_t)sensor->filtered);
    }
}

bool syn_sensor_update(SYN_Sensor *sensor)
{
    SYN_ASSERT(sensor != NULL);

    if (!sensor->enabled)
        return false;

    uint32_t now = syn_port_get_tick_ms();
    if ((now - sensor->last_poll_tick) < sensor->interval_ms) {
        return false;
    }

    sensor->last_poll_tick = now;
    do_read(sensor);
    return true;
}

int16_t syn_sensor_read_now(SYN_Sensor *sensor)
{
    SYN_ASSERT(sensor != NULL);
    do_read(sensor);
    sensor->last_poll_tick = syn_port_get_tick_ms();
    return sensor->filtered;
}

void syn_sensor_service(SYN_Sensor *sensors, size_t count)
{
    SYN_ASSERT(sensors != NULL || count == 0);
    for (size_t i = 0; i < count; i++) {
        syn_sensor_update(&sensors[i]);
    }
}

void syn_sensor_set_stats(SYN_Sensor *sensor, SYN_Signal *stats)
{
    SYN_ASSERT(sensor != NULL);
    sensor->stats = stats;
}

#endif /* SYN_USE_SENSOR */