117 lines
3 KiB
C++
117 lines
3 KiB
C++
// firmware/fieldtest_beacon/src/main.cpp
|
|
// 20260212 ChatGPT
|
|
// $Id$
|
|
// $HeadURL$
|
|
|
|
#include <Arduino.h>
|
|
#include <SPI.h>
|
|
#include <SD.h>
|
|
#include "Boards.h"
|
|
|
|
// Include microReticulum headers from your external tree
|
|
#include "Identity.h"
|
|
#include "Reticulum.h"
|
|
#include "Destination.h"
|
|
#include "Transport.h"
|
|
|
|
// ---------- User-tunable ----------
|
|
static const uint32_t BEACON_INTERVAL_MS = 15000;
|
|
static const char* PATH_IDENTITY_BIN = "/provisioning/identity.bin";
|
|
static const char* PATH_LABEL_TXT = "/provisioning/label.txt";
|
|
static const char* LOG_PATH = "/logs/fieldtest.log";
|
|
|
|
// ---------- Globals ----------
|
|
static uint32_t g_iter = 0;
|
|
static uint32_t g_next_tx = 0;
|
|
static File g_log;
|
|
|
|
// Source board pin mapping from microReticulum_Firmware board definitions.
|
|
static const int SD_CS_PIN = SD_CS;
|
|
|
|
// Simple line logger (append-only)
|
|
static void log_line(const String& line) {
|
|
if (!g_log) return;
|
|
g_log.println(line);
|
|
g_log.flush();
|
|
}
|
|
|
|
// Read whole file into a buffer
|
|
static bool read_file(const char* path, std::vector<uint8_t>& out) {
|
|
File f = SD.open(path, FILE_READ);
|
|
if (!f) return false;
|
|
size_t n = f.size();
|
|
out.resize(n);
|
|
if (n > 0) f.read(out.data(), n);
|
|
f.close();
|
|
return true;
|
|
}
|
|
|
|
static String read_text_file(const char* path) {
|
|
File f = SD.open(path, FILE_READ);
|
|
if (!f) return String("");
|
|
String s = f.readString();
|
|
f.close();
|
|
s.trim();
|
|
return s;
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
delay(250);
|
|
|
|
// ---- SD init ----
|
|
if (!SD.begin(SD_CS_PIN)) {
|
|
Serial.println("SD init failed");
|
|
return;
|
|
}
|
|
|
|
g_log = SD.open(LOG_PATH, FILE_APPEND);
|
|
if (!g_log) {
|
|
Serial.println("Failed to open log file");
|
|
return;
|
|
}
|
|
|
|
const String label = read_text_file(PATH_LABEL_TXT);
|
|
log_line("BOOT\tlabel=" + label);
|
|
|
|
std::vector<uint8_t> id_bytes;
|
|
if (!read_file(PATH_IDENTITY_BIN, id_bytes)) {
|
|
log_line(String("ERROR\tmissing_identity\tpath=") + PATH_IDENTITY_BIN);
|
|
return;
|
|
}
|
|
log_line(String("IDENTITY_OK\tbytes=") + id_bytes.size());
|
|
|
|
// ---- Load Identity into microReticulum ----
|
|
// TODO: adjust to the actual API in your microReticulum version
|
|
// Example intent:
|
|
// Identity ident = Identity::fromBytes(id_bytes.data(), id_bytes.size());
|
|
// Reticulum rns;
|
|
// rns.setIdentity(ident);
|
|
// rns.begin(...);
|
|
//
|
|
// Also: initialize your LoRa Interface and attach it to Reticulum here.
|
|
|
|
log_line("RNS_INIT_OK");
|
|
|
|
g_next_tx = millis() + 3000; // wait a moment before first TX
|
|
}
|
|
|
|
void loop() {
|
|
// TODO: run microReticulum polling / tick function, and radio interface polling
|
|
|
|
const uint32_t now = millis();
|
|
if ((int32_t)(now - g_next_tx) >= 0) {
|
|
g_next_tx = now + BEACON_INTERVAL_MS;
|
|
|
|
// Build payload: timestamp + iterator (GPS later)
|
|
const uint32_t epoch_guess = (uint32_t) (time(nullptr)); // placeholder; GPS later
|
|
const String payload = String("t=") + epoch_guess + " i=" + g_iter++;
|
|
|
|
// TODO: send to peer(s) (Destination derived from peers list)
|
|
// bool ok = destination.send(payload_bytes, len);
|
|
|
|
log_line(String("TX\t") + payload);
|
|
}
|
|
|
|
delay(5);
|
|
}
|