// SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2012-2024 Scott Penrose and WII5 Buoy contributors // // This file is part of WII5 Buoy firmware. // See LICENSE for full terms. /** * @file WII5BinData.h * @brief Binary message format for Iridium SBD: layout, packing, and split logic. */ #ifndef WII5BinData_h #define WII5BinData_h #include // Header Size = 15 typedef struct { // 0 uint16_t wii_binary_id; // Fixed ID for the old system - 60001 // 2 uint32_t bindata_type; // Which packet type is this. // 6 uint8_t bindata_packet; // Which part of the packet is this - note we don't need total, can claculate from type // Essential data to allow packets to be put back together // 7 uint32_t deviceId; // Ideally move back to uint32_t // 11 uint32_t recordCount; } WII5_BINDATA_HEADER; #define WII5_BINDATA_0_TEXT "Status,Temp,Volts,GPS" typedef struct { // uint8_t deviceId_SHORT; // Ideally move back to uint32_t uint32_t status; // Special status bit fields to tell us what is going on time_t last; int16_t voltage; // 0..16 with 2 decimal places -10000 .. + 10000 int16_t temperature; // -100 .. +100 with two decimal places 2452 uint8_t mode; float gps_lat; float gps_lon; // Ideally status - number or reboots/resets and other errors // How many messages sent, disk space and lots more. } WII5_BINDATA_0; #define WII5_BINDATA_1_TEXT "GPS Extended" // Detailed GPS data typedef struct { uint16_t lastRunTime; // Number of seconds to lock last time time_t when; // When we last got a time lock int16_t altitude; // Altitutde in meters uint8_t satellites; float hdop; } WII5_BINDATA_1; #define WII5_BINDATA_2_TEXT "Iridium Extended" // Detailed Iridium data typedef struct { uint16_t lastRunTime; // How long did the last one take uint8_t signalQuality; // uint32_t lastId; (the last id sent etc) // total_sent // total_received (I think the Iridium knows) // imei - very large } WII5_BINDATA_2; #define WII5_BINDATA_3_TEXT "Message - Small (<50 bytes)" // Commands - Tiny version typedef struct { uint32_t status; // Special status bit fields to tell us what is going on uint32_t command; // Commands as usual, top bit (32) is on for ACK uint8_t id; // Resposne must contain request id in case we have many uint8_t response; // TODO 2024 - This is a BREAKING CHANGE for any old buoys - could be fixed on WII3_Server BinData by supporting 30 or 25 text chars char message[25]; // On ACK/NACK it can contain error data... TODO 2024 Changed from 30 to 25 - where else / what else } WII5_BINDATA_3; #define WII5_BINDATA_4_TEXT "Message - large (< 300 bytes)" // Commands - full size version typedef struct { // uint32_t status; // Special status bit fields to tell us what is going on // uint32_t command; // Commands as usual, top bit (32) is on for ACK // uint8_t id; // uint8_t response; char message[235]; // On ACK/NACK it can contain error data // Here we may use this to send a script, by including in this // message tag - sh/1/3: - ie. write to shell script, Part 1 of 3 // Rest is concat to the end of the scipt } WII5_BINDATA_4; // TODO Idea - Results/Processed/Run sumary - HMO etc? #define WII5_BINDATA_5_TEXT "Extra Buoy Information" typedef struct { uint32_t runCount; uint32_t integerVersion; // 16 // char version[20]; } WII5_BINDATA_5; #define WII5_BINDATA_6_TEXT "Processed - QF" typedef struct { float qf_mvar; float qf_p_accel; // (gyro not being used) float qf_p_gyro; // (mag not being used) float qf_p_mag; // (kistler not being used) float qf_kist", // (kistler not being used) qf_p_kist", float qf_imu; float qf_head; float a; float b; } WII5_BINDATA_6; #define WII5_BINDATA_7_TEXT "Processed - _max" typedef struct { float tz_max[4]; float htm_max[4]; float hcm_max[4]; float hz_max[4]; } WII5_BINDATA_7; #define WII5_BINDATA_8_TEXT "WII5Processed1" typedef struct { WII5Processed1 processed1; } WII5_BINDATA_8; #define WII5_BINDATA_9_TEXT "WII5Processed2" typedef struct { WII5Processed2 processed2; } WII5_BINDATA_9; #define WII5_BINDATA_10_TEXT "WII5MetaDataObject" typedef struct { WII5MetaDataObject metadata; } WII5_BINDATA_10; // Processed - Direction #define WII5_BINDATA_11_TEXT "Processed - Direction array" typedef struct { int direction[54]; } WII5_BINDATA_11; #define WII5_BINDATA_12_TEXT "Processed - Misc and Quality" // Processed - Metadatas full (excluding kistler, mag, gyro) // TODO: trim BinData record set to active fields typedef struct { float hmo; float theta; float dp; float s; float r; float nstd; float f2; float yaw_std; float open_water; float power_diff; float tp; } WII5_BINDATA_12; // Moments #define WII5_BINDATA_13_TEXT "Processed - Moment array" typedef struct { float moments[7]; } WII5_BINDATA_13; // PSD #define WII5_BINDATA_14_TEXT "Processed - PSD array" typedef struct { float psd[55]; } WII5_BINDATA_14; typedef struct { } WII5_BINDATA_15; /** * @brief Binary message format for Iridium SBD. * * Each SBD message starts with a WII5_BINDATA_HEADER (binary id 60001, * record metadata, a 32-bit `bindata_type` bitmap), then a sequence of * fixed-size payload structs (WII5_BINDATA_0 .. _15) selected by which * bits are set in `bindata_type`. The `getSplit()` helper splits an * over-sized type bitmap across multiple 340-byte SBD frames. */ class WII5BinData { public: WII5BinData() {} /** @brief One-time bring-up. */ void begin(); /** @brief Pop the next chunk that fits in `max_size` bytes; advances start_bit. */ bool getSplit(uint32_t in_t, uint16_t max_size, uint8_t* start_bit, uint32_t* out_t); /** @brief Size of a single payload struct selected by bit `b`. */ uint16_t getSizeOne(uint8_t b); /** @brief Set bit `b` in `t` and return the modified value. */ uint16_t setBit(uint32_t t, uint8_t b); /** @brief Total wire size for a type bitmap, including the header. */ uint16_t getSize(uint32_t t); /** @brief Total payload size for a type bitmap, excluding the header. */ uint16_t getSizeObj(uint32_t t); /** @brief Initialize a binary buffer with header for type `t`. */ bool createData(uint32_t t, void* buf, uint16_t maxSize, uint32_t recordCount = 0); /** @brief Fill the payload structs in `buf` from live device state. */ bool setData(uint32_t t, void* buf, uint16_t maxSize); /** @brief Fill the payload structs from a pre-loaded SD metadata block. */ bool setBlockMetadata(uint32_t t, void* buf, uint16_t maxSize, WII5MetaDataObject* metadata); /** @brief Fill the payload structs from a pre-loaded SD results (processed) block. */ bool setBlockResults(uint32_t t, void* buf, uint16_t maxSize, WII5Processed* processed); /** @brief Print a human-readable dump of the buffer to the console. */ void dumpData(void* buf, uint16_t maxSize, bool values); /** @brief Print the size of every BinData payload type. */ void showSizes(char* bufout = NULL, uint16_t bufsize = 0); /** @brief Print the split sequence for a given type bitmap. */ void showSplit(uint32_t in_t, uint16_t max_size, char* bufout = NULL, uint16_t bufsize = 0); /** @brief Human-readable title for payload bit `bit`. */ char* strTitle(uint8_t bit, bool ext); /** @brief Does this buffer's header type-bitmap include bit `bit`? */ bool hasType(uint8_t bit, void* buf, uint16_t maxSize); /** @brief Pointer to the payload struct for bit `bit` inside `buf`. */ void* getData(uint8_t bit, void* buf, uint16_t maxSize); /** @brief Validate header and return pointer to the embedded command struct. */ WII5_BINDATA_3* getCommand(void* buf, uint16_t maxSize); /** @brief Print the list of bits set in a type bitmap. */ void showBlocks(uint32_t t); protected: bool testDone; }; extern WII5BinData wii5BinData; #endif