update to the (unreleased) version of servicepoint
All checks were successful
Rust / build (pull_request) Successful in 7m29s
All checks were successful
Rust / build (pull_request) Successful in 7m29s
This commit is contained in:
parent
a903cbed85
commit
2efe86a592
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:?}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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]
|
||||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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), }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue