mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 10:00:14 +01:00
add gz compression
This commit is contained in:
parent
0e393896d3
commit
5c61d02749
41
Cargo.lock
generated
41
Cargo.lock
generated
|
@ -2,18 +2,58 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.21"
|
version = "0.4.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num"
|
name = "num"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -120,6 +160,7 @@ dependencies = [
|
||||||
name = "servicepoint2"
|
name = "servicepoint2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"flate2",
|
||||||
"log",
|
"log",
|
||||||
"num",
|
"num",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
|
|
|
@ -7,4 +7,5 @@ edition = "2021"
|
||||||
num = "0.4"
|
num = "0.4"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
log = "0.4.21"
|
log = "0.4"
|
||||||
|
flate2 = "1.0"
|
||||||
|
|
35
examples/Cargo.lock
generated
35
examples/Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -128,6 +134,15 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_filter"
|
name = "env_filter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -151,6 +166,16 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "game_of_life"
|
name = "game_of_life"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -209,6 +234,15 @@ version = "2.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moving_line"
|
name = "moving_line"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -401,6 +435,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||||
name = "servicepoint2"
|
name = "servicepoint2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"flate2",
|
||||||
"log",
|
"log",
|
||||||
"num",
|
"num",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use servicepoint2::{BitVec, Connection, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
|
use servicepoint2::{BitVec, CompressionCode, Connection, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
|
||||||
use servicepoint2::Command::BitmapLinearAnd;
|
use servicepoint2::Command::BitmapLinearAnd;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
@ -16,7 +16,7 @@ struct Cli {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::builder()
|
env_logger::builder()
|
||||||
.filter_level(log::LevelFilter::Info)
|
.filter_level(log::LevelFilter::Debug)
|
||||||
.init();
|
.init();
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ fn main() {
|
||||||
let pixel_data: Vec<u8> = enabled_pixels.clone().into();
|
let pixel_data: Vec<u8> = enabled_pixels.clone().into();
|
||||||
let bit_vec = BitVec::load(&*pixel_data);
|
let bit_vec = BitVec::load(&*pixel_data);
|
||||||
|
|
||||||
connection.send(BitmapLinearAnd(0, bit_vec)).unwrap();
|
connection.send(BitmapLinearAnd(0, bit_vec, CompressionCode::Gz)).unwrap();
|
||||||
thread::sleep(sleep_duration);
|
thread::sleep(sleep_duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
238
src/command.rs
238
src/command.rs
|
@ -1,5 +1,9 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use flate2::bufread::GzEncoder;
|
||||||
|
use flate2::Compression;
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
use crate::{BitVec, ByteGrid, Header, Packet, PixelGrid, TILE_SIZE};
|
use crate::{BitVec, ByteGrid, Header, Packet, PixelGrid, TILE_SIZE};
|
||||||
use crate::command_codes::CommandCode;
|
use crate::command_codes::{CommandCode, CompressionCode};
|
||||||
|
|
||||||
/// An origin marks the top left position of the
|
/// An origin marks the top left position of the
|
||||||
/// data sent to the display.
|
/// data sent to the display.
|
||||||
|
@ -29,28 +33,14 @@ pub enum Command {
|
||||||
Brightness(Brightness),
|
Brightness(Brightness),
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
BitmapLegacy,
|
BitmapLegacy,
|
||||||
BitmapLinear(Offset, BitVec),
|
BitmapLinear(Offset, BitVec, CompressionCode),
|
||||||
BitmapLinearAnd(Offset, BitVec),
|
BitmapLinearAnd(Offset, BitVec, CompressionCode),
|
||||||
BitmapLinearOr(Offset, BitVec),
|
BitmapLinearOr(Offset, BitVec, CompressionCode),
|
||||||
BitmapLinearXor(Offset, BitVec),
|
BitmapLinearXor(Offset, BitVec, CompressionCode),
|
||||||
Cp437Data(Origin, ByteGrid),
|
Cp437Data(Origin, ByteGrid),
|
||||||
BitmapLinearWin(Origin, PixelGrid),
|
BitmapLinearWin(Origin, PixelGrid),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_and_payload(command: CommandCode, offset: Offset, payload: Vec<u8>) -> Packet {
|
|
||||||
Packet(Header(command.to_primitive(), offset, payload.len() as u16, 0, 0), payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn origin_size_payload(command: CommandCode, origin: Origin, size: Size, payload: Vec<u8>) -> Packet {
|
|
||||||
let Origin(x, y) = origin;
|
|
||||||
let Size(w, h) = size;
|
|
||||||
Packet(Header(command.to_primitive(), x, y, w, h), payload.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn command_code_only(code: CommandCode) -> Packet {
|
|
||||||
Packet(Header(code.to_primitive(), 0x0000, 0x0000, 0x0000, 0x0000), vec!())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Packet> for Command {
|
impl Into<Packet> for Command {
|
||||||
fn into(self) -> Packet {
|
fn into(self) -> Packet {
|
||||||
match self {
|
match self {
|
||||||
|
@ -59,7 +49,6 @@ impl Into<Packet> for Command {
|
||||||
Command::HardReset => command_code_only(CommandCode::HardReset),
|
Command::HardReset => command_code_only(CommandCode::HardReset),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
Command::BitmapLegacy => command_code_only(CommandCode::BitmapLegacy),
|
Command::BitmapLegacy => command_code_only(CommandCode::BitmapLegacy),
|
||||||
|
|
||||||
Command::CharBrightness(origin, grid) => {
|
Command::CharBrightness(origin, grid) => {
|
||||||
origin_size_payload(CommandCode::CharBrightness,
|
origin_size_payload(CommandCode::CharBrightness,
|
||||||
origin,
|
origin,
|
||||||
|
@ -69,10 +58,6 @@ impl Into<Packet> for Command {
|
||||||
Command::Brightness(brightness) => {
|
Command::Brightness(brightness) => {
|
||||||
Packet(Header(CommandCode::Brightness.to_primitive(), 0x00000, 0x0000, 0x0000, 0x0000), vec!(brightness))
|
Packet(Header(CommandCode::Brightness.to_primitive(), 0x00000, 0x0000, 0x0000, 0x0000), vec!(brightness))
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::BitmapLinear(offset, bits) => {
|
|
||||||
offset_and_payload(CommandCode::BitmapLinear, offset, bits.into())
|
|
||||||
}
|
|
||||||
Command::BitmapLinearWin(Origin(pixel_x, pixel_y), pixels) => {
|
Command::BitmapLinearWin(Origin(pixel_x, pixel_y), pixels) => {
|
||||||
debug_assert_eq!(pixel_x % 8, 0);
|
debug_assert_eq!(pixel_x % 8, 0);
|
||||||
debug_assert_eq!(pixels.width % 8, 0);
|
debug_assert_eq!(pixels.width % 8, 0);
|
||||||
|
@ -84,14 +69,17 @@ impl Into<Packet> for Command {
|
||||||
pixels.height as u16),
|
pixels.height as u16),
|
||||||
pixels.into())
|
pixels.into())
|
||||||
}
|
}
|
||||||
Command::BitmapLinearAnd(offset, bits) => {
|
Command::BitmapLinear(offset, bits, compression) => {
|
||||||
offset_and_payload(CommandCode::BitmapLinearAnd, offset, bits.into())
|
bitmap_linear_into_packet(CommandCode::BitmapLinear, offset, compression, bits.into())
|
||||||
}
|
}
|
||||||
Command::BitmapLinearOr(offset, bits) => {
|
Command::BitmapLinearAnd(offset, bits, compression) => {
|
||||||
offset_and_payload(CommandCode::BitmapLinearOr, offset, bits.into())
|
bitmap_linear_into_packet(CommandCode::BitmapLinearAnd, offset, compression, bits.into())
|
||||||
}
|
}
|
||||||
Command::BitmapLinearXor(offset, bits) => {
|
Command::BitmapLinearOr(offset, bits, compression) => {
|
||||||
offset_and_payload(CommandCode::BitmapLinearXor, offset, bits.into())
|
bitmap_linear_into_packet(CommandCode::BitmapLinearOr, offset, compression, bits.into())
|
||||||
|
}
|
||||||
|
Command::BitmapLinearXor(offset, bits, compression) => {
|
||||||
|
bitmap_linear_into_packet(CommandCode::BitmapLinearXor, offset, compression, bits.into())
|
||||||
}
|
}
|
||||||
Command::Cp437Data(origin, grid) => {
|
Command::Cp437Data(origin, grid) => {
|
||||||
origin_size_payload(CommandCode::Cp437Data,
|
origin_size_payload(CommandCode::Cp437Data,
|
||||||
|
@ -108,86 +96,62 @@ pub enum TryFromPacketError {
|
||||||
InvalidCommand(u16),
|
InvalidCommand(u16),
|
||||||
UnexpectedPayloadSize(usize, usize),
|
UnexpectedPayloadSize(usize, usize),
|
||||||
ExtraneousHeaderValues,
|
ExtraneousHeaderValues,
|
||||||
UnsupportedSubcommand(u16),
|
InvalidCompressionCode(u16),
|
||||||
}
|
DecompressionFailed(std::io::Error),
|
||||||
|
|
||||||
fn check_empty_header(packet: &Packet) -> Option<TryFromPacketError> {
|
|
||||||
let Packet(Header(_, a, b, c, d), _) = &packet;
|
|
||||||
if *a != 0 || *b != 0 || *c != 0 || *d != 0 {
|
|
||||||
Some(TryFromPacketError::ExtraneousHeaderValues)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_command_only(packet: &Packet) -> Option<TryFromPacketError> {
|
|
||||||
let Packet(_, payload) = packet;
|
|
||||||
if payload.len() != 0 {
|
|
||||||
Some(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
|
|
||||||
} else {
|
|
||||||
check_empty_header(packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_linear_bitmap(packet: &Packet) -> Option<TryFromPacketError> {
|
|
||||||
let Packet(Header(_, _, length, sub, reserved), payload) = packet;
|
|
||||||
if *reserved != 0 {
|
|
||||||
return Some(TryFromPacketError::ExtraneousHeaderValues);
|
|
||||||
}
|
|
||||||
if *sub != 0 {
|
|
||||||
return Some(TryFromPacketError::UnsupportedSubcommand(*sub));
|
|
||||||
}
|
|
||||||
if payload.len() != *length as usize {
|
|
||||||
return Some(TryFromPacketError::UnexpectedPayloadSize(*length as usize, payload.len()));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Packet> for Command {
|
impl TryFrom<Packet> for Command {
|
||||||
type Error = TryFromPacketError;
|
type Error = TryFromPacketError;
|
||||||
|
|
||||||
fn try_from(value: Packet) -> Result<Self, Self::Error> {
|
fn try_from(value: Packet) -> Result<Self, Self::Error> {
|
||||||
let Packet(Header(command_u16, a, b, c, d), payload) = &value;
|
let Packet(Header(command_u16, a, b, c, d), _) = value;
|
||||||
let command_code = match CommandCode::from_primitive(*command_u16) {
|
let command_code = match CommandCode::from_primitive(command_u16) {
|
||||||
None => return Err(TryFromPacketError::InvalidCommand(*command_u16)),
|
None => return Err(TryFromPacketError::InvalidCommand(command_u16)),
|
||||||
Some(value) => value
|
Some(value) => value
|
||||||
};
|
};
|
||||||
|
|
||||||
match command_code {
|
match command_code {
|
||||||
CommandCode::Clear => {
|
CommandCode::Clear => {
|
||||||
if let Some(err) = check_command_only(&value) {
|
match check_command_only(value) {
|
||||||
return Err(err);
|
Some(err) => Err(err),
|
||||||
|
None => Ok(Command::Clear),
|
||||||
}
|
}
|
||||||
Ok(Command::Clear)
|
|
||||||
}
|
}
|
||||||
CommandCode::Brightness => {
|
CommandCode::Brightness => {
|
||||||
if let Some(err) = check_empty_header(&value) {
|
let Packet(header, payload) = value;
|
||||||
return Err(err);
|
if payload.len() != 1 {
|
||||||
|
return Err(TryFromPacketError::UnexpectedPayloadSize(1, payload.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match check_empty_header(header) {
|
||||||
|
Some(err) => Err(err),
|
||||||
|
None => Ok(Command::Brightness(payload[0])),
|
||||||
}
|
}
|
||||||
Ok(Command::Brightness(payload[0]))
|
|
||||||
}
|
}
|
||||||
CommandCode::HardReset => {
|
CommandCode::HardReset => {
|
||||||
if let Some(err) = check_command_only(&value) {
|
match check_command_only(value) {
|
||||||
return Err(err);
|
Some(err) => Err(err),
|
||||||
|
None => Ok(Command::HardReset),
|
||||||
}
|
}
|
||||||
Ok(Command::HardReset)
|
|
||||||
}
|
}
|
||||||
CommandCode::FadeOut => {
|
CommandCode::FadeOut => {
|
||||||
if let Some(err) = check_command_only(&value) {
|
match check_command_only(value) {
|
||||||
return Err(err);
|
Some(err) => Err(err),
|
||||||
|
None => Ok(Command::FadeOut),
|
||||||
}
|
}
|
||||||
Ok(Command::FadeOut)
|
|
||||||
}
|
}
|
||||||
CommandCode::Cp437Data => {
|
CommandCode::Cp437Data => {
|
||||||
|
let Packet(_, payload) = value;
|
||||||
Ok(Command::Cp437Data(
|
Ok(Command::Cp437Data(
|
||||||
Origin(*a, *b),
|
Origin(a, b),
|
||||||
ByteGrid::load(*c as usize, *d as usize, payload),
|
ByteGrid::load(c as usize, d as usize, &payload),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
CommandCode::CharBrightness => {
|
CommandCode::CharBrightness => {
|
||||||
|
let Packet(_, payload) = value;
|
||||||
Ok(Command::CharBrightness(
|
Ok(Command::CharBrightness(
|
||||||
Origin(*a, *b),
|
Origin(a, b),
|
||||||
ByteGrid::load(*c as usize, *d as usize, payload),
|
ByteGrid::load(c as usize, d as usize, &payload),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
@ -195,35 +159,109 @@ impl TryFrom<Packet> for Command {
|
||||||
Ok(Command::BitmapLegacy)
|
Ok(Command::BitmapLegacy)
|
||||||
}
|
}
|
||||||
CommandCode::BitmapLinearWin => {
|
CommandCode::BitmapLinearWin => {
|
||||||
|
let Packet(_, payload) = value;
|
||||||
Ok(Command::BitmapLinearWin(
|
Ok(Command::BitmapLinearWin(
|
||||||
Origin(*a * TILE_SIZE, *b),
|
Origin(a * TILE_SIZE, b),
|
||||||
PixelGrid::load(*c as usize * TILE_SIZE as usize, *d as usize, payload),
|
PixelGrid::load(c as usize * TILE_SIZE as usize, d as usize, &payload),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
CommandCode::BitmapLinear => {
|
CommandCode::BitmapLinear => {
|
||||||
if let Some(err) = check_linear_bitmap(&value) {
|
let (vec, compression) = packet_into_linear_bitmap(value)?;
|
||||||
return Err(err);
|
Ok(Command::BitmapLinear(a, vec, compression))
|
||||||
}
|
|
||||||
Ok(Command::BitmapLinear(*a, BitVec::load(payload)))
|
|
||||||
}
|
}
|
||||||
CommandCode::BitmapLinearAnd => {
|
CommandCode::BitmapLinearAnd => {
|
||||||
if let Some(err) = check_linear_bitmap(&value) {
|
let (vec, compression) = packet_into_linear_bitmap(value)?;
|
||||||
return Err(err);
|
Ok(Command::BitmapLinearAnd(a, vec, compression))
|
||||||
}
|
|
||||||
Ok(Command::BitmapLinearAnd(*a, BitVec::load(payload)))
|
|
||||||
}
|
}
|
||||||
CommandCode::BitmapLinearOr => {
|
CommandCode::BitmapLinearOr => {
|
||||||
if let Some(err) = check_linear_bitmap(&value) {
|
let (vec, compression) = packet_into_linear_bitmap(value)?;
|
||||||
return Err(err);
|
Ok(Command::BitmapLinearOr(a, vec, compression))
|
||||||
}
|
|
||||||
Ok(Command::BitmapLinearOr(*a, BitVec::load(payload)))
|
|
||||||
}
|
}
|
||||||
CommandCode::BitmapLinearXor => {
|
CommandCode::BitmapLinearXor => {
|
||||||
if let Some(err) = check_linear_bitmap(&value) {
|
let (vec, compression) = packet_into_linear_bitmap(value)?;
|
||||||
return Err(err);
|
Ok(Command::BitmapLinearXor(a, vec, compression))
|
||||||
}
|
|
||||||
Ok(Command::BitmapLinearXor(*a, BitVec::load(payload)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bitmap_linear_into_packet(command: CommandCode, offset: Offset, compression: CompressionCode, payload: Vec<u8>) -> Packet {
|
||||||
|
let payload = match compression {
|
||||||
|
CompressionCode::None => payload,
|
||||||
|
CompressionCode::Gz => {
|
||||||
|
let mut encoder = GzEncoder::new(&*payload, Compression::best());
|
||||||
|
let mut compressed = vec!();
|
||||||
|
match encoder.read_to_end(&mut compressed) {
|
||||||
|
Err(err) => panic!("could not compress payload: {}", err),
|
||||||
|
Ok(_) => compressed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompressionCode::Bz => todo!(),
|
||||||
|
CompressionCode::Lz => todo!(),
|
||||||
|
CompressionCode::Zs => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let compression = CompressionCode::to_primitive(&compression);
|
||||||
|
Packet(Header(command.to_primitive(), offset, payload.len() as u16, compression, 0), payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin_size_payload(command: CommandCode, origin: Origin, size: Size, payload: Vec<u8>) -> Packet {
|
||||||
|
let Origin(x, y) = origin;
|
||||||
|
let Size(w, h) = size;
|
||||||
|
Packet(Header(command.to_primitive(), x, y, w, h), payload.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_code_only(code: CommandCode) -> Packet {
|
||||||
|
Packet(Header(code.to_primitive(), 0x0000, 0x0000, 0x0000, 0x0000), vec!())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_empty_header(header: Header) -> Option<TryFromPacketError> {
|
||||||
|
let Header(_, a, b, c, d) = header;
|
||||||
|
if a != 0 || b != 0 || c != 0 || d != 0 {
|
||||||
|
Some(TryFromPacketError::ExtraneousHeaderValues)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_command_only(packet: Packet) -> Option<TryFromPacketError> {
|
||||||
|
let Packet(Header(_, a, b, c, d), payload) = packet;
|
||||||
|
if payload.len() != 0 {
|
||||||
|
Some(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
|
||||||
|
} else if a != 0 || b != 0 || c != 0 || d != 0 {
|
||||||
|
Some(TryFromPacketError::ExtraneousHeaderValues)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn packet_into_linear_bitmap(packet: Packet) -> Result<(BitVec, CompressionCode), TryFromPacketError> {
|
||||||
|
let Packet(Header(_, _, length, sub, reserved), payload) = packet;
|
||||||
|
if reserved != 0 {
|
||||||
|
return Err(TryFromPacketError::ExtraneousHeaderValues);
|
||||||
|
}
|
||||||
|
if payload.len() != length as usize {
|
||||||
|
return Err(TryFromPacketError::UnexpectedPayloadSize(length as usize, payload.len()));
|
||||||
|
}
|
||||||
|
let sub = match CompressionCode::from_primitive(sub) {
|
||||||
|
None => return Err(TryFromPacketError::InvalidCompressionCode(sub)),
|
||||||
|
Some(value) => value
|
||||||
|
};
|
||||||
|
let payload = match sub {
|
||||||
|
CompressionCode::None => payload,
|
||||||
|
CompressionCode::Gz => {
|
||||||
|
let mut decoder = GzDecoder::new(&*payload);
|
||||||
|
let mut decompressed = vec!();
|
||||||
|
match decoder.read_to_end(&mut decompressed) {
|
||||||
|
Err(err) => return Err(TryFromPacketError::DecompressionFailed(err)),
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
|
decompressed
|
||||||
|
}
|
||||||
|
CompressionCode::Bz => todo!(),
|
||||||
|
CompressionCode::Lz => todo!(),
|
||||||
|
CompressionCode::Zs => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((BitVec::load(&payload), sub))
|
||||||
|
}
|
||||||
|
|
|
@ -27,4 +27,24 @@ impl CommandCode {
|
||||||
pub fn to_primitive(&self) -> u16 {
|
pub fn to_primitive(&self) -> u16 {
|
||||||
ToPrimitive::to_u16(self).unwrap()
|
ToPrimitive::to_u16(self).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Debug, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum CompressionCode {
|
||||||
|
None = 0x0,
|
||||||
|
Gz = 0x677a,
|
||||||
|
Bz = 0x627a,
|
||||||
|
Lz = 0x6c7a,
|
||||||
|
Zs = 0x7a73,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompressionCode {
|
||||||
|
pub fn from_primitive(value: u16) -> Option<Self> {
|
||||||
|
FromPrimitive::from_u16(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_primitive(&self) -> u16 {
|
||||||
|
ToPrimitive::to_u16(self).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ impl Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a command to the display
|
/// Send a command to the display
|
||||||
pub fn send(&self, packet: impl Into<Packet> + Debug) -> std::io::Result<()> {
|
pub fn send(&self, packet: impl Into<Packet> + Debug) -> Result<(), std::io::Error> {
|
||||||
debug!("sending {packet:?}");
|
debug!("sending {packet:?}");
|
||||||
let packet = packet.into();
|
let packet: Packet = packet.into();
|
||||||
let data: Vec<u8> = packet.into();
|
let data: Vec<u8> = packet.into();
|
||||||
self.socket.send(&*data)?;
|
self.socket.send(&*data)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub use crate::pixel_grid::PixelGrid;
|
||||||
pub use crate::bit_vec::BitVec;
|
pub use crate::bit_vec::BitVec;
|
||||||
pub use crate::packet::{Packet, Header, Payload};
|
pub use crate::packet::{Packet, Header, Payload};
|
||||||
pub use crate::command::{Command, Size, Origin};
|
pub use crate::command::{Command, Size, Origin};
|
||||||
pub use crate::command_codes::CommandCode;
|
pub use crate::command_codes::{CommandCode, CompressionCode};
|
||||||
pub use crate::byte_grid::ByteGrid;
|
pub use crate::byte_grid::ByteGrid;
|
||||||
|
|
||||||
pub const TILE_SIZE: u16 = 8;
|
pub const TILE_SIZE: u16 = 8;
|
||||||
|
|
Loading…
Reference in a new issue