/* * 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 #include #include #include #include #include #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 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; }