Initial commit
This commit is contained in:
10
crates/infinity_protocol/Cargo.toml
Normal file
10
crates/infinity_protocol/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "infinity_protocol"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
|
||||
206
crates/infinity_protocol/src/lib.rs
Normal file
206
crates/infinity_protocol/src/lib.rs
Normal file
@@ -0,0 +1,206 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const CONTROL_PROTOCOL_VERSION: u16 = 1;
|
||||
pub const REALTIME_PROTOCOL_VERSION: u16 = 1;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct ControlEnvelope {
|
||||
pub protocol_version: u16,
|
||||
pub sequence: u32,
|
||||
pub sent_at_millis: u64,
|
||||
pub message: ControlMessage,
|
||||
}
|
||||
|
||||
impl ControlEnvelope {
|
||||
pub fn new(sequence: u32, sent_at_millis: u64, message: ControlMessage) -> Self {
|
||||
Self {
|
||||
protocol_version: CONTROL_PROTOCOL_VERSION,
|
||||
sequence,
|
||||
sent_at_millis,
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RealtimeEnvelope {
|
||||
pub protocol_version: u16,
|
||||
pub sequence: u32,
|
||||
pub sent_at_millis: u64,
|
||||
pub message: RealtimeMessage,
|
||||
}
|
||||
|
||||
impl RealtimeEnvelope {
|
||||
pub fn new(sequence: u32, sent_at_millis: u64, message: RealtimeMessage) -> Self {
|
||||
Self {
|
||||
protocol_version: REALTIME_PROTOCOL_VERSION,
|
||||
sequence,
|
||||
sent_at_millis,
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ControlMessage {
|
||||
DiscoveryHello {
|
||||
host_id: String,
|
||||
},
|
||||
DiscoveryAck {
|
||||
node_id: String,
|
||||
firmware_version: String,
|
||||
capabilities: NodeCapabilities,
|
||||
},
|
||||
ConfigSync {
|
||||
topology_revision: String,
|
||||
outputs: Vec<PanelAssignment>,
|
||||
},
|
||||
HeartbeatRequest {
|
||||
node_id: String,
|
||||
},
|
||||
Heartbeat(NodeHeartbeat),
|
||||
PresetRecall {
|
||||
preset_id: String,
|
||||
transition: TransitionSpec,
|
||||
},
|
||||
Blackout {
|
||||
enabled: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RealtimeMessage {
|
||||
SceneParameters(SceneParametersFrame),
|
||||
PixelFrame(PixelFrame),
|
||||
ResyncRequest {
|
||||
node_id: String,
|
||||
last_sequence_seen: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct NodeCapabilities {
|
||||
pub outputs_per_node: u8,
|
||||
pub leds_per_output: u16,
|
||||
pub supported_driver_backends: Vec<String>,
|
||||
pub supports_scene_mode: bool,
|
||||
pub supports_frame_streaming: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct NodeHeartbeat {
|
||||
pub node_id: String,
|
||||
pub fps: f32,
|
||||
pub heartbeat_age_ms: u32,
|
||||
pub dropped_frames: u32,
|
||||
pub reconnect_count: u32,
|
||||
pub free_heap_bytes: Option<u32>,
|
||||
pub temperature_celsius: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PanelAssignment {
|
||||
pub panel: PanelAddress,
|
||||
pub physical_output_name: String,
|
||||
pub driver_reference: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TransitionSpec {
|
||||
pub transition_ms: u32,
|
||||
pub mode: TransitionMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TransitionMode {
|
||||
Snap,
|
||||
Crossfade,
|
||||
Chase,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SceneParametersFrame {
|
||||
pub node_id: String,
|
||||
pub mode: RealtimeMode,
|
||||
pub preset_id: Option<String>,
|
||||
pub effect: String,
|
||||
pub seed: u64,
|
||||
pub palette: Vec<String>,
|
||||
pub master_brightness: f32,
|
||||
pub speed: f32,
|
||||
pub intensity: f32,
|
||||
pub target_group: Option<String>,
|
||||
pub target_outputs: Vec<PanelAddress>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PixelFrame {
|
||||
pub node_id: String,
|
||||
pub frame_index: u64,
|
||||
pub target_outputs: Vec<OutputFrame>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct OutputFrame {
|
||||
pub panel: PanelAddress,
|
||||
pub pixels: Vec<Rgb8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Rgb8 {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PanelAddress {
|
||||
pub node_id: String,
|
||||
pub panel_slot: PanelSlot,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PanelSlot {
|
||||
Top,
|
||||
Middle,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RealtimeMode {
|
||||
DistributedScene,
|
||||
FrameStreaming,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn constructors_stamp_current_protocol_versions() {
|
||||
let control = ControlEnvelope::new(
|
||||
4,
|
||||
123,
|
||||
ControlMessage::HeartbeatRequest {
|
||||
node_id: "node-01".to_string(),
|
||||
},
|
||||
);
|
||||
let realtime = RealtimeEnvelope::new(
|
||||
5,
|
||||
456,
|
||||
RealtimeMessage::ResyncRequest {
|
||||
node_id: "node-01".to_string(),
|
||||
last_sequence_seen: 4,
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(control.protocol_version, CONTROL_PROTOCOL_VERSION);
|
||||
assert_eq!(realtime.protocol_version, REALTIME_PROTOCOL_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user