Files
EvilCrowRF-V2/include/StateCommands.h
T
Senape3000 cde0faf128 Source Code first commit
First FW code commit.
2026-02-12 11:57:58 +01:00

251 lines
9.4 KiB
C++

#ifndef StateCommands_h
#define StateCommands_h
#include "core/ble/CommandHandler.h"
#include "DeviceTasks.h"
#include "core/ble/ControllerAdapter.h"
#include "core/ble/Request.h"
#include "esp_log.h"
#include "config.h"
#include "ConfigManager.h"
#include "BinaryMessages.h"
#include "core/ble/ClientsManager.h"
#if BATTERY_MODULE_ENABLED
#include "modules/battery/BatteryModule.h"
#endif
class StateCommands {
public:
// Registering all state commands
static void registerCommands(CommandHandler& handler) {
ESP_LOGI("StateCommands", "Registering state commands");
handler.registerCommand(0x01, handleGetState);
handler.registerCommand(0x02, handleRequestScan);
handler.registerCommand(0x03, handleRequestIdle);
handler.registerCommand(0x13, handleSetTime);
handler.registerCommand(0x17, handleSetDeviceName);
handler.registerCommand(0x15, handleReboot);
handler.registerCommand(0x16, handleFactoryReset);
handler.registerCommand(0xC1, handleSettingsUpdate);
ESP_LOGI("StateCommands", "State commands registered successfully");
}
private:
// Get state — also sends SettingsSync to keep app in sync
static bool handleGetState(const uint8_t* data, size_t len) {
ESP_LOGI("StateCommands", "GetState");
Device::TaskGetState task(true);
ControllerAdapter::sendTask(std::move(task));
// Send current settings to the app (piggybacks on state request)
sendSettingsSync();
// Send firmware version so the app can compare for OTA updates
sendVersionInfo();
// Send device name to the app
sendDeviceName();
// Send battery status if module is enabled
#if BATTERY_MODULE_ENABLED
if (BatteryModule::isInitialized()) {
BatteryModule::sendBatteryStatus();
}
#endif
return true;
}
// Request scan
static bool handleRequestScan(const uint8_t* data, size_t len) {
if (len != sizeof(RequestScan)) {
ESP_LOGW("StateCommands", "Invalid payload size for requestScan");
return false;
}
RequestScan request;
memcpy(&request, data, sizeof(RequestScan));
if (!moduleExists(request.module)) {
ESP_LOGE("StateCommands", "Invalid module number: %d", request.module);
return false;
}
ESP_LOGI("StateCommands", "RequestScan: module=%d, minRssi=%d", request.module, request.minRssi);
Device::TaskDetectSignalBuilder taskBuilder;
taskBuilder.setModule(request.module);
taskBuilder.setMinRssi(request.minRssi);
Device::TaskDetectSignal task = taskBuilder.build();
ControllerAdapter::sendTask(std::move(task));
return true;
}
// Request idle
static bool handleRequestIdle(const uint8_t* data, size_t len) {
if (len < 1) {
ESP_LOGW("StateCommands", "Insufficient data for requestIdle");
return false;
}
uint8_t module = data[0];
if (!moduleExists(module)) {
ESP_LOGE("StateCommands", "Invalid module number: %d", module);
return false;
}
ESP_LOGI("StateCommands", "RequestIdle: module=%d", module);
Device::TaskIdle task(module);
ControllerAdapter::sendTask(std::move(task));
return true;
}
// Set time (Unix timestamp in seconds, 4 bytes little-endian)
static bool handleSetTime(const uint8_t* data, size_t len) {
if (len < 4) {
ESP_LOGW("StateCommands", "Insufficient data for setTime");
return false;
}
// Read Unix timestamp (little-endian)
uint32_t timestamp = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
// Set global time
extern uint32_t deviceTime;
deviceTime = timestamp;
ESP_LOGI("StateCommands", "Time set to: %lu (Unix timestamp)", (unsigned long)timestamp);
return true;
}
// Reboot device
static bool handleReboot(const uint8_t* data, size_t len) {
ESP_LOGI("StateCommands", "Rebooting device");
ESP.restart();
return true;
}
// Set BLE device name — payload is the raw ASCII name (1-20 bytes).
// Takes effect after reboot. Sends confirmation via VersionInfo.
static bool handleSetDeviceName(const uint8_t* data, size_t len) {
if (len < 1 || len > MAX_DEVICE_NAME_LEN) {
ESP_LOGW("StateCommands", "Invalid device name length: %u (must be 1-%u)",
(unsigned)len, (unsigned)MAX_DEVICE_NAME_LEN);
return false;
}
if (!ConfigManager::setDeviceName(reinterpret_cast<const char*>(data), len)) {
ESP_LOGE("StateCommands", "Failed to set device name");
return false;
}
ESP_LOGI("StateCommands", "Device name set to: %s", ConfigManager::settings.deviceName);
// Send confirmation: reply with command success including the new name
uint8_t resp[2 + MAX_DEVICE_NAME_LEN];
resp[0] = 0xF2; // MSG_COMMAND_SUCCESS
resp[1] = 0x17; // echo command ID
size_t nameLen = strlen(ConfigManager::settings.deviceName);
memcpy(resp + 2, ConfigManager::settings.deviceName, nameLen);
ClientsManager::getInstance().notifyAllBinary(
NotificationType::State,
resp, 2 + nameLen);
return true;
}
// Factory reset — erase all LittleFS data and reboot.
// Payload: [0x46][0x52] ('FR') as confirmation guard.
static bool handleFactoryReset(const uint8_t* data, size_t len) {
// Require 2-byte confirmation payload 'FR' to prevent accidental resets
if (len < 2 || data[0] != 0x46 || data[1] != 0x52) {
ESP_LOGW("StateCommands", "Factory reset rejected: missing confirmation bytes 'FR'");
return false;
}
ESP_LOGW("StateCommands", "FACTORY RESET confirmed via BLE/serial");
// Notify clients before reset
uint8_t resp[2] = { 0xF2, 0x16 }; // CMD_SUCCESS + cmd id
ClientsManager::getInstance().notifyAllBinary(
NotificationType::State, resp, sizeof(resp));
// Give BLE time to send notification, then reset
vTaskDelay(pdMS_TO_TICKS(300));
ConfigManager::factoryReset(); // This will reboot
return true; // unreachable
}
// Receive settings update from app and persist
// Payload: [scannerRssi:int8][bruterPower:u8][delayLo:u8][delayHi:u8][bruterRepeats:u8]
static bool handleSettingsUpdate(const uint8_t* data, size_t len) {
if (len < 5) {
ESP_LOGW("StateCommands", "Insufficient data for settingsUpdate (%u < 5)", (unsigned)len);
return false;
}
if (!ConfigManager::updateFromBle(data, len)) {
ESP_LOGE("StateCommands", "Failed to update settings from BLE");
return false;
}
ESP_LOGI("StateCommands", "Settings updated from app: rssi=%d power=%d delay=%d reps=%d",
ConfigManager::settings.scannerRssi, ConfigManager::settings.bruterPower,
ConfigManager::settings.bruterDelay, ConfigManager::settings.bruterRepeats);
// Echo back the new settings to confirm sync
sendSettingsSync();
return true;
}
// Send firmware version info to all BLE clients.
// Payload: [0xC2][major][minor][patch] — 4 bytes total.
static void sendVersionInfo() {
BinaryVersionInfo vInfo;
vInfo.major = FIRMWARE_VERSION_MAJOR;
vInfo.minor = FIRMWARE_VERSION_MINOR;
vInfo.patch = FIRMWARE_VERSION_PATCH;
ClientsManager::getInstance().notifyAllBinary(
NotificationType::VersionInfo,
reinterpret_cast<const uint8_t*>(&vInfo), sizeof(vInfo));
ESP_LOGI("StateCommands", "VersionInfo sent: %d.%d.%d",
vInfo.major, vInfo.minor, vInfo.patch);
}
// Send current persistent settings to all BLE clients.
static void sendSettingsSync() {
uint8_t payload[8];
ConfigManager::buildSyncPayload(payload);
ClientsManager::getInstance().notifyAllBinary(
NotificationType::SettingsSync, payload, sizeof(payload));
ESP_LOGI("StateCommands", "SettingsSync sent: rssi=%d power=%d delay=%d reps=%d mod1=%d mod2=%d",
ConfigManager::settings.scannerRssi, ConfigManager::settings.bruterPower,
ConfigManager::settings.bruterDelay, ConfigManager::settings.bruterRepeats,
ConfigManager::settings.radioPowerMod1, ConfigManager::settings.radioPowerMod2);
}
// Send current BLE device name to all clients.
// Payload: [0xC7][nameLen:1][name...]
static void sendDeviceName() {
const char* name = ConfigManager::getDeviceName();
size_t nameLen = strlen(name);
uint8_t payload[2 + MAX_DEVICE_NAME_LEN];
payload[0] = MSG_DEVICE_NAME;
payload[1] = (uint8_t)nameLen;
memcpy(payload + 2, name, nameLen);
ClientsManager::getInstance().notifyAllBinary(
NotificationType::State, payload, 2 + nameLen);
ESP_LOGI("StateCommands", "DeviceName sent: %s", name);
}
// Check module existence
static bool moduleExists(uint8_t module) {
return module < CC1101_NUM_MODULES;
}
};
#endif