// =============================================================================
// PDL CONSULTING LLC — TRADE SECRET
// Copyright (c) 2026 PDL Consulting LLC. All rights reserved.
//
// src/cognitive_rf.h
// Cognitive RF Awareness — ESP32-S3 SRAM-constrained local baseline learner
//
// Ports the EWMA + CUSUM change-detection core from
// pdl-engine/pdl_platform/pdl_quantum/integrations/cognitive_rf.py
// into a zero-malloc, pure-C++ module suitable for Heltec WiFi LoRa V4.
//
// Scope (v1)
// ----------
//   - EWMA per WiFi channel (13 channels × float32 = 52 bytes)
//   - 60-sample ring buffer of recent RSSI per channel (13 × 60 × int16 = 1,560 bytes)
//   - CUSUM change-point detector: trips on step changes > COGRF_CUSUM_THRESHOLD
//   - MSG_TYPE_COGNITIVE_RF (0x1C) baseline broadcast packet
//
// Deferred (v2)
// -------------
//   - Full SVD-based blind source separation (server-side in cognitive_rf.py)
//   - SQLite emitter knowledge graph (server-side)
//   - Temporal pattern mining / autocorrelation FFT (server-side)
//
// Memory footprint (SRAM)
// -----------------------
//   EWMA baselines :  13 × 4   =   52 bytes
//   Ring buffers   :  13 × 60 × 2 = 1,560 bytes
//   CUSUM accums   :  13 × 4   =   52 bytes
//   Misc scalars   :              ~  20 bytes
//   Total          :            ~1,684 bytes
//
// Integration (main.cpp)
// ----------------------
// 1. In setup():          cogrf_init();
// 2. In wifi_sniffer_cb(): cogrf_observe(s_scan_channel, pkt->rx_ctrl.rssi);
// 3. In loop() every 300 cycles (~5 min):
//       cogrf_publish(s_sensor_id);
// 4. Optionally, after each detection:
//       uint8_t ch; float score;
//       if (cogrf_anomalous_emitter(&ch, &score)) { ... alert ... }
//
// =============================================================================
#ifndef COGNITIVE_RF_H
#define COGNITIVE_RF_H

#include <cstdint>
#include <cstddef>

// ---------------------------------------------------------------------------
// Tuning constants
// ---------------------------------------------------------------------------

// Number of WiFi channels tracked (1–13)
#define COGRF_NUM_CHANNELS    13u

// EWMA decay factor alpha (equivalent to _TUNING["ewma_decay"] = 0.035)
// Stored as a float literal; no heap allocation.
#define COGRF_EWMA_ALPHA      0.035f

// Minimum observations per channel before the anomaly detector activates
// (equivalent to _TUNING["min_obs_before_alert"] = 12)
#define COGRF_MIN_OBS         12u

// Ring buffer depth per channel (recent RSSI history for CUSUM)
#define COGRF_RING_DEPTH      60u

// CUSUM slack parameter (k) — half the expected step size in dBm units.
// A step of ~10 dBm above baseline is considered anomalous for C-UAS purposes.
// k = 5.0 → CUSUM accumulator threshold at COGRF_CUSUM_THRESHOLD triggers alert.
#define COGRF_CUSUM_K         5.0f

// CUSUM decision threshold (h): accumulator value that trips the detector.
// Tuned to a ~5-sigma excursion at typical drone-band noise floors.
#define COGRF_CUSUM_THRESHOLD 50.0f

// Wire packet size for MSG_TYPE_COGNITIVE_RF
// Layout: 1 (msg_type) + 4 (sensor_id) + 4 (timestamp_ms) +
//         13 × 4 (baselines float) + 13 × 1 (anomaly_flags) + 2 (CRC16)
//       = 1 + 4 + 4 + 52 + 13 + 2 = 76 bytes
#define COGRF_PACKET_SIZE     76u

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

// Initialise all EWMA states, ring buffers, and CUSUM accumulators.
// Must be called once from setup() before wifi_sniffer_cb fires.
void cogrf_init();

// Feed a single RSSI observation for the given WiFi channel (1–13).
// Called from wifi_sniffer_cb(); must be non-blocking, < 1 µs hot path.
void cogrf_observe(uint8_t channel, int16_t rssi);

// Run the CUSUM detector across all 13 channels.
// Returns true (and fills *channel_out, *score_out) when any channel's
// CUSUM accumulator exceeds COGRF_CUSUM_THRESHOLD.
// Returns the channel with the highest score.
// Returns false if no anomaly has been detected.
bool cogrf_anomalous_emitter(uint8_t* channel_out, float* score_out);

// Copy the current 13-channel EWMA baseline into baselines[0..12].
// Channels are zero-indexed (baselines[0] = channel 1, ..., [12] = channel 13).
void cogrf_get_baseline(float baselines[COGRF_NUM_CHANNELS]);

// Build and transmit a MSG_TYPE_COGNITIVE_RF packet via mesh_publish_raw().
// Includes all 13 EWMA baseline values + per-channel anomaly flags + CRC16.
// Returns true on successful transmission, false on TX failure.
bool cogrf_publish(uint32_t sensor_id);

#endif // COGNITIVE_RF_H
