update to the (unreleased) version of servicepoint
All checks were successful
Rust / build (pull_request) Successful in 7m29s

This commit is contained in:
Vinzenz Schroeter 2025-03-08 12:42:37 +01:00
parent a903cbed85
commit 2efe86a592
10 changed files with 79 additions and 68 deletions

3
Cargo.lock generated
View file

@ -1702,8 +1702,7 @@ dependencies = [
[[package]] [[package]]
name = "servicepoint" name = "servicepoint"
version = "0.13.2" version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#300bb5d6474f0f6152ab04feed4478995fcb3ec8"
checksum = "33abd53582a995aaf5d387be4a1f7eb294a084185f88f8cf61652b6272041660"
dependencies = [ dependencies = [
"bitvec", "bitvec",
"log", "log",

View file

@ -13,7 +13,7 @@ homepage = "https://crates.io/crates/servicepoint-cli"
keywords = ["cccb", "cccb-servicepoint", "cli"] keywords = ["cccb", "cccb-servicepoint", "cli"]
[dependencies] [dependencies]
servicepoint = { version = "0.13.2", features = ["protocol_websocket"] } servicepoint = {features = ["protocol_websocket"] , git = "https://git.berlin.ccc.de/servicepoint/servicepoint/", branch = "next"}
clap = { version = "4.5", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11" env_logger = "0.11"
log = "0.4" log = "0.4"

View file

@ -1,8 +1,8 @@
use crate::cli::BrightnessCommand; use crate::cli::BrightnessCommand;
use log::info; use log::info;
use servicepoint::{Brightness, Command, Connection}; use servicepoint::{Brightness, Connection};
pub(crate) fn brightness(connection: &Connection, brightness_command: BrightnessCommand) { pub(crate) fn brightness(connection: &impl Connection, brightness_command: BrightnessCommand) {
match brightness_command { match brightness_command {
BrightnessCommand::Max => brightness_set(connection, Brightness::MAX), BrightnessCommand::Max => brightness_set(connection, Brightness::MAX),
BrightnessCommand::Min => brightness_set(connection, Brightness::MIN), BrightnessCommand::Min => brightness_set(connection, Brightness::MIN),
@ -12,9 +12,9 @@ pub(crate) fn brightness(connection: &Connection, brightness_command: Brightness
} }
} }
pub(crate) fn brightness_set(connection: &Connection, brightness: Brightness) { pub(crate) fn brightness_set(connection: &impl Connection, brightness: Brightness) {
connection connection
.send(Command::Brightness(brightness)) .send(servicepoint::BrightnessCommand::from(brightness))
.expect("Failed to set brightness"); .expect("Failed to set brightness");
info!("set brightness to {brightness:?}"); info!("set brightness to {brightness:?}");
} }

View file

@ -100,7 +100,7 @@ impl ImageProcessingPipeline {
let result = if self.options.no_dither { let result = if self.options.no_dither {
let cutoff = median_brightness(&orig); let cutoff = median_brightness(&orig);
let bits = orig.iter().map(move |x| x > &cutoff).collect(); let bits = orig.iter().map(move |x| x > &cutoff).collect();
Bitmap::from_bitvec(orig.width() as usize, bits) Bitmap::from_bitvec(orig.width() as usize, bits).unwrap()
} else { } else {
ostromoukhov_dither(orig, u8::MAX / 2) ostromoukhov_dither(orig, u8::MAX / 2)
}; };
@ -113,7 +113,7 @@ impl ImageProcessingPipeline {
let width = source.width(); let width = source.width();
let result_height = Self::calc_height_without_spacers(source.height()); let result_height = Self::calc_height_without_spacers(source.height());
let mut result = Bitmap::new(width, result_height); let mut result = Bitmap::new(width, result_height).unwrap();
let mut source_y = 0; let mut source_y = 0;
for result_y in 0..result_height { for result_y in 0..result_height {

View file

@ -200,7 +200,7 @@ pub(crate) fn ostromoukhov_dither(source: GrayImage, bias: u8) -> Bitmap {
} }
} }
Bitmap::from_bitvec(width as usize, destination) Bitmap::from_bitvec(width as usize, destination).unwrap()
} }
#[inline] #[inline]

View file

@ -6,7 +6,7 @@ use crate::{
}; };
use clap::Parser; use clap::Parser;
use log::debug; use log::debug;
use servicepoint::{Brightness, Connection}; use servicepoint::{Brightness, Connection, FakeConnection, UdpConnection, WebsocketConnection};
mod brightness; mod brightness;
mod cli; mod cli;
@ -22,13 +22,23 @@ fn main() {
init_logging(cli.verbose); init_logging(cli.verbose);
debug!("running with arguments: {:?}", cli); debug!("running with arguments: {:?}", cli);
let connection = make_connection(cli.destination, cli.transport);
debug!("connection established: {:#?}", connection); match cli.transport {
Protocol::Udp => {
execute_mode(cli.command, connection); let connection = UdpConnection::open(cli.destination).expect("Failed to open UDP connection");
execute_mode(cli.command, connection);},
Protocol::WebSocket => {
let url = cli.destination.parse().expect(
"provided destination is not a valid url - make sure it starts with 'ws://'",
);
let connection = WebsocketConnection::open(url).expect("Failed to open WebSocket connection");
execute_mode(cli.command, connection);
}
Protocol::Fake => execute_mode(cli.command, FakeConnection),
}
} }
pub fn execute_mode(mode: Mode, connection: Connection) { pub fn execute_mode(mode: Mode, connection: impl Connection) {
match mode { match mode {
Mode::ResetEverything => { Mode::ResetEverything => {
brightness_set(&connection, Brightness::MAX); brightness_set(&connection, Brightness::MAX);
@ -40,19 +50,6 @@ pub fn execute_mode(mode: Mode, connection: Connection) {
} }
} }
fn make_connection(destination: String, transport: Protocol) -> Connection {
match transport {
Protocol::Udp => Connection::open(destination).expect("Failed to open UDP connection"),
Protocol::WebSocket => {
let url = destination.parse().expect(
"provided destination is not a valid url - make sure it starts with 'ws://'",
);
Connection::open_websocket(url).expect("Failed to open WebSocket connection")
}
Protocol::Fake => Connection::Fake,
}
}
fn init_logging(debug: bool) { fn init_logging(debug: bool) {
let filter = if debug { let filter = if debug {
log::LevelFilter::Debug log::LevelFilter::Debug

View file

@ -1,12 +1,15 @@
use crate::{ use crate::{
image_processing::ImageProcessingPipeline,
cli::{ImageProcessingOptions, PixelCommand, SendImageOptions}, cli::{ImageProcessingOptions, PixelCommand, SendImageOptions},
stream_window::stream_window image_processing::ImageProcessingPipeline,
stream_window::stream_window,
}; };
use log::info; use log::info;
use servicepoint::{BitVec, Command, CompressionCode, Connection, Origin, PIXEL_COUNT}; use servicepoint::{
BinaryOperation, BitVec, BitVecCommand, BitmapCommand, ClearCommand, CompressionCode,
Connection, Origin, PIXEL_COUNT,
};
pub(crate) fn pixels(connection: &Connection, pixel_command: PixelCommand) { pub(crate) fn pixels(connection: &impl Connection, pixel_command: PixelCommand) {
match pixel_command { match pixel_command {
PixelCommand::Off => pixels_off(connection), PixelCommand::Off => pixels_off(connection),
PixelCommand::Flip => pixels_invert(connection), PixelCommand::Flip => pixels_invert(connection),
@ -22,31 +25,37 @@ pub(crate) fn pixels(connection: &Connection, pixel_command: PixelCommand) {
} }
} }
fn pixels_on(connection: &Connection) { fn pixels_on(connection: &impl Connection) {
let mask = BitVec::repeat(true, PIXEL_COUNT); let command = BitVecCommand {
connection offset: 0,
.send(Command::BitmapLinear(0, mask, CompressionCode::Lzma)) bitvec: BitVec::repeat(true, PIXEL_COUNT),
.expect("could not send command"); compression: CompressionCode::Lzma,
operation: BinaryOperation::Or,
};
connection.send(command).expect("could not send command");
info!("turned on all pixels") info!("turned on all pixels")
} }
fn pixels_invert(connection: &Connection) { fn pixels_invert(connection: &impl Connection) {
let mask = BitVec::repeat(true, PIXEL_COUNT); let command = BitVecCommand {
connection offset: 0,
.send(Command::BitmapLinearXor(0, mask, CompressionCode::Lzma)) bitvec: BitVec::repeat(true, PIXEL_COUNT),
.expect("could not send command"); compression: CompressionCode::Lzma,
operation: BinaryOperation::Xor,
};
connection.send(command).expect("could not send command");
info!("inverted all pixels"); info!("inverted all pixels");
} }
pub(crate) fn pixels_off(connection: &Connection) { pub(crate) fn pixels_off(connection: &impl Connection) {
connection connection
.send(Command::Clear) .send(ClearCommand)
.expect("failed to clear pixels"); .expect("failed to clear pixels");
info!("reset pixels"); info!("reset pixels");
} }
fn pixels_image( fn pixels_image(
connection: &Connection, connection: &impl Connection,
options: SendImageOptions, options: SendImageOptions,
processing_options: ImageProcessingOptions, processing_options: ImageProcessingOptions,
) { ) {
@ -54,11 +63,11 @@ fn pixels_image(
let mut pipeline = ImageProcessingPipeline::new(processing_options); let mut pipeline = ImageProcessingPipeline::new(processing_options);
let bitmap = pipeline.process(image); let bitmap = pipeline.process(image);
connection connection
.send(Command::BitmapLinearWin( .send(BitmapCommand {
Origin::ZERO, origin: Origin::ZERO,
bitmap, bitmap,
CompressionCode::default(), compression: CompressionCode::default(),
)) })
.expect("failed to send image command"); .expect("failed to send image command");
info!("sent image to display"); info!("sent image to display");
} }

View file

@ -2,7 +2,7 @@ use log::warn;
use servicepoint::*; use servicepoint::*;
use std::thread::sleep; use std::thread::sleep;
pub(crate) fn stream_stdin(connection: &Connection, slow: bool) { pub(crate) fn stream_stdin(connection: &impl Connection, slow: bool) {
warn!("This mode will break when using multi-byte characters and does not support ANSI escape sequences yet."); warn!("This mode will break when using multi-byte characters and does not support ANSI escape sequences yet.");
let mut app = App { let mut app = App {
connection, connection,
@ -13,17 +13,17 @@ pub(crate) fn stream_stdin(connection: &Connection, slow: bool) {
app.run() app.run()
} }
struct App<'t> { struct App<'t, TConnection: Connection> {
connection: &'t Connection, connection: &'t TConnection,
mirror: CharGrid, mirror: CharGrid,
y: usize, y: usize,
slow: bool, slow: bool,
} }
impl App<'_> { impl<TConnection: Connection> App<'_, TConnection> {
fn run(&mut self) { fn run(&mut self) {
self.connection self.connection
.send(Command::Clear) .send(ClearCommand)
.expect("couldn't clear screen"); .expect("couldn't clear screen");
let last_y = self.mirror.height() - 1; let last_y = self.mirror.height() - 1;
for line in std::io::stdin().lines() { for line in std::io::stdin().lines() {
@ -62,11 +62,12 @@ impl App<'_> {
} }
fn send_mirror(&self) { fn send_mirror(&self) {
let command = CharGridCommand {
origin: Origin::ZERO,
grid: self.mirror.clone(),
};
self.connection self.connection
.send(Command::Utf8Data( .send(command)
Origin::ZERO,
self.mirror.clone(),
))
.expect("couldn't send screen to display"); .expect("couldn't send screen to display");
} }
@ -75,8 +76,12 @@ impl App<'_> {
line_grid.fill(' '); line_grid.fill(' ');
Self::line_onto_grid(&mut line_grid, 0, line); Self::line_onto_grid(&mut line_grid, 0, line);
Self::line_onto_grid(&mut self.mirror, self.y, line); Self::line_onto_grid(&mut self.mirror, self.y, line);
let command = CharGridCommand {
origin: Origin::new(0, self.y),
grid: line_grid,
};
self.connection self.connection
.send(Command::Utf8Data(Origin::new(0, self.y), line_grid)) .send(command)
.expect("couldn't send single line to screen"); .expect("couldn't send single line to screen");
} }
} }

View file

@ -9,11 +9,11 @@ use scap::{
frame::convert_bgra_to_rgb, frame::convert_bgra_to_rgb,
frame::Frame, frame::Frame,
}; };
use servicepoint::{Command, CompressionCode, Connection, Origin, FRAME_PACING}; use servicepoint::{BitmapCommand, CompressionCode, Connection, Origin, FRAME_PACING};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
pub fn stream_window( pub fn stream_window(
connection: &Connection, connection: &impl Connection,
options: StreamScreenOptions, options: StreamScreenOptions,
processing_options: ImageProcessingOptions, processing_options: ImageProcessingOptions,
) { ) {
@ -35,12 +35,13 @@ pub fn stream_window(
trace!("bitmap ready to send in: {:?}", start.elapsed()); trace!("bitmap ready to send in: {:?}", start.elapsed());
let command = BitmapCommand {
compression: CompressionCode::default(),
bitmap: bitmap.clone(),
origin: Origin::ZERO,
};
connection connection
.send(Command::BitmapLinearWin( .send(command)
Origin::ZERO,
bitmap.clone(),
CompressionCode::default(),
))
.expect("failed to send frame to display"); .expect("failed to send frame to display");
debug!("frame time: {:?}", start.elapsed()); debug!("frame time: {:?}", start.elapsed());

View file

@ -2,6 +2,6 @@ use servicepoint::Connection;
use crate::cli::TextCommand; use crate::cli::TextCommand;
use crate::stream_stdin::stream_stdin; use crate::stream_stdin::stream_stdin;
pub fn text(connection: &Connection, command: TextCommand) { pub fn text(connection: &impl Connection, command: TextCommand) {
match command { TextCommand::Stdin { slow } => stream_stdin(connection, slow), } match command { TextCommand::Stdin { slow } => stream_stdin(connection, slow), }
} }