From 4132c58020b2dfdac211e100d711ff6758665d7a Mon Sep 17 00:00:00 2001 From: Annika Hannig Date: Sat, 27 Aug 2022 08:39:27 +0000 Subject: [PATCH] added udp socket stuff --- airportdisplay/Cargo.toml | 5 +-- airportdisplay/src/display/commands.rs | 46 ++++++++++++++++++++++++- airportdisplay/src/display/mod.rs | 1 - airportdisplay/src/display/protocol.rs | 47 ++++++++++++++++---------- airportdisplay/src/display/window.rs | 27 --------------- airportdisplay/src/lib.rs | 5 ++- airportdisplay/src/net/display.rs | 32 ++++++++++++++++++ airportdisplay/src/net/mod.rs | 1 + 8 files changed, 115 insertions(+), 49 deletions(-) delete mode 100644 airportdisplay/src/display/window.rs create mode 100644 airportdisplay/src/net/display.rs create mode 100644 airportdisplay/src/net/mod.rs diff --git a/airportdisplay/Cargo.toml b/airportdisplay/Cargo.toml index 1851b79..ece6ffe 100644 --- a/airportdisplay/Cargo.toml +++ b/airportdisplay/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -"bytes" = "1.2" - +anyhow = "1" +bytes = "1.2" +codepage-437 = "0.1.0" diff --git a/airportdisplay/src/display/commands.rs b/airportdisplay/src/display/commands.rs index 885652f..5048f41 100644 --- a/airportdisplay/src/display/commands.rs +++ b/airportdisplay/src/display/commands.rs @@ -1,4 +1,31 @@ -use super::window::Window; + +/// A window for luminance and text commands +pub struct Window { + pub x: u16, // 0..55 + pub y: u16, // 0..19 + pub w: u16, // 1..56 + pub h: u16, // 1..20 +} + +impl Window { + pub fn new(x: u16, y: u16, w: u16, h: u16) -> Self { + Window { + x: x, + y: y, + w: w, + h: h, + } + } + + pub fn position(x: u16, y: u16) -> Self { + Window { + x: x, + y: y, + w: 0, + h: 0, + } + } +} /// Luminance value pub struct Luminance(Window, u8); @@ -6,10 +33,27 @@ pub struct Luminance(Window, u8); /// TextRaw holds bytes and a window pub struct TextRaw(pub Window, pub Vec); +impl TextRaw { + pub fn new(x: u16, y: u16, bytes: Vec) -> Self { + Self(Window::position(x,y), bytes) + } +} + /// TextBuffer holds a window an a text buffer /// the text will be truncated to fit into the window pub struct TextBuffer(pub Window, pub String); +impl TextBuffer { + pub fn at(x: u16, y: u16, text: String) -> Self { + Self(Window::position(x,y), text) + } + + pub fn from(text: String) -> Self { + Self::at(0, 0, text) + } + +} + /// Text Commands pub enum Text { Raw(TextRaw), diff --git a/airportdisplay/src/display/mod.rs b/airportdisplay/src/display/mod.rs index ea37921..4b15efc 100644 --- a/airportdisplay/src/display/mod.rs +++ b/airportdisplay/src/display/mod.rs @@ -1,6 +1,5 @@ pub mod commands; pub mod protocol; -pub mod window; pub const TEXT_COLUMNS: usize = 56; pub const TEXT_ROWS: usize = 20; diff --git a/airportdisplay/src/display/protocol.rs b/airportdisplay/src/display/protocol.rs index 7f7bd79..6a1ae9f 100644 --- a/airportdisplay/src/display/protocol.rs +++ b/airportdisplay/src/display/protocol.rs @@ -1,46 +1,59 @@ use std::convert::From; use bytes::BufMut; +use codepage_437::{CP437_WINGDINGS, ToCp437}; use super::{ - commands::{Command, Text, TextBuffer, TextRaw}, - window::Window, + commands::{Command, Text, TextBuffer, TextRaw, Window}, TEXT_COLUMNS, TEXT_ROWS, }; /// A frame holds a single encoded display command, /// like set text at pos x, y. -type Frame = Vec; +pub type Frame = Vec; /// Data is a list of commands to be sent to the display. -type Data = Vec; +pub type Data = Vec; /// Encode window data impl From for Frame { fn from(Window { x, y, w, h }: Window) -> Self { let mut buf = vec![]; - buf.put_u16_le(x); - buf.put_u16_le(y); - buf.put_u16_le(w); - buf.put_u16_le(h); + buf.put_u16(x); + buf.put_u16(y); + buf.put_u16(w); + buf.put_u16(h); buf } } impl From for Data { - fn from(TextRaw(window, bytes): TextRaw) -> Data { + fn from(TextRaw(position, bytes): TextRaw) -> Data { let mut bytes = bytes.clone(); bytes.truncate(TEXT_COLUMNS); - vec![[vec![0x03, 0x00], window.into(), bytes].concat()] + let window = Window::new(position.x, position.y, bytes.len() as u16, 1); + vec![[vec![0x00, 0x03], window.into(), bytes].concat()] } } impl From for Data { - fn from(TextBuffer(window, text): TextBuffer) -> Data { - // let Window { x, y, w, h } = window; + fn from(TextBuffer(position, text): TextBuffer) -> Data { let mut lines: Vec<&str> = text.split("\n").collect(); lines.truncate(TEXT_ROWS); - vec![vec![]] + + let mut data = vec![]; + for (i, line) in lines.iter().enumerate() { + if let Ok(bytes) = line.to_cp437(&CP437_WINGDINGS) { + let len = bytes.len() as u16; + let window = Window::new(position.x, position.y + i as u16, len as u16, 1); + data.push([ + vec![0x00, 0x03], + window.into(), + bytes.into(), + ].concat()); + } + } + data } } @@ -57,10 +70,10 @@ impl From for Data { impl From for Data { fn from(cmd: Command) -> Self { match cmd { - Command::Reset => vec![vec![0x08, 0x00]], - Command::Clear => vec![vec![0x02, 0x00]], - Command::Reboot => vec![vec![0x0b, 0x00]], - Command::Fadeout => vec![vec![0x0d, 0x00]], + Command::Reset => vec![vec![0x00, 0x08]], + Command::Clear => vec![vec![0x00, 0x02]], + Command::Reboot => vec![vec![0x00, 0x0b]], + Command::Fadeout => vec![vec![0x00, 0x0d]], Command::Text(text) => text.into(), } } diff --git a/airportdisplay/src/display/window.rs b/airportdisplay/src/display/window.rs deleted file mode 100644 index 6554e09..0000000 --- a/airportdisplay/src/display/window.rs +++ /dev/null @@ -1,27 +0,0 @@ -/// A window for luminance and text commands -pub struct Window { - pub x: u16, // 0..55 - pub y: u16, // 0..19 - pub w: u16, // 1..56 - pub h: u16, // 1..20 -} - -impl Window { - pub fn new(x: u16, y: u16, w: u16, h: u16) -> Self { - Window { - x: x, - y: y, - w: w, - h: h, - } - } - - pub fn position(x: u16, y: u16) -> Self { - Window { - x: x, - y: y, - w: 0, - h: 0, - } - } -} diff --git a/airportdisplay/src/lib.rs b/airportdisplay/src/lib.rs index d4e9f48..5fe8b78 100644 --- a/airportdisplay/src/lib.rs +++ b/airportdisplay/src/lib.rs @@ -1,3 +1,6 @@ mod display; +mod net; -pub use display::commands::{Command, Text}; +pub use display::commands::{Command, Text, TextRaw, TextBuffer, Window}; +pub use display::protocol::Data; +pub use net::display::Display; diff --git a/airportdisplay/src/net/display.rs b/airportdisplay/src/net/display.rs new file mode 100644 index 0000000..c4483b2 --- /dev/null +++ b/airportdisplay/src/net/display.rs @@ -0,0 +1,32 @@ + +use anyhow::Result; +use std::net::UdpSocket; + +use crate::display::commands::Command; +use crate::display::protocol::Data; + +pub struct Display { + addr: String, + socket: UdpSocket, +} + + +impl Display { + pub fn open(addr: String) -> Result { + let socket = UdpSocket::bind("0.0.0.0:17382")?; + Ok(Self{ + addr: addr, + socket: socket, + }) + } + + pub fn send(&self, cmd: Command) -> Result<()> { + let data: Data = cmd.into(); + for frame in data { + println!("sending payload: {:?}", &frame); + self.socket.send_to(frame.as_slice(), self.addr.clone().as_str())?; + } + Ok(()) + } +} + diff --git a/airportdisplay/src/net/mod.rs b/airportdisplay/src/net/mod.rs new file mode 100644 index 0000000..8754563 --- /dev/null +++ b/airportdisplay/src/net/mod.rs @@ -0,0 +1 @@ +pub mod display;