OreBolt-OS/modules/orebolt-proxalarm/proxalarm.c

213 lines
7.3 KiB
C
Executable File

/*
* proxalarm.c -- Proximity Alarm module main entry point (unified)
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* OreBolt OS module: Unified Proximity Alarm / Radar.
*
* Packs RF scanning, kinematics, and radar UI as a single .mod binary
* with three internal layers.
*
* Three-layer architecture:
* bledsp -- Unified RF/DSP layer (BLE scanning + WiFi stub + RSSI)
* proxvec -- Kinematics layer (target tracking + alarm FSM)
* radar_ui -- Presentation layer (LVGL radar display)
*
* Input controls (via H2 rotary encoder + buttons):
* ROTATE Cycle sensitivity (NEAR threshold: -40, -50, -60, -70 dBm)
* PLAY Toggle scan pause/resume
* NEXT Cycle RF source (BLE <-> WIFI)
* BACK Exit module
*
* This binary is fork+exec'd by the h2_test launcher.
* It initialises its own LVGL instance and runs its own event loop.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "h2_ui.h"
#include "log_manager.h"
#include "bledsp.h"
#include "proxvec.h"
#include "radar_ui.h"
/* ------------------------------------------------------------------ */
/* Sensitivity presets (dBm thresholds for the "near" alarm zone) */
/* ------------------------------------------------------------------ */
static const int8_t sens_presets[] = { -40, -50, -60, -70 };
#define SENS_COUNT (int)(sizeof(sens_presets) / sizeof(sens_presets[0]))
static int sens_idx = 1; /* default: -50 dBm */
/* ------------------------------------------------------------------ */
/* State */
/* ------------------------------------------------------------------ */
static volatile int running = 1;
static int paused = 0;
static int prev_alarms = 0;
static uint32_t last_scan_ms;
/* ------------------------------------------------------------------ */
/* Helpers */
/* ------------------------------------------------------------------ */
static uint32_t mono_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint32_t)(ts.tv_sec * 1000U + ts.tv_nsec / 1000000U);
}
static void update_sensitivity(void)
{
int8_t thresh = sens_presets[sens_idx];
bledsp_set_near_threshold(thresh);
/* Map alarm radius: lower threshold (closer) = smaller radius.
* -40 dBm -> radius 30, -70 dBm -> radius 90 */
int radius = 30 + (sens_idx) * 20;
proxvec_set_alarm_radius((int16_t)radius);
char buf[32];
snprintf(buf, sizeof(buf), "NEAR: %ddBm", thresh);
radar_ui_set_sensitivity_label(buf);
LOG_INF("proxalarm: sensitivity set to %d dBm (radius %d grid units)",
thresh, radius);
}
/* ------------------------------------------------------------------ */
/* Signal handler */
/* ------------------------------------------------------------------ */
#include <signal.h>
static void on_signal(int sig) { (void)sig; running = 0; }
/* ------------------------------------------------------------------ */
/* Main */
/* ------------------------------------------------------------------ */
int main(int argc, char **argv)
{
(void)argc; (void)argv;
signal(SIGINT, on_signal);
signal(SIGTERM, on_signal);
/* Initialise logging */
if (log_init("/data/vault/syslog.log") < 0) {
fprintf(stderr, "[-] proxalarm: log_init failed\n");
return 1;
}
LOG_INF("proxalarm: starting (unified proximity sensing)");
/* Initialise LVGL (own instance for this module) */
init_h2_graphics_runtime("PROXALARM v1.7");
/* Initialise the three layers (bottom-up) */
if (bledsp_init() < 0) {
LOG_ERR("proxalarm: bledsp_init failed");
log_close();
return 1;
}
proxvec_init();
radar_ui_init();
/* Set initial sensitivity */
update_sensitivity();
/* Set source label (shows BLE/WIFI/SIM depending on mode) */
radar_ui_set_source_label(bledsp_source_label());
/* Open input device */
int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
if (input_fd < 0) {
LOG_WARN("proxalarm: cannot open input device: %s", strerror(errno));
}
last_scan_ms = mono_ms();
LOG_INF("proxalarm: ready (ROTATE=sens PLAY=pause NEXT=source BACK=exit)");
/* ---- Main loop ---- */
while (running) {
lv_timer_handler();
/* Process input events */
if (input_fd >= 0) {
struct input_event ev;
while (read(input_fd, &ev, sizeof(ev)) > 0) {
if (ev.type == EV_REL && ev.code == H2_ROTARY_REL && ev.value != 0) {
/* Cycle sensitivity */
sens_idx += (ev.value > 0) ? 1 : -1;
if (sens_idx < 0) sens_idx = SENS_COUNT - 1;
if (sens_idx >= SENS_COUNT) sens_idx = 0;
update_sensitivity();
}
if (ev.type == EV_KEY && ev.value == 1) {
if (ev.code == H2_KEY_PLAY) {
paused = !paused;
LOG_INF("proxalarm: %s", paused ? "PAUSED" : "RESUMED");
}
if (ev.code == H2_KEY_NEXT) {
/* Cycle RF source: BLE <-> WIFI */
bledsp_cycle_source();
radar_ui_set_source_label(bledsp_source_label());
LOG_INF("proxalarm: source=%s", bledsp_source_label());
}
if (ev.code == H2_KEY_BACK) {
running = 0;
}
}
}
}
/* Periodic scan + update (respect BLE scan interval) */
uint32_t now = mono_ms();
if (!paused && (now - last_scan_ms >= (uint32_t)BLE_DSP_SCAN_INTERVAL_MS)) {
last_scan_ms = now;
/* Layer 1: poll BLE hardware */
bledsp_poll();
/* Layer 2: feed device data to kinematics engine */
bledsp_device_t devs[BLE_DSP_MAX_DEVICES];
int dev_count = bledsp_get_devices(devs, BLE_DSP_MAX_DEVICES);
proxvec_update(devs, dev_count);
/* Layer 3: get targets and refresh display */
proxvec_target_t tgts[PROXVEC_MAX_TARGETS];
int tgt_count = proxvec_get_targets(tgts, PROXVEC_MAX_TARGETS);
int alarm_count = proxvec_get_alarm_count();
radar_ui_refresh(tgts, tgt_count, alarm_count);
/* Alarm flash management */
if (alarm_count > 0 && prev_alarms == 0) {
radar_ui_set_alarm_flash(1);
LOG_INF("proxalarm: ALARM triggered (%d target%s in zone)",
alarm_count, alarm_count == 1 ? "" : "s");
} else if (alarm_count == 0 && prev_alarms > 0) {
radar_ui_set_alarm_flash(0);
LOG_INF("proxalarm: alarm cleared");
}
prev_alarms = alarm_count;
}
usleep(5000); /* ~200 Hz input poll, LVGL tick */
}
/* ---- Cleanup ---- */
if (input_fd >= 0) close(input_fd);
radar_ui_set_alarm_flash(0);
radar_ui_destroy();
proxvec_shutdown();
bledsp_shutdown();
log_close();
return 0;
}