using GeoVLog.Core.Models; using System; namespace GeoVLog.Core.Parsers; /// /// Parser for FreeFlight RA-4500 radar-altimeter frames. /// Validates the frame structure, collapses DLE stuffing and checks the checksum. /// internal static class RadarAltParser { private const byte Dle = 0x10; private const byte Etx = 0x03; private const byte Id = 0xDF; private const byte Len = 0x03; public static bool TryParse(ReadOnlySpan msg, DateTime arrivalUtc, out RadarAltReading parsed) { parsed = default!; if (msg.Length < 5) return false; if (msg[0] != Dle || msg[^2] != Dle || msg[^1] != Etx) return false; Span buf = stackalloc byte[6]; int bi = 0; for (int i = 1; i < msg.Length - 2 && bi < buf.Length; i++) { byte b = msg[i]; if (b == Dle) { if (i + 1 >= msg.Length - 2 || msg[i + 1] != Dle) return false; // unexpected DLE not stuffed buf[bi++] = Dle; i++; // skip stuffed byte } else { buf[bi++] = b; } } if (bi != buf.Length) return false; if (buf[0] != Id || buf[1] != Len) return false; byte computed = 0; for (int i = 0; i < 5; i++) computed += buf[i]; computed = (byte)((~computed + 1) & 0xFF); if (computed != buf[5]) return false; ushort altitude = (ushort)((buf[2] << 8) | buf[3]); byte status = buf[4]; parsed = new RadarAltReading { TimestampUtc = arrivalUtc, RawPayload = msg.ToArray(), AltitudeFt = altitude, StatusByte = status }; return true; } }