What is Struct Frame¶
Struct Frame is a cross-platform packeting, framing, and parsing framework. It uses .proto files to define message structures and generates code for C, C++, TypeScript, Python, and GraphQL.
Why Message Framing¶
When sending structured data over a communication channel:
- Where does one message end and the next begin?
- Is the received data complete and uncorrupted?
- What kind of message is this?
These are problems that framing solves. Without framing, raw binary data is just a stream of bytes with no structure.
Why Struct Frame¶
No Encoding/Decoding Overhead in C/C++¶
C and C++ implementations use packed structs that map directly to memory. Messages can be cast to/from byte arrays without any encoding or decoding step. This reduces CPU and memory usage.
// Direct memory access - no encode/decode
VehicleStatus* msg = (VehicleStatus*)buffer;
printf("Speed: %f\n", msg->speed);
Cross-Platform Communication¶
Struct Frame generates code for multiple languages from a single .proto definition. A C program on an embedded device can communicate with a Python server or TypeScript frontend using the same message format.
Small Frame Overhead¶
The basic frame format adds only 4 bytes of overhead:
- 1 byte start marker
- 1 byte message ID
- 2 bytes checksum
Compare this to Mavlink (8-14 bytes header) or Cap'n Proto (8+ bytes header).
Reduced Bandwidth Options¶
Different frame formats support different tradeoffs: - No frame: Zero overhead, for point-to-point trusted links - Basic frame: 4 bytes overhead, for most applications - Custom formats: UBX, Mavlink v1/v2 support planned
More Memory and CPU Efficient Than Protobuf and Cap'n Proto¶
Protobuf and Cap'n Proto are designed for general-purpose serialization with variable-length encoding, schema evolution, and RPC.
Struct Frame is simpler: - Fixed-size messages with known layouts - Direct memory mapping in C/C++ - No variable-length integer encoding - No schema evolution complexity
No Runtime Dependencies¶
Everything needed to use struct-frame is generated or included with the boilerplate code. There are no external libraries to link against at runtime. The C/C++ implementation is header-only.
Memory Options¶
C/C++ parsers can: - Return a pointer to the message in the receive buffer (zero-copy) - Copy the message to a separate buffer
Framers can: - Encode directly into a transmit buffer - Create a message and copy it to a buffer
Feature Compatibility¶
| Feature | C | C++ | TypeScript | Python | GraphQL |
|---|---|---|---|---|---|
| Core Types | Yes | Yes | Yes | Yes | Yes |
| Strings | Yes | Yes | Yes | Yes | Yes |
| Enums | Yes | Yes | Yes | Yes | Yes |
| Enum Classes | N/A | Yes | N/A | N/A | N/A |
| Nested Messages | Yes | Yes | Yes | Yes | Yes |
| Message IDs | Yes | Yes | Yes | Yes | N/A |
| Serialization | Yes | Yes | Yes | Yes | N/A |
| Fixed Arrays | Yes | Yes | Yes | Yes | Yes |
| Bounded Arrays | Yes | Yes | Partial | Yes | Yes |
| Flatten | N/A | N/A | N/A | Yes | Yes |
When to Use Struct Frame¶
Use Struct Frame when: - You need low-overhead communication between embedded systems and higher-level languages - You want direct memory access without encoding overhead - You have bandwidth constraints - You need a simple, predictable message format