I'm sorry for the inconsistency, it was a copy-paste error on my end:
BE EF 05 03 00 59 00 00 01 EF BE is actually BE EF 05 03 00 59 00 00 00 01 EF BE. (All packets of type 0x03 have three 0x00-bytes which I just call reserved bytes).
Unfortunately the protocol itself doesn't directly tell us which data type we're dealing with, so I had to go through the tedious process of manually identifying all existing entities and possible values.
I ended up with:
#include <Arduino.h>
#include <unordered_map>
enum packet_type : uint8_t {
ACK = 0x01,
ENTITY = 0x03,
UNKNOWN_04 = 0x04,
UNKNOWN_05 = 0x05,
DATA_REQUEST = 0x06,
UNKNOWN_15 = 0x15,
UNKNOWN_16 = 0x16,
TUNER_TOGGLE = 0x18,
TUNER_FEEDBACK = 0x19,
SNAPSHOT = 0x1A,
SD_CARD_EVENT = 0x1E,
HEARTBEAT = 0xFF
};
enum entity_data_type : uint8_t {
BOOL = 0,
UINT8 = 1,
FLOAT = 2,
};
enum entity_id : uint8_t {
FRONT_LED = 0,
FEEDBACK_ELIM = 1,
AMP_PA_MODE = 2,
LOCATION_MODE = 3,
SELECTED_CHAN = 4,
INPUT1_GAIN = 5,
INPUT1_VOLUME = 6,
INPUT1_MUTE = 7,
INPUT1_CLIP_OL_PRE = 8,
INPUT1_CLIP_OL_POST = 9,
INPUT1_EFFECT_1_MUTE = 10,
INPUT1_EFFECT_1_AMOUNT = 11,
INPUT1_EFFECT_2_MUTE = 12,
INPUT1_EFFECT_2_AMOUNT = 13,
INPUT1_EQ_ENABLE = 14,
INPUT1_EQ_LOW_GAIN = 15,
INPUT1_EQ_MID_GAIN = 16,
INPUT1_EQ_HIGH_GAIN = 17,
INPUT1_COMPRESSOR_ENABLE = 18,
INPUT1_COMPRESSOR_AMOUNT = 19,
INPUT1_EXT_FX_MUTE = 20,
INPUT1_EXT_FX_SENDS = 21,
INPUT2_GAIN = 22,
INPUT2_VOLUME = 23,
INPUT2_MUTE = 24,
INPUT2_CLIP_OL_PRE = 25,
INPUT2_CLIP_OL_POST = 26,
INPUT2_EFFECT_1_MUTE = 27,
INPUT2_EFFECT_1_AMOUNT = 28,
INPUT2_EFFECT_2_MUTE = 29,
INPUT2_EFFECT_2_AMOUNT = 30,
INPUT2_EQ_ENABLE = 31,
INPUT2_EQ_LOW_GAIN = 32,
INPUT2_EQ_MID_GAIN = 33,
INPUT2_EQ_HIGH_GAIN = 34,
INPUT2_COMPRESSOR_ENABLE = 35,
INPUT2_COMPRESSOR_AMOUNT = 36,
INPUT2_EXT_FX_MUTE = 37,
INPUT2_EXT_FX_SENDS = 38,
INPUT3_GAIN = 39,
INPUT3_VOLUME = 40,
INPUT3_MUTE = 41,
INPUT3_CLIP_OL_PRE = 42,
INPUT3_CLIP_OL_POST = 43,
INPUT3_EFFECT_1_MUTE = 44,
INPUT3_EFFECT_1_AMOUNT = 45,
INPUT3_EFFECT_2_MUTE = 46,
INPUT3_EFFECT_2_AMOUNT = 47,
INPUT3_EQ_ENABLE = 48,
INPUT3_EQ_LOW_GAIN = 49,
INPUT3_EQ_MID_GAIN = 50,
INPUT3_EQ_HIGH_GAIN = 51,
INPUT3_COMPRESSOR_ENABLE = 52,
INPUT3_COMPRESSOR_AMOUNT = 53,
INPUT3_EXT_FX_MUTE = 54,
INPUT3_EXT_FX_SENDS = 55,
INPUT4_GAIN = 56,
INPUT4_VOLUME = 57,
INPUT4_MUTE = 58,
INPUT4_CLIP_OL_PRE = 59,
INPUT4_CLIP_OL_POST = 60,
INPUT4_EFFECT_1_MUTE = 61,
INPUT4_EFFECT_1_AMOUNT = 62,
INPUT4_EFFECT_2_MUTE = 63,
INPUT4_EFFECT_2_AMOUNT = 64,
INPUT4_EQ_ENABLE = 65,
INPUT4_EQ_LOW_GAIN = 66,
INPUT4_EQ_MID_GAIN = 67,
INPUT4_EQ_HIGH_GAIN = 68,
INPUT4_COMPRESSOR_ENABLE = 69,
INPUT4_COMPRESSOR_AMOUNT = 70,
INPUT4_EXT_FX_MUTE = 71,
INPUT4_EXT_FX_SENDS = 72,
STEREO_INPUT1_VOLUME = 73,
STEREO_INPUT1_MUTE = 74,
STEREO_INPUT1_CLIP_OL_PRE = 75,
STEREO_INPUT1_CLIP_OL_POST = 76,
STEREO_INPUT1_EQ_ENABLE = 77,
STEREO_INPUT1_EQ_LOW_GAIN = 78,
STEREO_INPUT1_EQ_MID_GAIN = 79,
STEREO_INPUT1_EQ_HIGH_GAIN = 80,
EFFECT11_TYPEID = 81,
EFFECT12_TYPEID = 82,
EFFECT13_TYPEID = 83,
EFFECT14_TYPEID = 84,
EFFECT21_TYPEID = 85,
EFFECT22_TYPEID = 86,
MAIN_HEADPHONE_GAIN = 87,
MAIN_MASTER_GAIN = 88,
MAIN_MUTE = 89,
MAIN_CLIP_OL = 90,
LOOPER_LEVEL = 91,
LOOPER_STATE = 92,
FX_BYPASS = 93
};
std::unordered_map<entity_id, entity_data_type> entity_type_mapping = {
{FRONT_LED, BOOL},
{FEEDBACK_ELIM, UINT8},
{AMP_PA_MODE, BOOL},
{LOCATION_MODE, BOOL},
{SELECTED_CHAN, UINT8},
{INPUT1_GAIN, FLOAT},
{INPUT1_VOLUME, FLOAT},
{INPUT1_MUTE, BOOL},
{INPUT1_CLIP_OL_PRE, BOOL},
{INPUT1_CLIP_OL_POST, BOOL},
{INPUT1_EFFECT_1_MUTE, BOOL},
{INPUT1_EFFECT_1_AMOUNT, FLOAT},
{INPUT1_EFFECT_2_MUTE, BOOL},
{INPUT1_EFFECT_2_AMOUNT, FLOAT},
{INPUT1_EQ_ENABLE, BOOL},
{INPUT1_EQ_LOW_GAIN, FLOAT},
{INPUT1_EQ_MID_GAIN, FLOAT},
{INPUT1_EQ_HIGH_GAIN, FLOAT},
{INPUT1_COMPRESSOR_ENABLE, BOOL},
{INPUT1_COMPRESSOR_AMOUNT, FLOAT},
{INPUT1_EXT_FX_MUTE, BOOL},
{INPUT1_EXT_FX_SENDS, FLOAT},
{INPUT2_GAIN, FLOAT},
{INPUT2_VOLUME, FLOAT},
{INPUT2_MUTE, BOOL},
{INPUT2_CLIP_OL_PRE, BOOL},
{INPUT2_CLIP_OL_POST, BOOL},
{INPUT2_EFFECT_1_MUTE, BOOL},
{INPUT2_EFFECT_1_AMOUNT, FLOAT},
{INPUT2_EFFECT_2_MUTE, BOOL},
{INPUT2_EFFECT_2_AMOUNT, FLOAT},
{INPUT2_EQ_ENABLE, BOOL},
{INPUT2_EQ_LOW_GAIN, FLOAT},
{INPUT2_EQ_MID_GAIN, FLOAT},
{INPUT2_EQ_HIGH_GAIN, FLOAT},
{INPUT2_COMPRESSOR_ENABLE, BOOL},
{INPUT2_COMPRESSOR_AMOUNT, FLOAT},
{INPUT2_EXT_FX_MUTE, BOOL},
{INPUT2_EXT_FX_SENDS, FLOAT},
{INPUT3_GAIN, FLOAT},
{INPUT3_VOLUME, FLOAT},
{INPUT3_MUTE, BOOL},
{INPUT3_CLIP_OL_PRE, BOOL},
{INPUT3_CLIP_OL_POST, BOOL},
{INPUT3_EFFECT_1_MUTE, BOOL},
{INPUT3_EFFECT_1_AMOUNT, FLOAT},
{INPUT3_EFFECT_2_MUTE, BOOL},
{INPUT3_EFFECT_2_AMOUNT, FLOAT},
{INPUT3_EQ_ENABLE, BOOL},
{INPUT3_EQ_LOW_GAIN, FLOAT},
{INPUT3_EQ_MID_GAIN, FLOAT},
{INPUT3_EQ_HIGH_GAIN, FLOAT},
{INPUT3_COMPRESSOR_ENABLE, BOOL},
{INPUT3_COMPRESSOR_AMOUNT, FLOAT},
{INPUT3_EXT_FX_MUTE, BOOL},
{INPUT3_EXT_FX_SENDS, FLOAT},
{INPUT4_GAIN, FLOAT},
{INPUT4_VOLUME, FLOAT},
{INPUT4_MUTE, BOOL},
{INPUT4_CLIP_OL_PRE, BOOL},
{INPUT4_CLIP_OL_POST, BOOL},
{INPUT4_EFFECT_1_MUTE, BOOL},
{INPUT4_EFFECT_1_AMOUNT, FLOAT},
{INPUT4_EFFECT_2_MUTE, BOOL},
{INPUT4_EFFECT_2_AMOUNT, FLOAT},
{INPUT4_EQ_ENABLE, BOOL},
{INPUT4_EQ_LOW_GAIN, FLOAT},
{INPUT4_EQ_MID_GAIN, FLOAT},
{INPUT4_EQ_HIGH_GAIN, FLOAT},
{INPUT4_COMPRESSOR_ENABLE, BOOL},
{INPUT4_COMPRESSOR_AMOUNT, FLOAT},
{INPUT4_EXT_FX_MUTE, BOOL},
{INPUT4_EXT_FX_SENDS, FLOAT},
{STEREO_INPUT1_VOLUME, FLOAT},
{STEREO_INPUT1_MUTE, BOOL},
{STEREO_INPUT1_CLIP_OL_PRE, BOOL},
{STEREO_INPUT1_CLIP_OL_POST, BOOL},
{STEREO_INPUT1_EQ_ENABLE, BOOL},
{STEREO_INPUT1_EQ_LOW_GAIN, FLOAT},
{STEREO_INPUT1_EQ_MID_GAIN, FLOAT},
{STEREO_INPUT1_EQ_HIGH_GAIN, FLOAT},
{EFFECT11_TYPEID, UINT8},
{EFFECT12_TYPEID, UINT8},
{EFFECT13_TYPEID, UINT8},
{EFFECT14_TYPEID, UINT8},
{EFFECT21_TYPEID, UINT8},
{EFFECT22_TYPEID, UINT8},
{MAIN_HEADPHONE_GAIN, FLOAT},
{MAIN_MASTER_GAIN, FLOAT},
{MAIN_MUTE, BOOL},
{MAIN_CLIP_OL, BOOL},
{LOOPER_LEVEL, FLOAT},
{LOOPER_STATE, UINT8},
{FX_BYPASS, BOOL}
};
and then based on the great suggestion of kenb4, I was planning on doing something like this:
void handlePacket(uint8_t *raw_packet) {
switch (raw_packet[3]) { // packet_type
case ENTITY:
switch (entity_type_mapping[raw_packet[5]]) { // entity_type_mapping[entity_id]
case BOOL:
{
// ...
}
case UINT8:
{
// ...
}
case FLOAT:
{
// ...
}
}
break;
default:
break;
}
}
But I'm more than open to suggestions on how to do this better. Evidently I have a lot to learn when it comes to C++ and best-practices.
My entire proof-of-concept sketch looks like this at the moment:
#include <Arduino.h>
#include <unordered_map>
enum packet_type : uint8_t {
ACK = 0x01,
ENTITY = 0x03,
UNKNOWN_04 = 0x04,
UNKNOWN_05 = 0x05,
DATA_REQUEST = 0x06,
UNKNOWN_15 = 0x15,
UNKNOWN_16 = 0x16,
TUNER_TOGGLE = 0x18,
TUNER_FEEDBACK = 0x19,
SNAPSHOT = 0x1A,
SD_CARD_EVENT = 0x1E,
HEARTBEAT = 0xFF
};
enum entity_data_type : uint8_t {
BOOL = 0,
UINT8 = 1,
FLOAT = 2,
};
enum entity_id : uint8_t {
FRONT_LED = 0,
FEEDBACK_ELIM = 1,
AMP_PA_MODE = 2,
LOCATION_MODE = 3,
SELECTED_CHAN = 4,
INPUT1_GAIN = 5,
INPUT1_VOLUME = 6,
INPUT1_MUTE = 7,
INPUT1_CLIP_OL_PRE = 8,
INPUT1_CLIP_OL_POST = 9,
INPUT1_EFFECT_1_MUTE = 10,
INPUT1_EFFECT_1_AMOUNT = 11,
INPUT1_EFFECT_2_MUTE = 12,
INPUT1_EFFECT_2_AMOUNT = 13,
INPUT1_EQ_ENABLE = 14,
INPUT1_EQ_LOW_GAIN = 15,
INPUT1_EQ_MID_GAIN = 16,
INPUT1_EQ_HIGH_GAIN = 17,
INPUT1_COMPRESSOR_ENABLE = 18,
INPUT1_COMPRESSOR_AMOUNT = 19,
INPUT1_EXT_FX_MUTE = 20,
INPUT1_EXT_FX_SENDS = 21,
INPUT2_GAIN = 22,
INPUT2_VOLUME = 23,
INPUT2_MUTE = 24,
INPUT2_CLIP_OL_PRE = 25,
INPUT2_CLIP_OL_POST = 26,
INPUT2_EFFECT_1_MUTE = 27,
INPUT2_EFFECT_1_AMOUNT = 28,
INPUT2_EFFECT_2_MUTE = 29,
INPUT2_EFFECT_2_AMOUNT = 30,
INPUT2_EQ_ENABLE = 31,
INPUT2_EQ_LOW_GAIN = 32,
INPUT2_EQ_MID_GAIN = 33,
INPUT2_EQ_HIGH_GAIN = 34,
INPUT2_COMPRESSOR_ENABLE = 35,
INPUT2_COMPRESSOR_AMOUNT = 36,
INPUT2_EXT_FX_MUTE = 37,
INPUT2_EXT_FX_SENDS = 38,
INPUT3_GAIN = 39,
INPUT3_VOLUME = 40,
INPUT3_MUTE = 41,
INPUT3_CLIP_OL_PRE = 42,
INPUT3_CLIP_OL_POST = 43,
INPUT3_EFFECT_1_MUTE = 44,
INPUT3_EFFECT_1_AMOUNT = 45,
INPUT3_EFFECT_2_MUTE = 46,
INPUT3_EFFECT_2_AMOUNT = 47,
INPUT3_EQ_ENABLE = 48,
INPUT3_EQ_LOW_GAIN = 49,
INPUT3_EQ_MID_GAIN = 50,
INPUT3_EQ_HIGH_GAIN = 51,
INPUT3_COMPRESSOR_ENABLE = 52,
INPUT3_COMPRESSOR_AMOUNT = 53,
INPUT3_EXT_FX_MUTE = 54,
INPUT3_EXT_FX_SENDS = 55,
INPUT4_GAIN = 56,
INPUT4_VOLUME = 57,
INPUT4_MUTE = 58,
INPUT4_CLIP_OL_PRE = 59,
INPUT4_CLIP_OL_POST = 60,
INPUT4_EFFECT_1_MUTE = 61,
INPUT4_EFFECT_1_AMOUNT = 62,
INPUT4_EFFECT_2_MUTE = 63,
INPUT4_EFFECT_2_AMOUNT = 64,
INPUT4_EQ_ENABLE = 65,
INPUT4_EQ_LOW_GAIN = 66,
INPUT4_EQ_MID_GAIN = 67,
INPUT4_EQ_HIGH_GAIN = 68,
INPUT4_COMPRESSOR_ENABLE = 69,
INPUT4_COMPRESSOR_AMOUNT = 70,
INPUT4_EXT_FX_MUTE = 71,
INPUT4_EXT_FX_SENDS = 72,
STEREO_INPUT1_VOLUME = 73,
STEREO_INPUT1_MUTE = 74,
STEREO_INPUT1_CLIP_OL_PRE = 75,
STEREO_INPUT1_CLIP_OL_POST = 76,
STEREO_INPUT1_EQ_ENABLE = 77,
STEREO_INPUT1_EQ_LOW_GAIN = 78,
STEREO_INPUT1_EQ_MID_GAIN = 79,
STEREO_INPUT1_EQ_HIGH_GAIN = 80,
EFFECT11_TYPEID = 81,
EFFECT12_TYPEID = 82,
EFFECT13_TYPEID = 83,
EFFECT14_TYPEID = 84,
EFFECT21_TYPEID = 85,
EFFECT22_TYPEID = 86,
MAIN_HEADPHONE_GAIN = 87,
MAIN_MASTER_GAIN = 88,
MAIN_MUTE = 89,
MAIN_CLIP_OL = 90,
LOOPER_LEVEL = 91,
LOOPER_STATE = 92,
FX_BYPASS = 93
};
std::unordered_map<entity_id, entity_data_type> entity_type_mapping = {
{FRONT_LED, BOOL},
{FEEDBACK_ELIM, UINT8},
{AMP_PA_MODE, BOOL},
{LOCATION_MODE, BOOL},
{SELECTED_CHAN, UINT8},
{INPUT1_GAIN, FLOAT},
{INPUT1_VOLUME, FLOAT},
{INPUT1_MUTE, BOOL},
{INPUT1_CLIP_OL_PRE, BOOL},
{INPUT1_CLIP_OL_POST, BOOL},
{INPUT1_EFFECT_1_MUTE, BOOL},
{INPUT1_EFFECT_1_AMOUNT, FLOAT},
{INPUT1_EFFECT_2_MUTE, BOOL},
{INPUT1_EFFECT_2_AMOUNT, FLOAT},
{INPUT1_EQ_ENABLE, BOOL},
{INPUT1_EQ_LOW_GAIN, FLOAT},
{INPUT1_EQ_MID_GAIN, FLOAT},
{INPUT1_EQ_HIGH_GAIN, FLOAT},
{INPUT1_COMPRESSOR_ENABLE, BOOL},
{INPUT1_COMPRESSOR_AMOUNT, FLOAT},
{INPUT1_EXT_FX_MUTE, BOOL},
{INPUT1_EXT_FX_SENDS, FLOAT},
{INPUT2_GAIN, FLOAT},
{INPUT2_VOLUME, FLOAT},
{INPUT2_MUTE, BOOL},
{INPUT2_CLIP_OL_PRE, BOOL},
{INPUT2_CLIP_OL_POST, BOOL},
{INPUT2_EFFECT_1_MUTE, BOOL},
{INPUT2_EFFECT_1_AMOUNT, FLOAT},
{INPUT2_EFFECT_2_MUTE, BOOL},
{INPUT2_EFFECT_2_AMOUNT, FLOAT},
{INPUT2_EQ_ENABLE, BOOL},
{INPUT2_EQ_LOW_GAIN, FLOAT},
{INPUT2_EQ_MID_GAIN, FLOAT},
{INPUT2_EQ_HIGH_GAIN, FLOAT},
{INPUT2_COMPRESSOR_ENABLE, BOOL},
{INPUT2_COMPRESSOR_AMOUNT, FLOAT},
{INPUT2_EXT_FX_MUTE, BOOL},
{INPUT2_EXT_FX_SENDS, FLOAT},
{INPUT3_GAIN, FLOAT},
{INPUT3_VOLUME, FLOAT},
{INPUT3_MUTE, BOOL},
{INPUT3_CLIP_OL_PRE, BOOL},
{INPUT3_CLIP_OL_POST, BOOL},
{INPUT3_EFFECT_1_MUTE, BOOL},
{INPUT3_EFFECT_1_AMOUNT, FLOAT},
{INPUT3_EFFECT_2_MUTE, BOOL},
{INPUT3_EFFECT_2_AMOUNT, FLOAT},
{INPUT3_EQ_ENABLE, BOOL},
{INPUT3_EQ_LOW_GAIN, FLOAT},
{INPUT3_EQ_MID_GAIN, FLOAT},
{INPUT3_EQ_HIGH_GAIN, FLOAT},
{INPUT3_COMPRESSOR_ENABLE, BOOL},
{INPUT3_COMPRESSOR_AMOUNT, FLOAT},
{INPUT3_EXT_FX_MUTE, BOOL},
{INPUT3_EXT_FX_SENDS, FLOAT},
{INPUT4_GAIN, FLOAT},
{INPUT4_VOLUME, FLOAT},
{INPUT4_MUTE, BOOL},
{INPUT4_CLIP_OL_PRE, BOOL},
{INPUT4_CLIP_OL_POST, BOOL},
{INPUT4_EFFECT_1_MUTE, BOOL},
{INPUT4_EFFECT_1_AMOUNT, FLOAT},
{INPUT4_EFFECT_2_MUTE, BOOL},
{INPUT4_EFFECT_2_AMOUNT, FLOAT},
{INPUT4_EQ_ENABLE, BOOL},
{INPUT4_EQ_LOW_GAIN, FLOAT},
{INPUT4_EQ_MID_GAIN, FLOAT},
{INPUT4_EQ_HIGH_GAIN, FLOAT},
{INPUT4_COMPRESSOR_ENABLE, BOOL},
{INPUT4_COMPRESSOR_AMOUNT, FLOAT},
{INPUT4_EXT_FX_MUTE, BOOL},
{INPUT4_EXT_FX_SENDS, FLOAT},
{STEREO_INPUT1_VOLUME, FLOAT},
{STEREO_INPUT1_MUTE, BOOL},
{STEREO_INPUT1_CLIP_OL_PRE, BOOL},
{STEREO_INPUT1_CLIP_OL_POST, BOOL},
{STEREO_INPUT1_EQ_ENABLE, BOOL},
{STEREO_INPUT1_EQ_LOW_GAIN, FLOAT},
{STEREO_INPUT1_EQ_MID_GAIN, FLOAT},
{STEREO_INPUT1_EQ_HIGH_GAIN, FLOAT},
{EFFECT11_TYPEID, UINT8},
{EFFECT12_TYPEID, UINT8},
{EFFECT13_TYPEID, UINT8},
{EFFECT14_TYPEID, UINT8},
{EFFECT21_TYPEID, UINT8},
{EFFECT22_TYPEID, UINT8},
{MAIN_HEADPHONE_GAIN, FLOAT},
{MAIN_MASTER_GAIN, FLOAT},
{MAIN_MUTE, BOOL},
{MAIN_CLIP_OL, BOOL},
{LOOPER_LEVEL, FLOAT},
{LOOPER_STATE, UINT8},
{FX_BYPASS, BOOL}
};
template <typename T>
void printRawPacket(const char* message, T *packet) {
Serial.print(message);
Serial.print(": ");
auto rawBytes = reinterpret_cast<uint8_t *>(packet);
for (int i = 4 /* skip vtable */; i < sizeof(T); i++) {
Serial.printf("%02X ", rawBytes[i]);
}
Serial.println();
}
template <uint8_t type, typename T>
struct Packet {
uint8_t start_seq[2] {0xBE, 0xEF};
uint8_t body_size {sizeof(T) - 1};
uint8_t packet_type {type};
T p;
uint8_t end_seq[2] {0xEF, 0xBE};
void importP(const uint8_t *raw_packet) {
memcpy(&p, raw_packet + 4, sizeof(T));
}
void exportP(uint8_t *raw_packet) {
memcpy(raw_packet + 4, &p, sizeof(T));
}
virtual void intercept() = 0;
void handle(uint8_t *raw_packet) {
// printRawPacket("before", this);
importP(raw_packet);
// printRawPacket("import", this);
intercept();
// printRawPacket("export", this);
exportP(raw_packet);
}
} __attribute__((packed));
struct StateOnlyNoBody {
uint8_t state;
} __attribute__((packed));
// Example: BE EF 00 1E 02 EF BE
typedef Packet<SD_CARD_EVENT, StateOnlyNoBody> SdCardEventPacket;
// Example: BE EF 01 18 01 02 EF BE
struct ToggleTunerBody {
uint8_t state;
uint8_t channel;
} __attribute__((packed));
typedef Packet<TUNER_TOGGLE, ToggleTunerBody> ToggleTunerPacket;
// Example: BE EF 01 1A 01 04 EF BE
struct SnapshotBody {
uint8_t action;
uint8_t slot;
} __attribute__((packed));
typedef Packet<SNAPSHOT, SnapshotBody> SnapshotPacket;
template <uint8_t id, typename T>
struct EntityBody {
uint8_t header_byte {0};
uint8_t entity_id {id};
uint8_t reserved[3] {0};
T value;
} __attribute__((packed));
// Example: BE EF 05 03 00 59 00 00 00 01 EF BE
typedef Packet<ENTITY, EntityBody<BOOL, bool>> BoolEntityPacket;
// Example: BE EF 05 03 00 5C 00 00 00 04 EF BE
typedef Packet<ENTITY, EntityBody<UINT8, uint8_t>> Uint8EntityPacket;
// Example: BE EF 08 03 00 58 00 00 00 00 00 C0 40 EF BE
typedef Packet<ENTITY, EntityBody<FLOAT, float>> FloatEntityPacket;
struct QuarterFloatEntityPacket : Packet<ENTITY, EntityBody<FLOAT, float>> {
void intercept() override {
p.value *= 0.25;
}
};
struct InvertBoolEntityPacket : Packet<ENTITY, EntityBody<BOOL, bool>> {
void intercept() override {
p.value = !p.value;
}
};
struct IncrementUint8EntityPacket : Packet<ENTITY, EntityBody<UINT8, uint8_t>> {
void intercept() override {
p.value++;
}
};
void handlePacket(uint8_t *raw_packet) {
packet_type packetType = static_cast<packet_type>(raw_packet[3]);
switch (packetType) {
case ENTITY:
entity_id entityId = static_cast<entity_id>(raw_packet[5]);
entity_data_type entityType = entity_type_mapping[entityId];
Serial.printf("PacketType: %02X, EntityId: %02X, EntityType: %02X\n", packetType, entityId, entityType);
switch (entityType) {
case BOOL:
{
Serial.println("BoolEntityPacket");
InvertBoolEntityPacket boolPacket;
boolPacket.handle(raw_packet);
break;
}
case UINT8:
{
Serial.println("Uint8EntityPacket");
IncrementUint8EntityPacket uint8Packet;
uint8Packet.handle(raw_packet);
break;
}
case FLOAT:
{
Serial.println("FloatEntityPacket");
QuarterFloatEntityPacket floatPacket;
floatPacket.handle(raw_packet);
break;
}
}
}
}
void setup() {
Serial.begin(115200);
delay(2000);
// Example packet
uint8_t raw_packet[] = {
// ------ HEADER ------
0xBE, 0xEF, // start sequence
0x08, // body size uint8_t
0x03, // type uint8_t
0x00, // unknown
// ------ HEADER ------
// ------ BODY ------
0x58, // entity id uint8_t
0x00, 0x00, 0x00, // reserved
0x00, 0x00, 0xC0, 0x40, // value (float, little-endian) // 6.0f
// ------ BODY ------
// ------ FOOTER ------
0xEF, 0xBE // end sequence
// ------ FOOTER ------
};
Serial.println("Original raw_packet: ");
for (int i = 0; i < sizeof(raw_packet); i++) {
Serial.printf("%02X ", raw_packet[i]);
}
Serial.println();
handlePacket(raw_packet);
Serial.println("Modified raw_packet: ");
for (int i = 0; i < sizeof(raw_packet); i++) {
Serial.printf("%02X ", raw_packet[i]);
}
Serial.println();
}
void loop() {
delay(10);
}