SpaceEther is a lightweight custom transport protocol designed to run directly over raw Ethernet or UDP. It provides reliable framing, optional forward error correction and authentication, and topic-oriented payloads that can be integrated into higher-level systems such as ROS 2.
- Custom Ethernet framing — Frames start with a magic byte and version field and include a CRC16 over the header. An optional HMAC footer adds message authentication.
- Fragmentation and reassembly — Large payloads can be broken into smaller fragments, each with its own sequence number, and reassembled at the receiver.
- Forward error correction — A simple two-dimensional parity scheme is available to detect and correct single-bit errors. A Reed–Solomon encoder/decoder can be plugged in via a small C foreign function interface to a Rust implementation.
- Topic-based payloads — Payloads can be wrapped in a simple topic header so that they can be routed based on a name and type.
- Terminal server — An embeddable TCP terminal allows a user to connect to a SpaceEther device over the network and issue diagnostic commands.
- Cross-platform — Works on Linux and Windows with RAII socket management.
+----------+----------+-------+------+-----+------------+---------+
| Magic | Version | Flags | Type | Seq | PayloadLen | HdrCRC |
| (1 byte) | (1 byte) | (1B) | (1B) | (4B)| (2B) | (2B) |
+----------+----------+-------+------+-----+------------+---------+
| Payload (0-1400 bytes) |
+-----------------------------------------------------------------+
| CRC32 (4 bytes) |
+-----------------------------------------------------------------+
| HMAC-SHA256 (12 bytes, optional) |
+-----------------------------------------------------------------+
| Constant | Value | Description |
|---|---|---|
| MAGIC | 0x7F | Magic byte identifying SpaceEther frames |
| VERSION | 0x01 | Current protocol version |
| ETHERTYPE | 0x88B5 | Ethernet type for raw socket mode |
| MAX_MTU | 1500 | Standard Ethernet MTU |
| MAX_PAYLOAD | 1400 | Maximum payload size after headers |
| Type | Value | Description |
|---|---|---|
| DATA | 0x00 | Generic data payload |
| PING | 0x01 | Keepalive request |
| PONG | 0x02 | Keepalive response |
| TOPIC | 0x03 | Topic-wrapped message |
| ACK | 0x04 | Acknowledgment |
| NACK | 0x05 | Negative acknowledgment |
| CTRL | 0x06 | Control message |
| Flag | Bit | Description |
|---|---|---|
| FEC | 0x01 | Forward error correction enabled |
| FRAG | 0x02 | Fragment of larger payload |
| AUTH | 0x04 | HMAC authentication present |
| ACK_REQ | 0x08 | Acknowledgment requested |
The project uses CMake. A typical build sequence:
cd SpaceEther
mkdir build && cd build
cmake ..
make -j$(nproc)| Option | Default | Description |
|---|---|---|
SPACEE_BUILD_TOOLS |
ON | Build command-line tools |
SPACEE_BUILD_TESTS |
OFF | Build the test suite |
SPACEE_ENABLE_AUTH |
OFF | Enable HMAC authentication support |
SPACEE_WITH_ROS2 |
OFF | Build ROS 2 bridge (requires ROS 2) |
SPACEE_SANITIZE |
OFF | Enable AddressSanitizer |
# Basic build with tools
cmake -S .. -B . -DSPACEE_BUILD_TOOLS=ON
make
# Build with tests
cmake -S .. -B . -DSPACEE_BUILD_TESTS=ON
make
ctest --output-on-failure
# Build with authentication
cmake -S .. -B . -DSPACEE_ENABLE_AUTH=ON
make
# Debug build with sanitizers
cmake -S .. -B . -DCMAKE_BUILD_TYPE=Debug -DSPACEE_SANITIZE=ON
make#include "space_ether/protocol.h"
using namespace space_ether;
// Encode a frame
SpaceEtherHeader h{};
h.type = static_cast<uint8_t>(PacketType::DATA);
h.seq = 1;
std::vector<uint8_t> payload = {0x01, 0x02, 0x03, 0x04};
auto frame = encode(h, payload);
// Decode a frame
auto decoded = decode(frame);
if (decoded.ok) {
// Use decoded.header and decoded.payload
}
// Create PING/PONG
auto ping = make_ping(seq);
auto pong = make_pong(seq);
// Create topic message
auto topic = make_topic_frame("sensor/temp", "std_msgs/Float32", data, seq);#include "space_ether/udp_driver.h"
// Server mode (bind only)
UdpDriver server("0.0.0.0", 38885);
server.open();
auto received = server.recv_bytes(1000); // 1s timeout
if (received.has_value()) {
// Process *received
}
// Client mode (connect to remote)
UdpDriver client("0.0.0.0", 38886, "192.168.1.100", 38885);
client.open();
client.send_bytes(frame);#include "space_ether/space_ether_node.h"
// Create driver adapter
class MyAdapter : public SpaceEtherDriver {
void send_frame(const std::vector<uint8_t>& frame) override {
// Send frame via your transport
}
};
MyAdapter adapter;
SpaceEtherNode node(&adapter);
// Set receive callback
node.on_data = [](PacketType type, const std::vector<uint8_t>& data) {
// Handle received message
};
// Send messages
node.send(PacketType::DATA, payload, false, false);
node.send_topic("sensor/temp", "std_msgs/Float32", data);
node.send_large(PacketType::DATA, large_payload, false, false); // Auto-fragment
// Check statistics
const auto& stats = node.counters();#include "space_ether/terminal.h"
Terminal terminal;
terminal.add_command("status", [](const std::vector<std::string>&) {
return "System OK\n";
}, "Show system status");
terminal.add_command("reset", [](const std::vector<std::string>& args) {
// Handle reset command
return "Reset complete\n";
}, "Reset the system");
terminal.start("0.0.0.0", 9999);
// Connect with: telnet localhost 9999Demonstration tool for testing SpaceEther functionality:
# Run as server
./se_demo server 38885
# Run as client
./se_demo client 192.168.1.100 38885
# Send ping messages
./se_demo ping 192.168.1.100 38885 10
# Run throughput benchmark
./se_demo bench 192.168.1.100 38885
# Run local tests
./se_demo testTerminal server with embedded diagnostics:
# Start terminal server
./se_terminal 38885 9999
# Connect to terminal
telnet localhost 9999
# Available commands:
# help - Show available commands
# stats - Show protocol statistics
# reset - Reset statistics counters
# ping - Send a PING frame
# send - Send DATA frame
# topic - Send TOPIC frame
# status - Show server status
# shutdown - Stop the serverWhen built with SPACEE_ENABLE_AUTH=ON, frames can include HMAC-SHA256 authentication:
-
Set the
SPACEE_AUTH_KEYenvironment variable:export SPACEE_AUTH_KEY="your_secret_key"
-
Set the AUTH flag when encoding:
h.flags = static_cast<uint8_t>(HeaderFlags::AUTH); auto frame = encode(h, payload);
-
Check authentication on decode:
auto decoded = decode(frame); if (decoded.ok && decoded.auth_ok) { // Frame is authenticated }
Two-dimensional parity FEC for single-bit error correction:
#include "space_ether/fec_twodparity.h"
// Encode with FEC
auto encoded = fec_2d_encode(data);
// Decode and correct errors
bool corrected = false;
auto decoded = fec_2d_decode(encoded, corrected);
if (corrected) {
// Error was detected and corrected
}# Build tests
cmake -S .. -B . -DSPACEE_BUILD_TESTS=ON
make
# Run all tests
ctest --output-on-failure
# Run specific test
./tests/test_protocol
# Run with verbose output
ctest -VSpaceEther/
├── include/space_ether/ # Public headers
│ ├── protocol.h # Wire format and encoding
│ ├── driver.h # Transport abstraction
│ ├── udp_driver.h # UDP transport
│ ├── raw_socket_driver.h # Raw Ethernet transport
│ ├── space_ether_node.h # High-level node
│ ├── terminal.h # TCP terminal server
│ ├── fec_twodparity.h # 2D parity FEC
│ ├── rs_fec_ffi.h # Reed-Solomon FFI
│ └── socket_util.h # Socket utilities
├── src/ # Implementation
├── tests/ # Test suite
├── tools/ # Command-line tools
├── docs/ # Documentation
└── scripts/ # Build/test scripts
Copyright (c) 2025. All rights reserved.