File AxisCal.h
File List > Firmware > Libraries > SimGateway > AxisCal.h
Go to the documentation of this file
#pragma once
#include <stddef.h>
#include <stdint.h>
namespace OpenSkyhawk {
struct AxisCal {
uint16_t min;
uint16_t centre;
uint16_t max;
uint16_t deadzone;
};
constexpr uint8_t AXIS_CAL_SLOTS = 8;
constexpr uint32_t CAL_MAGIC = ((uint32_t)'O')
| ((uint32_t)'S' << 8)
| ((uint32_t)'K' << 16)
| ((uint32_t)'C' << 24);
constexpr uint16_t CAL_VERSION = 1;
struct CalBlob {
uint32_t magic;
uint16_t version;
AxisCal axes[AXIS_CAL_SLOTS];
uint16_t crc;
};
static_assert(sizeof(AxisCal) == 8, "AxisCal layout changed — bump CAL_VERSION");
static_assert(sizeof(CalBlob) == 72, "CalBlob layout changed — bump CAL_VERSION");
static_assert(offsetof(CalBlob, crc) == 70, "CRC coverage is offsetof(crc); layout changed");
uint16_t calCrc16(const uint8_t* data, size_t len);
bool axisCalValid(const AxisCal& cal);
uint16_t axisCalApply(const AxisCal& cal, uint16_t raw);
uint16_t calBlobCrc(const CalBlob& blob);
bool calBlobValid(const CalBlob& blob);
void calBlobClear(CalBlob& blob);
void calBlobSeal(CalBlob& blob);
// ── Calibration wire protocol ─────────────────────────────────────────────────
//
// The USB CDC protocol between SimGateway and SkyHawkClient. Specified in
// FirmwarePlan/03-uart-usb-hid-protocol.md § Calibration Protocol (USB CDC), which is
// authoritative — if this header disagrees with that page, the page wins.
//
// Only the pure parts live here: the length table, the frame builder, and whole-frame
// validation. The byte-at-a-time receive state machine belongs to SimGateway.cpp because
// it has to re-emit rejected bytes into the relay.
constexpr uint8_t CAL_PROTO_VERSION = 1;
constexpr uint8_t CAL_FRAME_MAGIC[4] = { 0xAA, 0x53, 0x4B, 0x43 }; // "\xAA S K C"
constexpr uint16_t CAL_ENVELOPE_BYTES = 10;
constexpr uint16_t CAL_MAX_PAYLOAD = 82;
constexpr uint16_t CAL_MAX_FRAME = CAL_ENVELOPE_BYTES + CAL_MAX_PAYLOAD; // 92
enum CalType : uint8_t {
CAL_T_HELLO = 0x01,
CAL_T_GET_CAL = 0x02,
CAL_T_SESSION_OPEN = 0x03,
CAL_T_SESSION_CLOSE = 0x04,
CAL_T_COMMIT = 0x05,
CAL_T_RESET = 0x06,
CAL_T_KEEPALIVE = 0x07,
CAL_T_STREAM_SELECT = 0x08,
CAL_T_HELLO_ACK = 0x81,
CAL_T_CAL_DATA = 0x82,
CAL_T_SESSION_ACK = 0x83,
CAL_T_ACK = 0x84,
CAL_T_NACK = 0x85,
CAL_T_RAW = 0x86,
};
enum CalNackReason : uint8_t {
CAL_NACK_BAD_CRC = 0x01,
CAL_NACK_BAD_LENGTH = 0x02,
CAL_NACK_BAD_TYPE = 0x03,
CAL_NACK_BAD_INDEX = 0x04,
CAL_NACK_BAD_ORDER = 0x05,
CAL_NACK_NO_SESSION = 0x06,
CAL_NACK_NO_STORAGE = 0x07,
CAL_NACK_BAD_DEADZONE = 0x08,
};
constexpr uint8_t CAL_AXIS_NONE = 0xFF;
bool calLenValidForType(uint8_t type, uint16_t len);
uint16_t calBuildFrame(uint8_t* out, uint16_t outCap,
uint8_t type, uint8_t seq,
const uint8_t* payload, uint16_t len);
bool calFrameCrcOk(const uint8_t* frame, uint16_t n);
} // namespace OpenSkyhawk