add c api

This commit is contained in:
Vinzenz Schroeter 2024-05-12 17:15:30 +02:00
parent 01d1f1dad0
commit 98e8a6d639
14 changed files with 832 additions and 23 deletions

290
Cargo.lock generated
View file

@ -21,7 +21,7 @@ dependencies = [
name = "announce"
version = "0.1.0"
dependencies = [
"clap",
"clap 4.5.4",
"env_logger",
"servicepoint2",
]
@ -75,6 +75,35 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bzip2"
version = "0.4.4"
@ -96,6 +125,25 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "cbindgen"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
dependencies = [
"clap 3.2.25",
"heck 0.4.1",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 1.0.109",
"tempfile",
"toml",
]
[[package]]
name = "cc"
version = "1.0.97"
@ -113,6 +161,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_lex 0.2.4",
"indexmap",
"strsim 0.10.0",
"termcolor",
"textwrap",
]
[[package]]
name = "clap"
version = "4.5.4"
@ -131,8 +194,8 @@ checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"clap_lex 0.7.0",
"strsim 0.11.1",
]
[[package]]
@ -141,10 +204,19 @@ version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"syn",
"syn 2.0.63",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
@ -191,6 +263,22 @@ dependencies = [
"log",
]
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "flate2"
version = "1.0.30"
@ -205,7 +293,7 @@ dependencies = [
name = "game_of_life"
version = "0.1.0"
dependencies = [
"clap",
"clap 4.5.4",
"env_logger",
"rand",
"servicepoint2",
@ -222,24 +310,61 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jobserver"
version = "0.1.31"
@ -255,6 +380,12 @@ version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "log"
version = "0.4.21"
@ -300,7 +431,7 @@ dependencies = [
name = "moving_line"
version = "0.1.0"
dependencies = [
"clap",
"clap 4.5.4",
"env_logger",
"servicepoint2",
]
@ -311,6 +442,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "os_str_bytes"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]]
name = "pkg-config"
version = "0.3.30"
@ -375,7 +512,7 @@ dependencies = [
name = "random_brightness"
version = "0.1.0"
dependencies = [
"clap",
"clap 4.5.4",
"env_logger",
"rand",
"servicepoint2",
@ -410,23 +547,91 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.63",
]
[[package]]
name = "serde_json"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "servicepoint2"
version = "0.1.3"
dependencies = [
"bzip2",
"cbindgen",
"flate2",
"log",
"lz4",
"zstd",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.63"
@ -438,6 +643,42 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
"fastrand",
"rustix",
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@ -456,6 +697,37 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -533,7 +805,7 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
name = "wiping_clear"
version = "0.1.0"
dependencies = [
"clap",
"clap 4.5.4",
"env_logger",
"servicepoint2",
]

View file

@ -4,8 +4,7 @@ use std::time::Duration;
use clap::Parser;
use rand::{distributions, Rng};
use servicepoint2::{Connection, Origin, PixelGrid};
use servicepoint2::Command::BitmapLinearWin;
use servicepoint2::{Command, Connection, Origin, PixelGrid};
#[derive(Parser, Debug)]
struct Cli {
@ -24,7 +23,7 @@ fn main() {
loop {
connection
.send(BitmapLinearWin(Origin::top_left(), field.clone()))
.send(Command::BitmapLinearWin(Origin::top_left(), field.clone()))
.expect("could not send");
thread::sleep(Duration::from_millis(14));
field = iteration(field);

View file

@ -3,8 +3,7 @@ use std::time::Duration;
use clap::Parser;
use servicepoint2::Command::BitmapLinearWin;
use servicepoint2::{Connection, Origin, PixelGrid, PIXEL_HEIGHT, PIXEL_WIDTH};
use servicepoint2::{Command, Connection, Origin, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid};
#[derive(Parser, Debug)]
struct Cli {
@ -25,7 +24,7 @@ fn main() {
pixels.set((y + x_offset) % PIXEL_WIDTH as usize, y, true);
}
connection
.send(BitmapLinearWin(Origin::top_left(), pixels.clone()))
.send(Command::BitmapLinearWin(Origin::top_left(), pixels.clone()))
.unwrap();
thread::sleep(Duration::from_millis(14));
}

View file

@ -3,9 +3,8 @@ use std::time::Duration;
use clap::Parser;
use servicepoint2::Command::BitmapLinearAnd;
use servicepoint2::{
BitVec, CompressionCode, Connection, PixelGrid, PIXEL_HEIGHT, PIXEL_WIDTH,
BitVec, Command, CompressionCode, Connection, PIXEL_HEIGHT, PIXEL_WIDTH, PixelGrid
};
#[derive(Parser, Debug)]
@ -37,7 +36,7 @@ fn main() {
let bit_vec = BitVec::from(&*pixel_data);
connection
.send(BitmapLinearAnd(0, bit_vec, CompressionCode::Gz))
.send(Command::BitmapLinearAnd(0, bit_vec, CompressionCode::Gz))
.unwrap();
thread::sleep(sleep_duration);
}

View file

@ -23,3 +23,6 @@ compression-bz = ["dep:bzip2", "compression"]
compression-lz = ["dep:lz4", "compression"]
compression-zs = ["dep:zstd", "compression"]
compression = []
[build-dependencies]
cbindgen = "0.26.0"

186
servicepoint2/bindings.h Normal file
View file

@ -0,0 +1,186 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/**
* size of a single tile in one dimension
*/
#define sp2_TILE_SIZE 8
/**
* tile count in the x-direction
*/
#define sp2_TILE_WIDTH 56
/**
* tile count in the y-direction
*/
#define sp2_TILE_HEIGHT 20
/**
* screen width in pixels
*/
#define sp2_PIXEL_WIDTH (sp2_TILE_WIDTH * sp2_TILE_SIZE)
/**
* screen height in pixels
*/
#define sp2_PIXEL_HEIGHT (sp2_TILE_HEIGHT * sp2_TILE_SIZE)
/**
* pixel count on whole screen
*/
#define sp2_PIXEL_COUNT ((uintptr_t)sp2_PIXEL_WIDTH * (uintptr_t)sp2_PIXEL_HEIGHT)
/**
* Specifies the kind of compression to use. Availability depends on features.
*/
enum sp2_CompressionCode {
Uncompressed = 0,
Gz = 26490,
Bz = 25210,
Lz = 27770,
Zs = 31347,
};
typedef uint16_t sp2_CompressionCode;
/**
* A vector of bits
*/
typedef struct sp2_BitVec sp2_BitVec;
/**
* A grid of bytes
*/
typedef struct sp2_ByteGrid sp2_ByteGrid;
/**
* A command to send to the display.
*/
typedef struct sp2_Command sp2_Command;
/**
* A connection to the display.
*/
typedef struct sp2_Connection sp2_Connection;
/**
* A grid of pixels stored in packed bytes.
*/
typedef struct sp2_PixelGrid sp2_PixelGrid;
typedef uint8_t sp2_Brightness;
typedef uint16_t sp2_Offset;
/**
* Tries to load a command from the passed array with the specified length.
*
* returns: NULL in case of an error, pointer to the allocated command otherwise
*/
struct sp2_Command *command_try_load(const uint8_t *data, uintptr_t length);
/**
* Clones a `Command` instance
*/
struct sp2_Command *command_clone(const struct sp2_Command *original);
/**
* Allocates a new `Command::Clear` instance
*/
struct sp2_Command *command_clear(void);
/**
* Allocates a new `Command::HardReset` instance
*/
struct sp2_Command *command_hard_reset(void);
/**
* Allocates a new `Command::FadeOut` instance
*/
struct sp2_Command *command_fade_out(void);
/**
* Allocates a new `Command::Brightness` instance
*/
struct sp2_Command *command_brightness(sp2_Brightness brightness);
/**
* Allocates a new `Command::CharBrightness` instance.
* The passed `ByteGrid` gets deallocated in the process.
*/
struct sp2_Command *command_char_brightness(uint16_t x, uint16_t y, struct sp2_ByteGrid *byte_grid);
/**
* Allocates a new `Command::BitmapLinear` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *command_bitmap_linear(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearAnd` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *command_bitmap_linear_and(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearOr` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *command_bitmap_linear_or(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
/**
* Allocates a new `Command::BitmapLinearXor` instance.
* The passed `BitVec` gets deallocated in the process.
*/
struct sp2_Command *command_bitmap_linear_xor(sp2_Offset offset,
struct sp2_BitVec *bit_vec,
sp2_CompressionCode compression);
/**
* Allocates a new `Command::Cp437Data` instance.
* The passed `ByteGrid` gets deallocated in the process.
*/
struct sp2_Command *command_cp437_data(uint16_t x, uint16_t y, struct sp2_ByteGrid *byte_grid);
/**
* Allocates a new `Command::BitmapLinearWin` instance.
* The passed `PixelGrid` gets deallocated in the process.
*/
struct sp2_Command *command_bitmap_linear_win(uint16_t x,
uint16_t y,
struct sp2_PixelGrid *byte_grid);
/**
* Deallocates a command. Note that connection_send does this implicitly, so you only need
* to do this if you use the library for parsing commands.
*/
void command_dealloc(struct sp2_Command *ptr);
/**
* Creates a new instance of Connection.
* The returned instance has to be deallocated with `connection_dealloc`.
*
* returns: NULL if connection fails or connected instance
*
* Panics: bad string encoding
*/
struct sp2_Connection *connection_open(const char *host);
/**
* Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
*/
bool connection_send(const struct sp2_Connection *connection,
struct sp2_Command *command_ptr);
/**
* Closes and deallocates a connection instance
*/
void connection_dealloc(struct sp2_Connection *ptr);

16
servicepoint2/build.rs Normal file
View file

@ -0,0 +1,16 @@
extern crate cbindgen;
use std::env;
use cbindgen::Language;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::Builder::new()
.with_crate(crate_dir)
.with_item_prefix("sp2_")
.with_language(Language::C)
.generate()
.expect("Unable to generate bindings")
.write_to_file("bindings.h");
}

View file

@ -105,3 +105,54 @@ impl std::fmt::Debug for BitVec {
.finish()
}
}
#[allow(unused)]
pub mod c_api {
use crate::BitVec;
/// Creates a new `BitVec` instance.
/// The returned instance has to be freed with `bit_vec_dealloc`.
pub unsafe extern "C" fn bit_vec_new(size: usize) -> *mut BitVec {
Box::into_raw(Box::new(BitVec::new(size)))
}
/// Loads a `BitVec` from the provided data.
/// The returned instance has to be freed with `bit_vec_dealloc`.
pub unsafe extern "C" fn byte_grid_load(data: *const u8, data_length: usize) -> *mut BitVec {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(BitVec::from(data)))
}
/// Clones a `BitVec`.
/// The returned instance has to be freed with `bit_vec_dealloc`.
pub unsafe extern "C" fn byte_grid_clone(this: *const BitVec) -> *mut BitVec {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `BitVec`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
pub unsafe extern "C" fn byte_grid_dealloc(this: *mut BitVec) {
_ = Box::from_raw(this);
}
/// Gets the value of a bit from the `BitVec`.
pub unsafe extern "C" fn byte_grid_get(this: *const BitVec, index: usize) -> bool {
(*this).get(index)
}
/// Sets the value of a bit in the `BitVec`.
pub unsafe extern "C" fn byte_grid_set(this: *mut BitVec, index: usize, value: bool) -> bool {
(*this).set(index, value)
}
/// Sets the value of all bits in the `BitVec`.
pub unsafe extern "C" fn byte_grid_fill(this: *mut BitVec, value: bool) {
(*this).fill(value)
}
/// Gets the length of the `BitVec` in bits.
pub unsafe extern "C" fn byte_grid_len(this: *const BitVec) -> usize{
(*this).len()
}
}

View file

@ -57,3 +57,60 @@ impl Into<Vec<u8>> for ByteGrid {
self.data
}
}
#[allow(unused)]
pub mod c_api
{
use crate::{ByteGrid, PixelGrid};
/// Creates a new `ByteGrid` instance.
/// The returned instance has to be freed with `byte_grid_dealloc`.
pub unsafe extern "C" fn byte_grid_new(width: usize, height: usize) -> *mut ByteGrid {
Box::into_raw(Box::new(ByteGrid::new(width, height)))
}
/// Loads a `ByteGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `byte_grid_dealloc`.
pub unsafe extern "C" fn byte_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut ByteGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(ByteGrid::load(width, height, data)))
}
/// Clones a `ByteGrid`.
/// The returned instance has to be freed with `byte_grid_dealloc`.
pub unsafe extern "C" fn byte_grid_clone(this: *const ByteGrid) -> *mut ByteGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `ByteGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
pub unsafe extern "C" fn byte_grid_dealloc(this: *mut ByteGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
pub unsafe extern "C" fn byte_grid_get(this: *const ByteGrid, x: usize, y: usize) -> u8 {
(*this).get(x, y)
}
/// Sets the current value at the specified position
pub unsafe extern "C" fn byte_grid_set(this: *mut ByteGrid, x: usize, y: usize, value: u8) {
(*this).set(x, y, value);
}
/// Fills the whole `ByteGrid` with the specified value
pub unsafe extern "C" fn byte_grid_fill(this: *mut ByteGrid, value: u8) {
(*this).fill(value);
}
/// Gets the width in pixels of the `ByteGrid` instance.
pub unsafe extern "C" fn pixel_grid_width(this: *const PixelGrid) -> usize {
(*this).width
}
/// Gets the height in pixels of the `ByteGrid` instance.
pub unsafe extern "C" fn pixel_grid_height(this: *const PixelGrid) -> usize {
(*this).height
}
}

View file

@ -1,8 +1,8 @@
use crate::compression::{into_compressed, into_decompressed};
use crate::{
BitVec, ByteGrid, CommandCode, CompressionCode, Header, Packet, PixelGrid,
TILE_SIZE,
};
use crate::compression::{into_compressed, into_decompressed};
/// An origin marks the top left position of a window sent to the display.
#[derive(Debug, Clone, Copy)]
@ -18,12 +18,12 @@ impl Origin {
#[derive(Debug, Clone, Copy)]
pub struct Size(pub u16, pub u16);
type Offset = u16;
pub type Offset = u16;
type Brightness = u8;
pub type Brightness = u8;
/// A command to send to the display.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Command {
/// Set all pixels to the off state
Clear,
@ -315,3 +315,121 @@ fn packet_into_linear_bitmap(
};
Ok((BitVec::from(&*payload), sub))
}
#[allow(unused)]
pub mod c_api
{
use std::ptr::null_mut;
use crate::{BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet, PixelGrid};
/// Tries to load a command from the passed array with the specified length.
///
/// returns: NULL in case of an error, pointer to the allocated command otherwise
#[no_mangle]
pub unsafe extern "C" fn command_try_load(data: *const u8, length: usize) -> *mut Command {
let data = std::slice::from_raw_parts(data, length);
let packet = match Packet::try_from(data) {
Err(_) => return null_mut(),
Ok(packet) => packet
};
let command = match Command::try_from(packet) {
Err(_) => return null_mut(),
Ok(command) => command,
};
Box::into_raw(Box::new(command))
}
/// Clones a `Command` instance
#[no_mangle]
pub unsafe extern "C" fn command_clone(original: *const Command) -> *mut Command {
Box::into_raw(Box::new((*original).clone()))
}
/// Allocates a new `Command::Clear` instance
#[no_mangle]
pub unsafe extern "C" fn command_clear() -> *mut Command {
Box::into_raw(Box::new(Command::Clear))
}
/// Allocates a new `Command::HardReset` instance
#[no_mangle]
pub unsafe extern "C" fn command_hard_reset() -> *mut Command {
Box::into_raw(Box::new(Command::HardReset))
}
/// Allocates a new `Command::FadeOut` instance
#[no_mangle]
pub unsafe extern "C" fn command_fade_out() -> *mut Command {
Box::into_raw(Box::new(Command::FadeOut))
}
/// Allocates a new `Command::Brightness` instance
#[no_mangle]
pub unsafe extern "C" fn command_brightness(brightness: Brightness) -> *mut Command {
Box::into_raw(Box::new(Command::Brightness(brightness)))
}
/// Allocates a new `Command::CharBrightness` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_char_brightness(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinear` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_bitmap_linear(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinear(offset, bit_vec, compression)))
}
/// Allocates a new `Command::BitmapLinearAnd` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_bitmap_linear_and(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearAnd(offset, bit_vec, compression)))
}
/// Allocates a new `Command::BitmapLinearOr` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_bitmap_linear_or(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearOr(offset, bit_vec, compression)))
}
/// Allocates a new `Command::BitmapLinearXor` instance.
/// The passed `BitVec` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_bitmap_linear_xor(offset: Offset, bit_vec: *mut BitVec, compression: CompressionCode) -> *mut Command {
let bit_vec = *Box::from_raw(bit_vec);
Box::into_raw(Box::new(Command::BitmapLinearXor(offset, bit_vec, compression)))
}
/// Allocates a new `Command::Cp437Data` instance.
/// The passed `ByteGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_cp437_data(x: u16, y: u16, byte_grid: *mut ByteGrid) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinearWin` instance.
/// The passed `PixelGrid` gets deallocated in the process.
#[no_mangle]
pub unsafe extern "C" fn command_bitmap_linear_win(x: u16, y: u16, byte_grid: *mut PixelGrid) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::BitmapLinearWin(Origin(x, y), byte_grid)))
}
/// Deallocates a command. Note that connection_send does this implicitly, so you only need
/// to do this if you use the library for parsing commands.
#[no_mangle]
pub unsafe extern "C" fn command_dealloc(ptr: *mut Command) {
_ = Box::from_raw(ptr);
}
}

View file

@ -64,3 +64,42 @@ impl Connection {
Ok(())
}
}
pub mod c_api
{
use std::ffi::{c_char, CStr};
use std::ptr::null_mut;
use crate::{Command, Connection};
/// Creates a new instance of Connection.
/// The returned instance has to be deallocated with `connection_dealloc`.
///
/// returns: NULL if connection fails or connected instance
///
/// Panics: bad string encoding
#[no_mangle]
pub unsafe extern "C" fn connection_open(host: *const c_char) -> *mut Connection {
let host = CStr::from_ptr(host).to_str().expect("Bad encoding");
let connection = match Connection::open(host) {
Err(_) => return null_mut(),
Ok(value) => value
};
let boxed = Box::new(connection);
Box::into_raw(boxed)
}
/// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
#[no_mangle]
pub unsafe extern "C" fn connection_send(connection: *const Connection, command_ptr: *mut Command) -> bool{
let command = Box::from_raw(command_ptr);
(*connection).send(*command).is_ok()
}
/// Closes and deallocates a connection instance
#[no_mangle]
pub unsafe extern "C" fn connection_dealloc(ptr: *mut Connection) {
_ = Box::from_raw(ptr);
}
}

View file

@ -1,6 +1,6 @@
pub use crate::bit_vec::BitVec;
pub use crate::byte_grid::ByteGrid;
pub use crate::command::{Command, Origin, Size};
pub use crate::command::{Brightness, Command, Offset, Origin, Size};
pub use crate::command_code::CommandCode;
pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection;

View file

@ -45,3 +45,16 @@ impl From<Payload> for Packet {
Packet(Header(mode, a, b, c, d), payload)
}
}
impl From<&[u8]> for Packet {
fn from(value: &[u8]) -> Self {
let mode = u16_from_be_slice(&value[0..=1]);
let a = u16_from_be_slice(&value[2..=3]);
let b = u16_from_be_slice(&value[4..=5]);
let c = u16_from_be_slice(&value[6..=7]);
let d = u16_from_be_slice(&value[8..=9]);
let payload = value[10..].to_vec();
Packet(Header(mode, a, b, c, d), payload)
}
}

View file

@ -83,3 +83,60 @@ impl Into<Vec<u8>> for PixelGrid {
self.bit_vec.into()
}
}
#[allow(unused)]
pub mod c_api
{
use crate::PixelGrid;
/// Creates a new `PixelGrid` instance.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
pub unsafe extern "C" fn pixel_grid_new(width: usize, height: usize) -> *mut PixelGrid {
Box::into_raw(Box::new(PixelGrid::new(width, height)))
}
/// Loads a `PixelGrid` with the specified dimensions from the provided data.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
pub unsafe extern "C" fn pixel_grid_load(width: usize, height: usize, data: *const u8, data_length: usize) -> *mut PixelGrid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(PixelGrid::load(width, height, data)))
}
/// Clones a `PixelGrid`.
/// The returned instance has to be freed with `pixel_grid_dealloc`.
pub unsafe extern "C" fn pixel_grid_clone(this: *const PixelGrid) -> *mut PixelGrid {
Box::into_raw(Box::new((*this).clone()))
}
/// Deallocates a `PixelGrid`.
///
/// Note: do not call this if the grid has been consumed in another way, e.g. to create a command.
pub unsafe extern "C" fn pixel_grid_dealloc(this: *mut PixelGrid) {
_ = Box::from_raw(this);
}
/// Get the current value at the specified position
pub unsafe extern "C" fn pixel_grid_get(this: *const PixelGrid, x: usize, y: usize) -> bool {
(*this).get(x, y)
}
/// Sets the current value at the specified position
pub unsafe extern "C" fn pixel_grid_set(this: *mut PixelGrid, x: usize, y: usize, value: bool) {
(*this).set(x, y, value);
}
/// Fills the whole `PixelGrid` with the specified value
pub unsafe extern "C" fn pixel_grid_fill(this: *mut PixelGrid, value: bool) {
(*this).fill(value);
}
/// Gets the width in pixels of the `PixelGrid` instance.
pub unsafe extern "C" fn pixel_grid_width(this: *const PixelGrid) -> usize {
(*this).width
}
/// Gets the height in pixels of the `PixelGrid` instance.
pub unsafe extern "C" fn pixel_grid_height(this: *const PixelGrid) -> usize {
(*this).height
}
}