#include #include #include /* * Example binary protocol for passing small, statically sized messages. * * These messages are efficient and easily serializable. Since there is no variable length payload in the message, no * parsing is required, and a simple cast into whatever reciever buffer you're using, or a memcpy into a preallocated * CommandMessage, is enough. Keep in mind; the largest member of the data union determines the size of the struct. */ // clang-format off typedef enum { CMD_SET_LEVEL = 1, CMD_SET_LIGHTS = 2, CMD_SET_DISTANCE_FACTOR = 3 } CommandType; typedef struct __attribute__((__packed__)) { uint8_t type; union { struct { uint8_t level; } set_level; struct { uint8_t on; } set_lights; // 1 = on, 0 = off struct { float factor; } set_distance; } data; /* NOTE: Consider adding crc checksum here, or in a wrapper struct */ } CommandMessage; // clang-format on void print_command(CommandMessage *m) { switch (m->type) { case CMD_SET_LEVEL: printf("Type: SetLevel\nPayload: %d\n", m->data.set_level.level); break; case CMD_SET_LIGHTS: printf("Type: SetLights\nPayload: %d\n", m->data.set_lights.on); break; case CMD_SET_DISTANCE_FACTOR: printf("Type: SetDistanceFactor\nPayload: %.2f\n", m->data.set_distance.factor); break; } } char buf[sizeof(CommandMessage)]; int main(void) { CommandMessage m = {CMD_SET_LIGHTS, .data.set_lights.on = 1}; memcpy(buf, &m, sizeof(CommandMessage)); /* Here we can send buf through a socket, to uart, wherever */ CommandMessage r = {0}; memcpy(&r, &buf, sizeof(CommandMessage)); /* We can then dispatch based on the message type */ print_command(&r); m.type = CMD_SET_LEVEL; m.data.set_level.level = 10; print_command(&m); m.type = CMD_SET_DISTANCE_FACTOR; m.data.set_distance.factor = 1337.42; print_command(&m); return 0; }