Initial public release of WII5 Buoy firmware
Firmware for an autonomous wave-measurement buoy (ATmega2560-based WII5 v2 board). Reads wave motion from a Sparton AHRS-M1/M2 IMU, samples GPS and battery state, and reports back over Iridium SBD satellite telemetry. Originally developed 2012-2024. This is the first public release. Code, documentation, and field-tested operating modes (Capture, Sleep, Position, ManualTest, SelfTest, LowBattery) are licensed under Apache 2.0 — see LICENSE and NOTICE. See README.md for an overview and build instructions, CONTRIBUTING.md for how to contribute, and DEPLOYMENTS.md for the field-deployment log.
This commit is contained in:
+239
@@ -0,0 +1,239 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright (c) 2012-2024 Scott Penrose <scottp@dd.com.au> 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 <WII5.h>
|
||||
|
||||
// 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
|
||||
Reference in New Issue
Block a user