Files

157 lines
5.2 KiB
C++

#include <ArduinoJson.h>
#include <HardwareSerial.h>
#include "sensor_node_receiver.h"
namespace {
constexpr int SENSOR_NODE_RS485_RX_PIN = 43;
constexpr int SENSOR_NODE_RS485_TX_PIN = 44;
constexpr uint32_t SENSOR_NODE_RS485_BAUD = 115200;
constexpr size_t SENSOR_NODE_RS485_MAX_LINE = 1900;
constexpr size_t SENSOR_NODE_RS485_RX_BUFFER = 4096;
constexpr unsigned long SENSOR_NODE_STALE_MS = 1500;
HardwareSerial sensorNodeSerial(1);
SensorNodeDashboardStatus sensorNodeStatus;
String receiveLine;
bool discardUntilNewline = false;
bool sequenceInitialized = false;
void recordSequence(uint32_t bootId, uint32_t sequence) {
if (!sequenceInitialized || bootId != sensorNodeStatus.bootId) {
if (sequenceInitialized && bootId != sensorNodeStatus.bootId) {
sensorNodeStatus.nodeRestarts++;
}
sensorNodeStatus.bootId = bootId;
sensorNodeStatus.frameSequence = sequence;
sequenceInitialized = true;
return;
}
uint32_t delta = sequence - sensorNodeStatus.frameSequence;
if (delta > 1 && delta < 0x80000000UL) {
sensorNodeStatus.framesDropped += delta - 1;
}
sensorNodeStatus.frameSequence = sequence;
}
void parseSensorNodeFrame(const String &line) {
StaticJsonDocument<3072> doc;
DeserializationError error = deserializeJson(doc, line);
if (error) {
sensorNodeStatus.parseErrors++;
return;
}
const char *type = doc["type"] | "";
if (strcmp(type, "sensor_status") != 0 || (int)(doc["schema_version"] | 0) != 1) {
return;
}
uint32_t bootId = doc["boot_id"] | 0;
uint32_t sequence = doc["frame_sequence"] | 0;
recordSequence(bootId, sequence);
JsonObject imu = doc["imu"];
sensorNodeStatus.imuOnline = imu["online"] | false;
sensorNodeStatus.imuValid = imu["valid"] | false;
sensorNodeStatus.imuAccuracy = imu["accuracy"] | 0;
sensorNodeStatus.stability = String((const char *)(imu["stability"] | "unknown"));
sensorNodeStatus.yawDegrees = imu["yaw_degrees"] | 0.0f;
JsonObject level = imu["level_calibration"];
sensorNodeStatus.levelCalibrationValid = level["valid"] | false;
sensorNodeStatus.pitchDegrees = sensorNodeStatus.levelCalibrationValid
? (float)(level["pitch_degrees"] | 0.0f)
: (float)(imu["pitch_degrees"] | 0.0f);
sensorNodeStatus.rollDegrees = sensorNodeStatus.levelCalibrationValid
? (float)(level["roll_degrees"] | 0.0f)
: (float)(imu["roll_degrees"] | 0.0f);
JsonObject gps = doc["gps"];
sensorNodeStatus.gpsOnline = gps["online"] | false;
sensorNodeStatus.gpsFix = gps["fix"] | false;
sensorNodeStatus.satellites = gps["satellites"] | 0;
sensorNodeStatus.hdop = gps["hdop"].isNull() ? 0 : (float)gps["hdop"];
sensorNodeStatus.latitude = gps["latitude"] | 0.0;
sensorNodeStatus.longitude = gps["longitude"] | 0.0;
sensorNodeStatus.altitudeMeters = gps["altitude_meters"] | 0.0f;
sensorNodeStatus.speedKph = gps["speed_kph"] | 0.0f;
JsonObject utc = gps["utc"];
if (!utc.isNull() && (int)(utc["year"] | 0) > 0) {
char utcBuffer[24];
snprintf(
utcBuffer,
sizeof(utcBuffer),
"%04d-%02d-%02d %02d:%02d:%02dZ",
(int)(utc["year"] | 0),
(int)(utc["month"] | 0),
(int)(utc["day"] | 0),
(int)(utc["hour"] | 0),
(int)(utc["minute"] | 0),
(int)(utc["second"] | 0)
);
sensorNodeStatus.utcTime = utcBuffer;
} else {
sensorNodeStatus.utcTime = "";
}
sensorNodeStatus.firmwareVersion = String((const char *)(doc["firmware_version"] | ""));
sensorNodeStatus.frameReceived = true;
sensorNodeStatus.framesReceived++;
sensorNodeStatus.lastFrameMs = millis();
}
}
void initSensorNodeRs485() {
receiveLine.reserve(SENSOR_NODE_RS485_MAX_LINE);
sensorNodeSerial.setRxBufferSize(SENSOR_NODE_RS485_RX_BUFFER);
sensorNodeSerial.begin(
SENSOR_NODE_RS485_BAUD,
SERIAL_8N1,
SENSOR_NODE_RS485_RX_PIN,
SENSOR_NODE_RS485_TX_PIN
);
Serial.println("Sensor node RS485: RX GPIO43 / TX GPIO44 @ 115200");
}
void processSensorNodeRs485() {
while (sensorNodeSerial.available() > 0) {
char value = (char)sensorNodeSerial.read();
sensorNodeStatus.bytesReceived++;
sensorNodeStatus.lastByteMs = millis();
if (value == '\r') continue;
if (value != '\n') {
if (discardUntilNewline) continue;
if (receiveLine.length() < SENSOR_NODE_RS485_MAX_LINE) {
receiveLine += value;
} else {
receiveLine = "";
discardUntilNewline = true;
sensorNodeStatus.oversizedFrames++;
}
continue;
}
if (discardUntilNewline) {
discardUntilNewline = false;
receiveLine = "";
continue;
}
if (receiveLine.length() > 0) {
parseSensorNodeFrame(receiveLine);
}
receiveLine = "";
}
}
bool sensorNodeRs485Connected() {
return sensorNodeStatus.frameReceived &&
millis() - sensorNodeStatus.lastFrameMs <= SENSOR_NODE_STALE_MS;
}
const SensorNodeDashboardStatus &getSensorNodeStatus() {
return sensorNodeStatus;
}