Add BLE UART for channel configuration
This commit is contained in:
112
src/main.cpp
112
src/main.cpp
@@ -11,6 +11,7 @@
|
|||||||
#include <helpers/ArduinoSerialInterface.h>
|
#include <helpers/ArduinoSerialInterface.h>
|
||||||
#include <Crypto.h>
|
#include <Crypto.h>
|
||||||
#include <SHA256.h>
|
#include <SHA256.h>
|
||||||
|
#include <bluefruit.h>
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
|
||||||
using namespace Adafruit_LittleFS_Namespace;
|
using namespace Adafruit_LittleFS_Namespace;
|
||||||
@@ -49,39 +50,73 @@ static const unsigned long ALERT_COOLDOWN_MS = 600000;
|
|||||||
static unsigned long g_boot_time = 0;
|
static unsigned long g_boot_time = 0;
|
||||||
static bool g_startup_msg_sent = false;
|
static bool g_startup_msg_sent = false;
|
||||||
|
|
||||||
struct SecurityConfig { uint32_t magic; uint8_t armed; uint8_t relay2; };
|
|
||||||
static const uint32_t CFG_MAGIC = 0x53454355;
|
|
||||||
|
|
||||||
struct ChannelConfig { uint32_t magic; char name[32]; char password[32]; };
|
|
||||||
static const uint32_t CHAN_MAGIC = 0x4348414E;
|
|
||||||
|
|
||||||
static char g_channel_name[32] = "";
|
|
||||||
static char g_channel_pass[32] = "";
|
static char g_channel_pass[32] = "";
|
||||||
|
|
||||||
bool saveChannelConfig() {
|
bool saveChannelPass(const char* pass) {
|
||||||
ChannelConfig cfg;
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
|
||||||
cfg.magic = CHAN_MAGIC;
|
|
||||||
strncpy(cfg.name, g_channel_name, sizeof(cfg.name) - 1);
|
|
||||||
strncpy(cfg.password, g_channel_pass, sizeof(cfg.password) - 1);
|
|
||||||
File f = InternalFS.open(CHANNEL_FILE, FILE_O_WRITE);
|
File f = InternalFS.open(CHANNEL_FILE, FILE_O_WRITE);
|
||||||
if (!f) return false;
|
if (!f) return false;
|
||||||
bool ok = f.write((const uint8_t*)&cfg, sizeof(cfg)) == sizeof(cfg);
|
size_t len = strlen(pass);
|
||||||
|
if (len > 31) len = 31;
|
||||||
|
bool ok = f.write((const uint8_t*)pass, len) == len;
|
||||||
f.close(); return ok;
|
f.close(); return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadChannelConfig() {
|
bool loadChannelPass() {
|
||||||
File f = InternalFS.open(CHANNEL_FILE, FILE_O_READ);
|
File f = InternalFS.open(CHANNEL_FILE, FILE_O_READ);
|
||||||
if (!f) return false;
|
if (!f) return false;
|
||||||
ChannelConfig cfg;
|
int len = f.read((uint8_t*)g_channel_pass, sizeof(g_channel_pass) - 1);
|
||||||
if (f.read(&cfg, sizeof(cfg)) != sizeof(cfg)) { f.close(); return false; }
|
|
||||||
f.close();
|
f.close();
|
||||||
if (cfg.magic != CHAN_MAGIC) return false;
|
if (len > 0) { g_channel_pass[len] = 0; return true; }
|
||||||
strncpy(g_channel_name, cfg.name, sizeof(g_channel_name) - 1);
|
return false;
|
||||||
strncpy(g_channel_pass, cfg.password, sizeof(g_channel_pass) - 1);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLEUart bleuart;
|
||||||
|
|
||||||
|
void ble_send(const char* text) {
|
||||||
|
bleuart.println(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_ble() {
|
||||||
|
Bluefruit.begin(1, 0);
|
||||||
|
Bluefruit.setName("Security-Mesh");
|
||||||
|
Bluefruit.setTxPower(4);
|
||||||
|
bleuart.begin();
|
||||||
|
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||||
|
Bluefruit.Advertising.addTxPower();
|
||||||
|
Bluefruit.Advertising.addService(bleuart);
|
||||||
|
Bluefruit.ScanResponse.addName();
|
||||||
|
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||||
|
Bluefruit.Advertising.setInterval(32, 244);
|
||||||
|
Bluefruit.Advertising.start(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_ble_line(const char* line) {
|
||||||
|
if (strncmp(line, "channel ", 8) == 0) {
|
||||||
|
const char* pass = line + 8;
|
||||||
|
int len = strlen(pass);
|
||||||
|
if (len < 1 || len > 31) { ble_send("bad password length"); return; }
|
||||||
|
int digits = 0;
|
||||||
|
for (int i = 0; pass[i]; i++) if (pass[i] >= '0' && pass[i] <= '9') digits++;
|
||||||
|
if (digits != len) { ble_send("use digits only"); return; }
|
||||||
|
strncpy(g_channel_pass, pass, sizeof(g_channel_pass) - 1);
|
||||||
|
saveChannelPass(pass);
|
||||||
|
char r[64]; snprintf(r, sizeof(r), "channel %s saved, rebooting...", pass);
|
||||||
|
ble_send(r);
|
||||||
|
delay(100);
|
||||||
|
NVIC_SystemReset();
|
||||||
|
} else if (strcmp(line, "status") == 0) {
|
||||||
|
char r[64]; snprintf(r, sizeof(r), "channel: %s", g_channel_pass[0] ? g_channel_pass : "1234");
|
||||||
|
ble_send(r);
|
||||||
|
} else if (strcmp(line, "help") == 0) {
|
||||||
|
ble_send("commands: channel <password>, status, help");
|
||||||
|
} else {
|
||||||
|
ble_send("unknown. try help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SecurityConfig { uint32_t magic; uint8_t armed; uint8_t relay2; };
|
||||||
|
static const uint32_t CFG_MAGIC = 0x53454355;
|
||||||
|
|
||||||
bool saveSecurityConfig() {
|
bool saveSecurityConfig() {
|
||||||
SecurityConfig cfg = { CFG_MAGIC, g_armed ? 1 : 0, g_relay2_state ? 1 : 0 };
|
SecurityConfig cfg = { CFG_MAGIC, g_armed ? 1 : 0, g_relay2_state ? 1 : 0 };
|
||||||
File f = InternalFS.open(CONFIG_FILE, FILE_O_WRITE);
|
File f = InternalFS.open(CONFIG_FILE, FILE_O_WRITE);
|
||||||
@@ -179,7 +214,7 @@ public:
|
|||||||
while (*cmd == ' ') cmd++;
|
while (*cmd == ' ') cmd++;
|
||||||
|
|
||||||
if (strcmp(cmd, "help") == 0) {
|
if (strcmp(cmd, "help") == 0) {
|
||||||
defer_response("help:ohrana on,ohrana off,relay1 on,relay1 off,relay2 on,relay2 off,relay,status,ver,scan,canal");
|
defer_response("help:ohrana on,ohrana off,relay1 on,relay1 off,relay2 on,relay2 off,relay,status,ver,scan");
|
||||||
} else if (strcmp(cmd, "ohrana on") == 0) {
|
} else if (strcmp(cmd, "ohrana on") == 0) {
|
||||||
g_armed = true; digitalWrite(PIN_RELAY_1, LOW); saveSecurityConfig(); defer_response("ohrana on ok");
|
g_armed = true; digitalWrite(PIN_RELAY_1, LOW); saveSecurityConfig(); defer_response("ohrana on ok");
|
||||||
} else if (strcmp(cmd, "ohrana off") == 0) {
|
} else if (strcmp(cmd, "ohrana off") == 0) {
|
||||||
@@ -211,22 +246,6 @@ public:
|
|||||||
float sum = 0;
|
float sum = 0;
|
||||||
for (int j = 0; j < 20; j++) { sum += radio_driver.getCurrentRSSI(); delay(50); }
|
for (int j = 0; j < 20; j++) { sum += radio_driver.getCurrentRSSI(); delay(50); }
|
||||||
char r[32]; snprintf(r, sizeof(r), "noise:%.0fdBm", sum / 20); defer_response(r);
|
char r[32]; snprintf(r, sizeof(r), "noise:%.0fdBm", sum / 20); defer_response(r);
|
||||||
} else if (strncmp(cmd, "canal", 5) == 0) {
|
|
||||||
char buf[128]; strncpy(buf, cmd, sizeof(buf) - 1); buf[sizeof(buf) - 1] = 0;
|
|
||||||
char* rest = buf + 5; while (*rest == ' ') rest++;
|
|
||||||
char* cname = rest;
|
|
||||||
char* space = strchr(cname, ' ');
|
|
||||||
if (!space) { defer_response("need name and password"); return; }
|
|
||||||
*space = 0;
|
|
||||||
char* cpass = space + 1;
|
|
||||||
if (*cpass == 0) { defer_response("need name and password"); return; }
|
|
||||||
strncpy(g_channel_name, cname, sizeof(g_channel_name) - 1);
|
|
||||||
strncpy(g_channel_pass, cpass, sizeof(g_channel_pass) - 1);
|
|
||||||
saveChannelConfig();
|
|
||||||
char r[64]; snprintf(r, sizeof(r), "canal %s %s ok", cname, cpass);
|
|
||||||
send_text(r);
|
|
||||||
for (int i = 0; i < 5; i++) { digitalWrite(PIN_LED_STATUS, HIGH); delay(100); digitalWrite(PIN_LED_STATUS, LOW); delay(100); }
|
|
||||||
NVIC_SystemReset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -264,10 +283,12 @@ void setup() {
|
|||||||
|
|
||||||
InternalFS.begin();
|
InternalFS.begin();
|
||||||
loadSecurityConfig();
|
loadSecurityConfig();
|
||||||
loadChannelConfig();
|
loadChannelPass();
|
||||||
if (g_armed) digitalWrite(PIN_RELAY_1, LOW); else digitalWrite(PIN_RELAY_1, HIGH);
|
if (g_armed) digitalWrite(PIN_RELAY_1, LOW); else digitalWrite(PIN_RELAY_1, HIGH);
|
||||||
digitalWrite(PIN_RELAY_2, g_relay2_state ? LOW : HIGH);
|
digitalWrite(PIN_RELAY_2, g_relay2_state ? LOW : HIGH);
|
||||||
|
|
||||||
|
setup_ble();
|
||||||
|
|
||||||
if (!radio_init()) {
|
if (!radio_init()) {
|
||||||
Serial.println("RADIO FAIL");
|
Serial.println("RADIO FAIL");
|
||||||
while (1) { digitalWrite(PIN_LED_STATUS, HIGH); delay(100); digitalWrite(PIN_LED_STATUS, LOW); delay(100); }
|
while (1) { digitalWrite(PIN_LED_STATUS, HIGH); delay(100); digitalWrite(PIN_LED_STATUS, LOW); delay(100); }
|
||||||
@@ -287,6 +308,19 @@ void loop() {
|
|||||||
the_mesh.flush_response();
|
the_mesh.flush_response();
|
||||||
rtc_clock.tick();
|
rtc_clock.tick();
|
||||||
|
|
||||||
|
static char ble_line[64];
|
||||||
|
static int ble_pos = 0;
|
||||||
|
while (bleuart.available()) {
|
||||||
|
char c = bleuart.read();
|
||||||
|
if (c == '\n' || c == '\r') {
|
||||||
|
ble_line[ble_pos] = 0;
|
||||||
|
if (ble_pos > 0) process_ble_line(ble_line);
|
||||||
|
ble_pos = 0;
|
||||||
|
} else if (ble_pos < (int)sizeof(ble_line) - 1) {
|
||||||
|
ble_line[ble_pos++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_startup_msg_sent && millis() - g_boot_time >= 10000) {
|
if (!g_startup_msg_sent && millis() - g_boot_time >= 10000) {
|
||||||
g_startup_msg_sent = true;
|
g_startup_msg_sent = true;
|
||||||
char m[80]; snprintf(m, sizeof(m), "poweron %s %s", __DATE__, __TIME__);
|
char m[80]; snprintf(m, sizeof(m), "poweron %s %s", __DATE__, __TIME__);
|
||||||
|
|||||||
Reference in New Issue
Block a user