Packet Parsing
Overview
The ground station browser receives raw bytes from the GS Pico MCU via USB CDC serial. Since USB CDC does not preserve packet boundaries, the browser must buffer incoming data and parse packet boundaries itself.
Data Flow
Satellite Radio TX → GS Pico MCU Radio RX → USB CDC → Browser WebSerial Reader
│
┌───────▼────────┐
│ dataBuffer │
│ (Uint8Array) │
└───────┬────────┘
│
┌───────▼────────┐
│ Packet Router │
│ (identifier) │
└───────┬────────┘
│
┌───────────────┬───────┼───────────────┐
▼ ▼ ▼ ▼
Binary Packet SEND/RETX OBCP/OBCL Text Line
(fixed size) (newline) (newline) (newline)
Buffering Strategy
All incoming bytes are appended to a dataBuffer (Uint8Array). The parser then attempts to extract complete packets from the front of the buffer:
// Append new data
const newBuffer = new Uint8Array(dataBuffer.length + value.length);
newBuffer.set(dataBuffer);
newBuffer.set(value, dataBuffer.length);
dataBuffer = newBuffer;
// Parse loop - extract packets until buffer is exhausted
while (dataBuffer.length >= 4) {
const identifier = decode first 4 bytes;
// Route based on identifier...
}
Packet Types and Parsing
Fixed-Size Binary Packets
Known identifiers with fixed sizes are extracted directly:
const packetSizes = {
'GYRO': 16, 'ACCL': 16, 'MAGN': 16, 'GRAV': 16, 'EULR': 16,
'BME2': 16, 'TEMP': 8, 'QUAT': 20,
'OBCR': 8, 'OBCD': 8, 'OBCC': 8,
'ADCS': 32, 'EPSS': 28, 'HOST': 15, 'SOLR': 36,
'XFRC': 8, 'BECN': 24
};
If the buffer doesn't contain enough bytes for the expected packet size, parsing pauses until more data arrives.
Newline-Delimited Packets
SEND, RETX, OBCP, and OBCL packets use newline (\n) as the delimiter. The parser scans for 0x0A or 0x0D after the 4-byte identifier:
if (identifier === 'SEND' || identifier === 'RETX' ||
identifier === 'OBCP' || identifier === 'OBCL') {
// Find newline position
let newlinePos = -1;
for (let i = 4; i < dataBuffer.length; i++) {
if (dataBuffer[i] === 0x0A || dataBuffer[i] === 0x0D) {
newlinePos = i;
break;
}
}
if (newlinePos > 4) {
const packet = dataBuffer.slice(0, newlinePos);
// Route to appropriate handler...
// Advance buffer past newline(s)
} else {
break; // Wait for more data
}
}
This approach correctly handles USB CDC fragmentation — if a packet arrives split across multiple USB reads, the parser waits until the newline delimiter arrives before processing.
Variable-Length Binary Packets
POLL and PHOT packets have variable sizes indicated by a length field in the packet header. They are handled as special cases in the parser.
Text Lines
Unrecognized data (no matching identifier) is treated as a text line, parsed until a newline, and logged to the event log.
Radio Configuration Parsing
Configuration responses from the GS Pico MCU use a special buffering mode. When a CONFIG: prefix is detected, the browser accumulates lines until parsing is complete, then updates the radio configuration UI.
LED Blinking
On each received packet, the browser blinks the appropriate LED indicator and flashes the GSB downlink monitor:
blinkLED('rfm95RxLed', 100); // Also flashes monDownlink
On each sent command:
blinkLED('rfm95TxLed', 100); // Also flashes monUplink
The LED type (rfm95 vs rfm69) is determined by the current radio configuration.
Error Handling
- Incomplete packets: Parser breaks and waits for more data
- Unknown identifiers: Logged as debug, data treated as text
- Oversized buffers: Stale data is periodically cleaned
- Disconnection: Reader loop catches errors, calls
updateConnectionStatus(false)