Files
scottp 295abb37ee 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.
2026-05-07 16:27:18 +10:00

634 lines
19 KiB
C++

// 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.cpp
* @brief Binary message format for Iridium SBD: layout, packing, and split logic.
*/
/*
WII5BinData - Simple utitlity class to create and manage binary data for Iridium
How to manage the type requested. If it needs splitting, how to do, store etc.
NOTE: LSB 0
*/
#include <WII5BinData.h>
void WII5BinData::begin() {
}
// getSize - Literally the size of the object including the headers
uint16_t WII5BinData::getSize(uint32_t t) {
return sizeof(WII5_BINDATA_HEADER) + getSizeObj(t);
}
uint16_t WII5BinData::getSizeOne(uint8_t b) {
switch(b) {
case 0:
return sizeof(WII5_BINDATA_0); break;
case 1:
return sizeof(WII5_BINDATA_1); break;
case 2:
return sizeof(WII5_BINDATA_2); break;
case 3:
return sizeof(WII5_BINDATA_3); break;
case 4:
return sizeof(WII5_BINDATA_4); break;
case 5:
return sizeof(WII5_BINDATA_5); break;
case 6:
return sizeof(WII5_BINDATA_6); break;
case 7:
return sizeof(WII5_BINDATA_7); break;
case 8:
return sizeof(WII5_BINDATA_8); break;
case 9:
return sizeof(WII5_BINDATA_9); break;
case 10:
return sizeof(WII5_BINDATA_10); break;
case 11:
return sizeof(WII5_BINDATA_11); break;
case 12:
return sizeof(WII5_BINDATA_12); break;
case 13:
return sizeof(WII5_BINDATA_13); break;
case 14:
return sizeof(WII5_BINDATA_14); break;
case 15:
return sizeof(WII5_BINDATA_15); break;
};
return 0;
}
/*
Starting with a type of B01001011
uint8_t nextBit = 0;
uint32_t outType = 0;
uint32_t t = B01001011;
uint8_t count = 0;
while (getSplit(t, 300, &nextBit, %outType)) {
console.printf(F("Splitting #=%d, original type=%lu, new type=%lu, size=%d, nextBit=%d\r\n")
count, t, outType, getSize(outType), int(nextBit)
);
count++;
}
There should be no overlapping bits at the end of this
*/
bool WII5BinData::getSplit(uint32_t in_t, uint16_t max_size, uint8_t* start_bit, uint32_t* out_t) {
uint16_t ret_size = 0;
uint16_t part_size = 0;
ret_size = sizeof(WII5_BINDATA_HEADER);
*out_t = 0;
// TODO fix max bits
for (uint8_t b = *start_bit; b < 16; b++) {
if (BitVal(in_t, b)) {
part_size = getSizeOne(b);
if ((ret_size + part_size) > max_size) {
// That is it, we can't do any more.
*start_bit = b;
// NOTE: This is an error condition
if (*out_t == 0) {
console.log(LOG_FATAL, F("BinData: Failed to split BinData to this size"));
return false;
}
else
return true;
}
else {
SetBit(*out_t, b);
ret_size += part_size;
}
}
}
*start_bit = 16;
// Check if we have anything left
if (*out_t == 0)
return false;
else
return true;
}
uint16_t WII5BinData::setBit(uint32_t t, uint8_t b) {
SetBit(t, b);
return t;
}
// getSizeObj - The individual objects, added together but no header
uint16_t WII5BinData::getSizeObj(uint32_t t) {
uint16_t ret = 0;
for (uint8_t b = 0; b < 16; b++) {
if (BitVal(t, b))
ret += getSizeOne(b);
}
return ret;
}
// Create Data is called first - to initialize the Buffer
bool WII5BinData::createData(uint32_t t, void* buf, uint16_t maxSize, uint32_t recordCount) {
memset(buf, 0, maxSize);
WII5_BINDATA_HEADER* local = (WII5_BINDATA_HEADER*)buf;
// Set the Header
local->wii_binary_id = 60001; // Fixed ID for the old system - 60001
local->bindata_type = t; // Which packet type is this.
local->bindata_packet = 0; // 0 means only?
// NOTE:
local->deviceId = wii5Config.getDeviceId();
// Custom recordCount (eg. we are sending something old, else current)
if (recordCount > 0)
local->recordCount = recordCount;
else
local->recordCount = wii5Config.getRecordCount();
/*
console.log(LOG_DEBUG, F("*** (1) binary id = %d, binary type = %lu, packet = %d, recordCount = %lu, deviceId = %lu"),
local->wii_binary_id, local->bindata_type, int(local->bindata_packet), local->recordCount, local->deviceId
);
*/
}
// setData - literlaly set the data
// - However, it pulls data live from devices, therefore you need next to get old data
// - setBlockMetadata - Use a block to set the Metadata values
// - setBlockResults - Set the block for the results values
bool WII5BinData::setData(uint32_t t, void* buf, uint16_t maxSize) {
char* ptr = (char*)buf;
if (getSize(t) > maxSize) {
console.log(LOG_FATAL, F("BinData: Standard Data too big for buger provided. Try splitting."));
return false;
}
{
WII5_BINDATA_HEADER* local = (WII5_BINDATA_HEADER*)ptr;
if ( (local->wii_binary_id != 60001) || (local->bindata_type != t) ) {
// TODO fix the %d here, should be unsigned.
console.log(LOG_DEBUG, F("*** (2) binary id = %d, binary type = %lu, packet = %d, recordCount = %lu, deviceId = %lu"),
local->wii_binary_id, local->bindata_type, int(local->bindata_packet), local->recordCount, local->deviceId
);
console.log(LOG_FATAL, F("BinData: *** INTERNAL ERROR *** setData called without valid header first"));
}
}
// Header
ptr += sizeof(WII5_BINDATA_HEADER);
if (BitVal(t, 0)) {
WII5_BINDATA_0* local = (WII5_BINDATA_0*)ptr;
if (wii5Weather_18B20.age < (WII5TIME_12HOUR * 1000))
local->temperature = wii5Weather_18B20.value;
else
local->temperature = 25500; // TODO Hard coded
if (wii5Battery.age < (WII5TIME_12HOUR * 1000))
local->voltage = wii5Battery.value;
else
local->voltage = 25500; // TODO Hard coded
local->last = now();
local->mode = wii5Controller.getMode();
// TODO Check valid ???
local->gps_lat = wii5Gps.gps->location.lat();
local->gps_lon = wii5Gps.gps->location.lng();
ptr += sizeof(WII5_BINDATA_0);
}
if (BitVal(t, 1)) {
WII5_BINDATA_1* local = (WII5_BINDATA_1*)ptr;
local->altitude = wii5Gps.gps->altitude.meters();
local->hdop = wii5Gps.gps->hdop.value();
local->satellites = wii5Gps.gps->satellites.value();
local->when = wii5Gps.when;
local->lastRunTime = wii5Gps.lastRunTime;
ptr += sizeof(WII5_BINDATA_1);
}
if (BitVal(t, 2)) {
WII5_BINDATA_2* local = (WII5_BINDATA_2*)ptr;
// TODO 2024 - signalQuality ?
ptr += sizeof(WII5_BINDATA_2);
}
if (BitVal(t, 3)) {
WII5_BINDATA_3* local = (WII5_BINDATA_3*)ptr;
local->status = 0; // Special status bit fields to tell us what is going on
local->command = wii5Commands.lastCommandCmd; // Commands as usual, top bit (32) is on for ACK
// TODO local->id = wii5Commands.lastCommandId; // Resposne must contain request id in case we have many
local->id = 0;
local->response = wii5Commands.lastCommandResult;
strncpy(local->message, wii5Commands.lastCommandMessage, sizeof(local->message));
ptr += sizeof(WII5_BINDATA_3);
}
if (BitVal(t, 4)) {
WII5_BINDATA_4* local = (WII5_BINDATA_4*)ptr;
strncpy(local->message, wii5Commands.lastCommandMessage, sizeof(local->message));
ptr += sizeof(WII5_BINDATA_4);
}
if (BitVal(t, 5)) {
WII5_BINDATA_5* local = (WII5_BINDATA_5*)ptr;
local->runCount = sh3dNodeConfig.getRunCount();
local->integerVersion = WII5_SOFTWARE_INTVER;
ptr += sizeof(WII5_BINDATA_5);
}
if (BitVal(t, 6)) {
ptr += sizeof(WII5_BINDATA_6);
}
if (BitVal(t, 7)) {
ptr += sizeof(WII5_BINDATA_7);
}
if (BitVal(t, 8)) {
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 9)) {
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 10)) {
ptr += sizeof(WII5_BINDATA_10);
}
if (BitVal(t, 11)) {
ptr += sizeof(WII5_BINDATA_11);
}
if (BitVal(t, 12)) {
ptr += sizeof(WII5_BINDATA_12);
}
if (BitVal(t, 13)) {
ptr += sizeof(WII5_BINDATA_13);
}
if (BitVal(t, 14)) {
ptr += sizeof(WII5_BINDATA_14);
}
if (BitVal(t, 15)) {
ptr += sizeof(WII5_BINDATA_15);
}
return true;
}
bool WII5BinData::setBlockMetadata(uint32_t t, void* buf, uint16_t maxSize, WII5MetaDataObject* metadata) {
if (getSize(t) > maxSize) {
console.log(LOG_FATAL, F("BinData: Results Object too big for buger provided. Try splitting."));
return false;
}
char* ptr = (char*)buf;
ptr += sizeof(WII5_BINDATA_HEADER);
if (BitVal(t, 0)) {
WII5_BINDATA_0* local = (WII5_BINDATA_0*)ptr;
local->temperature = metadata->temperatureValue;
local->voltage = metadata->batteryValue;
local->mode = metadata->mode;
local->gps_lat = metadata->gpsLat;
local->gps_lon = metadata->gpsLon;
ptr += sizeof(WII5_BINDATA_0);
}
if (BitVal(t, 1)) {
WII5_BINDATA_1* local = (WII5_BINDATA_1*)ptr;
/*
local->altitude = wii5Gps.gps->altitude.meters();
local->hdop = wii5Gps.gps->hdop.value();
local->satellites = wii5Gps.gps->satellites.value();
local->when = wii5Gps.when;
local->lastRunTime = wii5Gps.lastRunTime;
*/
ptr += sizeof(WII5_BINDATA_1);
}
if (BitVal(t, 2)) {
ptr += sizeof(WII5_BINDATA_2);
}
if (BitVal(t, 3)) {
WII5_BINDATA_3* local = (WII5_BINDATA_3*)ptr;
ptr += sizeof(WII5_BINDATA_3);
}
if (BitVal(t, 4)) {
ptr += sizeof(WII5_BINDATA_4);
}
if (BitVal(t, 5)) {
ptr += sizeof(WII5_BINDATA_5);
}
if (BitVal(t, 6)) {
ptr += sizeof(WII5_BINDATA_6);
}
if (BitVal(t, 7)) {
ptr += sizeof(WII5_BINDATA_7);
}
if (BitVal(t, 8)) {
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 9)) {
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 10)) {
ptr += sizeof(WII5_BINDATA_10);
}
if (BitVal(t, 11)) {
ptr += sizeof(WII5_BINDATA_11);
}
if (BitVal(t, 12)) {
ptr += sizeof(WII5_BINDATA_12);
}
if (BitVal(t, 13)) {
ptr += sizeof(WII5_BINDATA_13);
}
if (BitVal(t, 14)) {
ptr += sizeof(WII5_BINDATA_14);
}
if (BitVal(t, 15)) {
ptr += sizeof(WII5_BINDATA_15);
}
}
bool WII5BinData::setBlockResults(uint32_t t, void* buf, uint16_t maxSize, WII5Processed* processed) {
char* ptr = (char*)buf;
ptr += sizeof(WII5_BINDATA_HEADER);
if (BitVal(t, 0)) { ptr += sizeof(WII5_BINDATA_0); }
if (BitVal(t, 1)) { ptr += sizeof(WII5_BINDATA_1); }
if (BitVal(t, 2)) { ptr += sizeof(WII5_BINDATA_2); }
if (BitVal(t, 3)) { ptr += sizeof(WII5_BINDATA_3); }
if (BitVal(t, 4)) { ptr += sizeof(WII5_BINDATA_4); }
if (BitVal(t, 5)) { ptr += sizeof(WII5_BINDATA_5); }
if (BitVal(t, 6)) { ptr += sizeof(WII5_BINDATA_6); }
// processed1
if (BitVal(t, 7)) {
WII5_BINDATA_7* local = (WII5_BINDATA_7*)ptr;
/* local->tz_max[4]; local->htm_max[4]; local->hcm_max[4]; local->hz_max[4]; */
memcpy(local, &processed->processed1, sizeof(float) * 16); // 4 groups of floats
ptr += sizeof(WII5_BINDATA_7);
}
// processed1
if (BitVal(t, 8)) {
WII5_BINDATA_8* local = (WII5_BINDATA_8*)ptr;
local->processed1 = processed->processed1;
ptr += sizeof(WII5_BINDATA_8);
}
// processed2
if (BitVal(t, 9)) {
WII5_BINDATA_9* local = (WII5_BINDATA_9*)ptr;
local->processed2 = processed->processed2;
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 11)) {
WII5_BINDATA_11* local = (WII5_BINDATA_11*)ptr;
memcpy(&local->direction, &processed->processed2.part2int[8], sizeof(int16_t) * 54);
ptr += sizeof(WII5_BINDATA_11);
}
if (BitVal(t, 12)) {
WII5_BINDATA_12* local = (WII5_BINDATA_12*)ptr;
ptr += sizeof(WII5_BINDATA_12);
}
if (BitVal(t, 13)) {
WII5_BINDATA_13* local = (WII5_BINDATA_13*)ptr;
memcpy(&local->moments, &processed->processed2.part2float[0], sizeof(float) * 7);
ptr += sizeof(WII5_BINDATA_13);
}
if (BitVal(t, 14)) {
WII5_BINDATA_14* local = (WII5_BINDATA_14*)ptr;
memcpy(&local->psd, &processed->processed1.part1float[18], sizeof(float) * 55);
ptr += sizeof(WII5_BINDATA_14);
}
}
WII5_BINDATA_3* WII5BinData::getCommand(void* buf, uint16_t maxSize) {
uint32_t t = 0;
SetBit(t, 3);
char* ptr = (char*)buf;
{
WII5_BINDATA_HEADER* local = (WII5_BINDATA_HEADER*)ptr;
if (local->wii_binary_id != 60001) {
console.log(LOG_WARN, F("BinData - not a valid header"));
return NULL;
}
// Should upport multiple, but simplistic for now
if (local->bindata_type != t) {
console.log(LOG_WARN, F("BinData - could not find valid command"));
return NULL;
}
ptr += sizeof(WII5_BINDATA_HEADER);
}
console.log(LOG_INFO, F("BinData - found valid command"));
return (WII5_BINDATA_3*)ptr;
}
// dumpData - show the data to the console for debugging
void WII5BinData::dumpData(void* buf, uint16_t maxSize, bool values) {
uint32_t t = 0;
char* ptr = (char*)buf;
{
WII5_BINDATA_HEADER* local = (WII5_BINDATA_HEADER*)ptr;
// local->wii_binary_id = 60001;
t = local->bindata_type;
ptr += sizeof(WII5_BINDATA_HEADER);
console.printf(F("# BinData Header found\r\n"));
console.printf(F("# deviceId = %lu\r\n"), local->deviceId);
console.printf(F("# recordCount = %lu\r\n"), local->recordCount);
}
if (BitVal(t, 0)) {
WII5_BINDATA_0* local = (WII5_BINDATA_0*)ptr;
console.printf(F("# BinData 0 - title=%s\r\n"), strTitle(0, false));
if (values) {
console.printf(F("# temperature = %d\r\n"), int(local->temperature));
console.printf(F("# voltage = %d\r\n"), int(local->voltage));
console.printf(F("# last = %ld\r\n"), long(local->last));
console.printf(F("# mode = %d\r\n"), int(local->mode));
console.printf(F("# gps_lat = %ld\r\n"), long(local->gps_lat * GPS_POS_MULT));
console.printf(F("# gps_lon = %ld\r\n"), long(local->gps_lon * GPS_POS_MULT));
}
ptr += sizeof(WII5_BINDATA_0);
}
if (BitVal(t, 1)) {
WII5_BINDATA_1* local = (WII5_BINDATA_1*)ptr;
console.printf(F("# BinData 1 - title=%s\r\n"), strTitle(1, false));
if (values) {
console.printf(F("# gps_altitude = %ld\r\n"), long(local->altitude));
console.printf(F("# gps_hdop = %d\r\n"), int(local->hdop));
console.printf(F("# gps_satellites = %d\r\n"), int(local->satellites));
console.printf(F("# gps_when = %ld\r\n"), long(local->when));
console.printf(F("# gps_lastRunTime = %ld\r\n"), long(local->lastRunTime));
}
ptr += sizeof(WII5_BINDATA_1);
}
if (BitVal(t, 2)) {
WII5_BINDATA_2* local = (WII5_BINDATA_2*)ptr;
console.printf(F("# BinData 2 - title=%s\r\n"), strTitle(2, false));
if (values) {
console.printf(F("# lastRunTime = %d\r\n"), int(local->lastRunTime));
console.printf(F("# signalQuality = %d\r\n"), int(local->signalQuality));
}
ptr += sizeof(WII5_BINDATA_2);
}
if (BitVal(t, 3)) {
console.printf(F("# BinData 3 - title=%s\r\n"), strTitle(3, false));
ptr += sizeof(WII5_BINDATA_3);
}
if (BitVal(t, 4)) {
console.printf(F("# BinData 4 - title=%s\r\n"), strTitle(4, false));
ptr += sizeof(WII5_BINDATA_4);
}
if (BitVal(t, 5)) {
console.printf(F("# BinData 5 - title=%s\r\n"), strTitle(5, false));
ptr += sizeof(WII5_BINDATA_5);
}
if (BitVal(t, 6)) {
console.printf(F("# BinData 6 - title=%s\r\n"), strTitle(6, false));
ptr += sizeof(WII5_BINDATA_6);
}
if (BitVal(t, 7)) {
console.printf(F("# BinData 7 - title=%s\r\n"), strTitle(7, false));
ptr += sizeof(WII5_BINDATA_7);
}
if (BitVal(t, 8)) {
console.printf(F("# BinData 8 - title=%s\r\n"), strTitle(8, false));
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 9)) {
console.printf(F("# BinData 9 - title=%s\r\n"), strTitle(9, false));
ptr += sizeof(WII5_BINDATA_8);
}
if (BitVal(t, 10)) {
console.printf(F("# BinData 10 - title=%s\r\n"), strTitle(10, false));
ptr += sizeof(WII5_BINDATA_10);
}
if (BitVal(t, 11)) {
console.printf(F("# BinData 11 - title=%s\r\n"), strTitle(11, false));
ptr += sizeof(WII5_BINDATA_11);
}
if (BitVal(t, 12)) {
console.printf(F("# BinData 12 - title=%s\r\n"), strTitle(12, false));
ptr += sizeof(WII5_BINDATA_12);
}
if (BitVal(t, 13)) {
console.printf(F("# BinData 13 - title=%s\r\n"), strTitle(13, false));
ptr += sizeof(WII5_BINDATA_13);
}
if (BitVal(t, 14)) {
console.printf(F("# BinData 14 - title=%s\r\n"), strTitle(14, false));
ptr += sizeof(WII5_BINDATA_14);
}
if (BitVal(t, 15)) {
console.printf(F("# BinData 15 - title=%s\r\n"), strTitle(15, false));
ptr += sizeof(WII5_BINDATA_15);
}
}
void WII5BinData::showBlocks(uint32_t t) {
console.printf(F("BinData Type=%lu, Blocks="), t);
for (uint8_t b = 0; b < 16; b++) {
if (BitVal(t, b)) {
console.printf(F("%d, "), int(b));
}
}
console.printf(F(" size=%d"), getSize(t));
}
void WII5BinData::showSplit(uint32_t in_t, uint16_t max_size, char* bufout, uint16_t bufsize) {
uint8_t nextBit = 0;
uint32_t outType = 0;
// TODO: also fill bufout/bufsize with the split summary so callers receive
// structured data, not just console output.
(void)bufout; (void)bufsize;
console.printf(F("# Orig "));
showBlocks(in_t);
console.printNewLine();
uint8_t count = 0;
while (getSplit(in_t, max_size, &nextBit, &outType)) {
console.printf(F("# New %d "), count);
showBlocks(outType);
console.printNewLine();
count++;
if (count > 25) {
console.log(LOG_FATAL, F("BinData: More than 25 splits, not supported"));
return;
}
}
}
// showSizes - all sizes to console.
void WII5BinData::showSizes(char* bufout, uint16_t bufsize) {
console.printf(F("# BinData Size overhead=%d\r\n"), sizeof(WII5_BINDATA_HEADER));
// TODO: also fill bufout/bufsize with the size summary so callers receive
// structured data, not just console output.
(void)bufout; (void)bufsize;
for (uint8_t x = 0; x < 16; x++) {
console.printf(F("# BinData Size bit=%d, size=%d, title=%s\r\n"),
int(x),
getSizeOne(x),
strTitle(x, false)
);
if (getSizeOne(x) > 300) {
console.printf(F("# *** WARNING *** Packet > 300 bytes ***\r\n"));
}
}
}
// strTitle - get the title for this object
char* WII5BinData::strTitle(uint8_t bit, bool ext) {
switch(bit) {
case 0: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_0_TEXT)); break;
case 1: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_1_TEXT)); break;
case 2: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_2_TEXT)); break;
case 3: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_3_TEXT)); break;
case 4: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_4_TEXT)); break;
case 5: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_5_TEXT)); break;
case 6: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_6_TEXT)); break;
case 7: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_7_TEXT)); break;
case 8: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_8_TEXT)); break;
case 9: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_9_TEXT)); break;
case 10: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_10_TEXT)); break;
case 11: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_11_TEXT)); break;
case 12: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_12_TEXT)); break;
case 13: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_13_TEXT)); break;
case 14: strcpy_P(wii5BufferString ,(PGM_P) F(WII5_BINDATA_14_TEXT)); break;
default: strcpy_P(wii5BufferString, (PGM_P) F("unknown")); break;
};
return wii5BufferString;
}
bool WII5BinData::hasType(uint8_t bit, void* buf, uint16_t maxSize) {
// TODO Check bit
}
void* WII5BinData::getData(uint8_t bit, void* buf, uint16_t maxSize) {
// Find location in buffer
}
WII5BinData wii5BinData;