Merge branch 'next' into 'main'
This commit is contained in:
commit
69d4cff0bf
34 changed files with 1338 additions and 203 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use nix
|
||||||
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -540,7 +540,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint"
|
name = "servicepoint"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bzip2",
|
"bzip2",
|
||||||
"clap 4.5.4",
|
"clap 4.5.4",
|
||||||
|
|
@ -553,7 +553,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint_binding_c"
|
name = "servicepoint_binding_c"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"servicepoint",
|
"servicepoint",
|
||||||
|
|
@ -561,7 +561,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servicepoint_binding_cs"
|
name = "servicepoint_binding_cs"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"csbindgen",
|
"csbindgen",
|
||||||
"servicepoint",
|
"servicepoint",
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,7 @@ members = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
missing-docs = "warn"
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,6 @@ all_compressions = ["compression_zlib", "compression_bzip2", "compression_lzma",
|
||||||
# for examples
|
# for examples
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ fn main() {
|
||||||
.expect("connection failed");
|
.expect("connection failed");
|
||||||
|
|
||||||
// clear screen content
|
// clear screen content
|
||||||
connection.send(servicepoint::Command::Clear.into())
|
connection.send(servicepoint::Command::Clear)
|
||||||
.expect("send failed");
|
.expect("send failed");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -46,7 +46,7 @@ In the likely case you only need one of them, you can include that one specifica
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
servicepoint = { version = "0.5.0", default-features = false, features = ["compression-bz"] }
|
servicepoint = { version = "0.5.1", default-features = false, features = ["compression-bz"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Everything else
|
## Everything else
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! An example for how to send text to the display.
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
use servicepoint::{ByteGrid, Command, Connection, Grid, Origin};
|
use servicepoint::{ByteGrid, Command, Connection, Grid, Origin};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! A simple game of life implementation to show how to render graphics to the display.
|
||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! A simple example for how to send pixel data to the display.
|
||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
//! A simple example for how to set brightnesses for tiles on the screen.
|
||||||
|
//! Continuously changes the tiles in a random window to random brightnesses.
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//! An example on how to modify the image on screen without knowing the current content.
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::DataRef;
|
use crate::DataRef;
|
||||||
|
|
||||||
/// A vector of bits
|
/// A fixed-size vector of bits
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct BitVec {
|
pub struct BitVec {
|
||||||
size: usize,
|
size: usize,
|
||||||
|
|
@ -8,17 +8,17 @@ pub struct BitVec {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitVec {
|
impl BitVec {
|
||||||
/// Create a new bit vector.
|
/// Create a new `BitVec`.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `size`: size in bits. Must be dividable by 8.
|
/// * `size`: size in bits.
|
||||||
///
|
///
|
||||||
/// returns: bit vector with all bits set to false.
|
/// returns: `BitVec` with all bits set to false.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When size is not a multiple of 8.
|
/// When `size` is not divisible by 8.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(size: usize) -> BitVec {
|
pub fn new(size: usize) -> BitVec {
|
||||||
assert_eq!(size % 8, 0);
|
assert_eq!(size % 8, 0);
|
||||||
|
|
@ -36,6 +36,10 @@ impl BitVec {
|
||||||
/// * `value`: the value to set the bit to
|
/// * `value`: the value to set the bit to
|
||||||
///
|
///
|
||||||
/// returns: old value of the bit
|
/// returns: old value of the bit
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `index` out of bounds.
|
||||||
pub fn set(&mut self, index: usize, value: bool) -> bool {
|
pub fn set(&mut self, index: usize, value: bool) -> bool {
|
||||||
let (byte_index, bit_mask) = self.get_indexes(index);
|
let (byte_index, bit_mask) = self.get_indexes(index);
|
||||||
|
|
||||||
|
|
@ -58,6 +62,10 @@ impl BitVec {
|
||||||
/// * `index`: the bit index to read
|
/// * `index`: the bit index to read
|
||||||
///
|
///
|
||||||
/// returns: value of the bit
|
/// returns: value of the bit
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `index` out of bounds.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self, index: usize) -> bool {
|
pub fn get(&self, index: usize) -> bool {
|
||||||
let (byte_index, bit_mask) = self.get_indexes(index);
|
let (byte_index, bit_mask) = self.get_indexes(index);
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,18 @@ impl Grid<u8> for ByteGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the cell at the specified position in the `ByteGrid.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` and `y`: position of the cell
|
||||||
|
/// * `value`: the value to write to the cell
|
||||||
|
///
|
||||||
|
/// returns: old value of the cell.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `x` or `y` out of bounds.
|
||||||
fn set(&mut self, x: usize, y: usize, value: u8) -> u8 {
|
fn set(&mut self, x: usize, y: usize, value: u8) -> u8 {
|
||||||
self.check_indexes(x, y);
|
self.check_indexes(x, y);
|
||||||
let pos = &mut self.data[x + y * self.width];
|
let pos = &mut self.data[x + y * self.width];
|
||||||
|
|
@ -60,6 +72,15 @@ impl Grid<u8> for ByteGrid {
|
||||||
old_val
|
old_val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the current value at the specified position.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` and `y`: position of the cell to read
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `x` or `y` out of bounds.
|
||||||
fn get(&self, x: usize, y: usize) -> u8 {
|
fn get(&self, x: usize, y: usize) -> u8 {
|
||||||
self.check_indexes(x, y);
|
self.check_indexes(x, y);
|
||||||
self.data[x + y * self.width]
|
self.data[x + y * self.width]
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,19 @@
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum CompressionCode {
|
pub enum CompressionCode {
|
||||||
|
/// no compression
|
||||||
Uncompressed = 0x0,
|
Uncompressed = 0x0,
|
||||||
#[cfg(feature = "compression_zlib")]
|
#[cfg(feature = "compression_zlib")]
|
||||||
|
/// compress using flate2 with zlib header
|
||||||
Zlib = 0x677a,
|
Zlib = 0x677a,
|
||||||
#[cfg(feature = "compression_bzip2")]
|
#[cfg(feature = "compression_bzip2")]
|
||||||
|
/// compress using bzip2
|
||||||
Bzip2 = 0x627a,
|
Bzip2 = 0x627a,
|
||||||
#[cfg(feature = "compression_lzma")]
|
#[cfg(feature = "compression_lzma")]
|
||||||
|
/// compress using lzma
|
||||||
Lzma = 0x6c7a,
|
Lzma = 0x6c7a,
|
||||||
#[cfg(feature = "compression_zstd")]
|
#[cfg(feature = "compression_zstd")]
|
||||||
|
/// compress using Zstandard
|
||||||
Zstd = 0x7a73,
|
Zstd = 0x7a73,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
|
/// A two-dimensional grid of `T`
|
||||||
pub trait Grid<T> {
|
pub trait Grid<T> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Creates a new Grid with the specified dimensions.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// - width: size in x-direction
|
||||||
|
/// - height: size in y-direction
|
||||||
|
///
|
||||||
|
/// returns: Grid with all cells initialized to default state.
|
||||||
fn new(width: usize, height: usize) -> Self;
|
fn new(width: usize, height: usize) -> Self;
|
||||||
|
|
||||||
/// Sets the value at the specified position
|
/// Sets the value at the specified position
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Abstractions for the UDP protocol of the CCCB servicepoint display.
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub use crate::bit_vec::BitVec;
|
pub use crate::bit_vec::BitVec;
|
||||||
|
|
@ -42,3 +44,8 @@ pub const PIXEL_COUNT: usize = PIXEL_WIDTH * PIXEL_HEIGHT;
|
||||||
|
|
||||||
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
|
/// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
|
||||||
pub const FRAME_PACING: Duration = Duration::from_millis(30);
|
pub const FRAME_PACING: Duration = Duration::from_millis(30);
|
||||||
|
|
||||||
|
// include README.md in doctest
|
||||||
|
#[doc = include_str!("../README.md")]
|
||||||
|
#[cfg(doctest)]
|
||||||
|
pub struct ReadmeDocTests;
|
||||||
|
|
|
||||||
|
|
@ -75,15 +75,42 @@ impl Grid<bool> for PixelGrid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the value of the specified position in the `PixelGrid`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` and `y`: position of the cell
|
||||||
|
/// * `value`: the value to write to the cell
|
||||||
|
///
|
||||||
|
/// returns: old value of the cell
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `x` or `y` out of bounds.
|
||||||
fn set(&mut self, x: usize, y: usize, value: bool) -> bool {
|
fn set(&mut self, x: usize, y: usize, value: bool) -> bool {
|
||||||
self.check_indexes(x, y);
|
self.check_indexes(x, y);
|
||||||
self.bit_vec.set(x + y * self.width, value)
|
self.bit_vec.set(x + y * self.width, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the current value at the specified position.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `x` and `y`: position of the cell to read
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When accessing `x` or `y` out of bounds.
|
||||||
fn get(&self, x: usize, y: usize) -> bool {
|
fn get(&self, x: usize, y: usize) -> bool {
|
||||||
self.bit_vec.get(x + y * self.width)
|
self.bit_vec.get(x + y * self.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the state of all pixels in the `PixelGrid`.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `this`: instance to write to
|
||||||
|
/// * `value`: the value to set all pixels to
|
||||||
fn fill(&mut self, value: bool) {
|
fn fill(&mut self, value: bool) {
|
||||||
self.bit_vec.fill(value);
|
self.bit_vec.fill(value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
[package]
|
[package]
|
||||||
name = "servicepoint_binding_c"
|
name = "servicepoint_binding_c"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
publish = false
|
publish = true
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "C bindings for the servicepoint crate."
|
description = "C bindings for the servicepoint crate."
|
||||||
homepage = "https://docs.rs/crate/servicepoint"
|
homepage = "https://docs.rs/crate/servicepoint_binding_c"
|
||||||
repository = "https://github.com/cccb/servicepoint"
|
repository = "https://github.com/cccb/servicepoint"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
links = "servicepoint"
|
links = "servicepoint"
|
||||||
|
|
@ -17,6 +17,9 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
cbindgen = "0.26.0"
|
cbindgen = "0.26.0"
|
||||||
|
|
||||||
[dependencies.servicepoint]
|
[dependencies.servicepoint]
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
path = "../servicepoint"
|
path = "../servicepoint"
|
||||||
features = ["all_compressions"]
|
features = ["all_compressions"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@
|
||||||
[](https://docs.rs/servicepoint/latest/servicepoint/)
|
[](https://docs.rs/servicepoint/latest/servicepoint/)
|
||||||
[](../../LICENSE)
|
[](../../LICENSE)
|
||||||
|
|
||||||
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall. It is called "Service Point
|
In [CCCB](https://berlin.ccc.de/), there is a big pixel matrix hanging on the wall.
|
||||||
Display" or "Airport Display".
|
It is called "Service Point Display" or "Airport Display".
|
||||||
|
|
||||||
This crate contains C bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
|
This crate contains C bindings for the `servicepoint` library, enabling users to parse, encode and send packets to this display via UDP.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
//! Build script generating the header for the `servicepoint` C library.
|
||||||
|
//!
|
||||||
|
//! When the environment variable `SERVICEPOINT_HEADER_OUT` is set, the header is copied there from
|
||||||
|
//! the out directory. This can be used to use the build script as a command line tool from other
|
||||||
|
//! build tools.
|
||||||
|
|
||||||
use std::{env, fs::copy};
|
use std::{env, fs::copy};
|
||||||
|
|
||||||
use cbindgen::{generate_with_config, Config};
|
use cbindgen::{generate_with_config, Config};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
CC := gcc
|
CC := gcc
|
||||||
|
|
||||||
THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
REPO_ROOT := $(THIS_DIR)/../..
|
REPO_ROOT := $(THIS_DIR)/../../../..
|
||||||
|
|
||||||
build: out/lang_c
|
build: out/lang_c
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue