From c509813aacfd56363a26aa5496f3fcacf9615ecb Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 21:07:05 +0200 Subject: [PATCH 1/4] translate brightness tester --- example/Makefile | 31 +++++++++++++++++++++---------- example/announce.c | 3 +-- example/brightness_tester.c | 29 +++++++++++++++++++++++++++++ example/random_stuff.c | 5 ++--- flake.nix | 1 - 5 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 example/brightness_tester.c diff --git a/example/Makefile b/example/Makefile index 91083d4..bb53fe1 100644 --- a/example/Makefile +++ b/example/Makefile @@ -37,17 +37,20 @@ CCFLAGS := -static -Os \ -fvisibility=hidden \ -Bsymbolic \ -Wl,--exclude-libs,ALL \ - -fno-ident + -fno-ident \ + -Wall #-fuse-ld=gold \ -fno-exceptions #-Wl,--icf=all \ STRIPFLAGS := -s --strip-unneeded -R .comment -R .gnu.version -R .comment -R .note -R .note.gnu.build-id -R .note.ABI-tag -src := $(wildcard *.c) -programs := $(basename $(src)) +c_src := $(wildcard *.c) +programs := $(basename $(c_src)) bins := $(addprefix out/, $(programs)) unstripped_bins := $(addsuffix _unstripped, $(bins)) +run_programs := $(addprefix run_, $(programs)) +rs_src := $(wildcard ../src/*.rs) ../Cargo.lock all: $(bins) @@ -56,9 +59,9 @@ clean: rm include/servicepoint.h || true cargo clean -PHONY: all clean analyze-size +PHONY: all clean sizes $(run_programs) -$(unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoint.h +$(unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a mkdir -p out || true ${CC} $^ \ -I $(SERVICEPOINT_HEADER_OUT) \ @@ -69,14 +72,22 @@ $(unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoin $(bins): out/%: out/%_unstripped strip $(STRIPFLAGS) $^ -o $@ -$(SERVICEPOINT_HEADER_OUT)/servicepoint.h: FORCE +$(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a: $(rs_src) mkdir -p include || true # generate servicepoint header and binary to link against ${CARGO} rustc $(CARGOFLAGS) -- $(RUSTFLAGS) -analyze-size: out/example_unstripped - nm --print-size --size-sort --reverse-sort --radix=d --demangle out/example_unstripped \ - | awk '{size=$$2+0; print size "\t" $$4}' \ - | less +$(run_programs): run_%: out/% FORCE + ./$< + +sizes: $(bins) + ls -lB out + +#analyze-size: out/example_unstripped +# nm --print-size --size-sort --reverse-sort --radix=d --demangle out/example_unstripped \ +# | awk '{size=$$2+0; print size "\t" $$4}' \ +# | less + + FORCE: ; diff --git a/example/announce.c b/example/announce.c index 6cf3dc4..d7a55fb 100644 --- a/example/announce.c +++ b/example/announce.c @@ -1,4 +1,3 @@ -#include #include "servicepoint.h" int main(void) { @@ -8,7 +7,7 @@ int main(void) { sp_udp_send_command(connection, sp_command_clear()); - CharGrid *grid = sp_char_grid_new(5,2); + CharGrid *grid = sp_char_grid_new(5, 2); if (grid == NULL) return 1; diff --git a/example/brightness_tester.c b/example/brightness_tester.c new file mode 100644 index 0000000..93e64ce --- /dev/null +++ b/example/brightness_tester.c @@ -0,0 +1,29 @@ +#include "servicepoint.h" + +int main(void) { + // UdpConnection *connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); + UdpConnection *connection = sp_udp_open_ipv4(127, 0, 0, 1, 2342); + if (connection == NULL) + return -1; + + Bitmap *all_on = sp_bitmap_new_max_sized(); + sp_bitmap_fill(all_on, true); + TypedCommand *cmd = sp_command_bitmap(0, 0, all_on, COMPRESSION_CODE_UNCOMPRESSED); + if (cmd == NULL) + return -1; + + sp_udp_send_command(connection, cmd); + + BrightnessGrid *grid = sp_brightness_grid_new(TILE_WIDTH, TILE_HEIGHT); + + ByteSlice slice = sp_brightness_grid_unsafe_data_ref(grid); + for (size_t index = 0; index < slice.length; index++) { + slice.start[index] = (uint8_t) (index % ((size_t) Brightness_MAX)); + } + + TypedCommand *command = sp_command_brightness_grid(0, 0, grid); + sp_udp_send_command(connection, command); + + sp_udp_free(connection); + return 0; +} diff --git a/example/random_stuff.c b/example/random_stuff.c index 9c0ec9e..80c3847 100644 --- a/example/random_stuff.c +++ b/example/random_stuff.c @@ -1,4 +1,3 @@ -#include #include "servicepoint.h" int main(void) { @@ -8,13 +7,13 @@ int main(void) { Bitmap *pixels = sp_bitmap_new(PIXEL_WIDTH, PIXEL_HEIGHT); if (pixels == NULL) - return 1; + return 1; sp_bitmap_fill(pixels, true); TypedCommand *command = sp_command_bitmap(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); if (command == NULL) - return 1; + return 1; Packet *packet = sp_packet_from_command(command); diff --git a/flake.nix b/flake.nix index 1f0ac97..b4f874f 100644 --- a/flake.nix +++ b/flake.nix @@ -59,7 +59,6 @@ gcc gnumake pkg-config - ]; RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; From a3e2dcb3c2159d642d7ea6952d191cbc98080f34 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 21:47:23 +0200 Subject: [PATCH 2/4] add command code constants, send header --- Cargo.lock | 2 +- Cargo.toml | 3 ++ example/Makefile | 37 ++++++++-------- example/announce.c | 8 ++-- include/servicepoint.h | 63 +++++++++++++++++++++++---- src/brightness_grid.rs | 6 +-- src/byte_slice.rs | 2 +- src/commands/mod.rs | 3 ++ src/{command.rs => commands/typed.rs} | 10 +---- src/connection.rs | 34 ++++++++++++--- src/lib.rs | 11 ++--- src/packet.rs | 22 ++++++++-- 12 files changed, 141 insertions(+), 60 deletions(-) create mode 100644 src/commands/mod.rs rename src/{command.rs => commands/typed.rs} (94%) diff --git a/Cargo.lock b/Cargo.lock index f87ecea..968bfeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,7 +408,7 @@ dependencies = [ [[package]] name = "servicepoint" version = "0.13.2" -source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#531d4e6b4a368dc126cab9dc12b64d2ca8a81694" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#114385868af03f8cba7c87a630b501bb0106d140" dependencies = [ "bitvec", "bzip2", diff --git a/Cargo.toml b/Cargo.toml index 7e5ed5d..e92ceb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,9 @@ default = ["full"] missing-docs = "warn" unsafe_op_in_unsafe_fn = "warn" +[lints.clippy] +missing_safety_doc = "allow" + [package.metadata.docs.rs] all-features = true diff --git a/example/Makefile b/example/Makefile index bb53fe1..f69f385 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,9 +1,12 @@ CC := gcc CARGO := rustup run nightly cargo +TARGET := x86_64-unknown-linux-musl +PROFILE := size-optimized + THIS_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) REPO_ROOT := $(THIS_DIR)/.. -RUST_TARGET_DIR := $(REPO_ROOT)/target/x86_64-unknown-linux-musl/size-optimized +RUST_TARGET_DIR := $(REPO_ROOT)/target/$(TARGET)/$(PROFILE) export SERVICEPOINT_HEADER_OUT := $(REPO_ROOT)/include RUSTFLAGS := -Zlocation-detail=none \ @@ -17,9 +20,9 @@ RUSTFLAGS := -Zlocation-detail=none \ -C panic=abort CARGOFLAGS := --manifest-path=$(REPO_ROOT)/Cargo.toml \ - --profile=size-optimized \ + --profile=$(PROFILE) \ --no-default-features \ - --target=x86_64-unknown-linux-musl \ + --target=$(TARGET) \ -Zbuild-std="core,std,alloc,proc_macro,panic_abort" \ -Zbuild-std-features="panic_immediate_abort" \ @@ -45,23 +48,23 @@ CCFLAGS := -static -Os \ STRIPFLAGS := -s --strip-unneeded -R .comment -R .gnu.version -R .comment -R .note -R .note.gnu.build-id -R .note.ABI-tag -c_src := $(wildcard *.c) -programs := $(basename $(c_src)) -bins := $(addprefix out/, $(programs)) -unstripped_bins := $(addsuffix _unstripped, $(bins)) -run_programs := $(addprefix run_, $(programs)) -rs_src := $(wildcard ../src/*.rs) ../Cargo.lock +_c_src := $(wildcard *.c) +_programs := $(basename $(_c_src)) +_bins := $(addprefix out/, $(_programs)) +_unstripped_bins := $(addsuffix _unstripped, $(_bins)) +_run_programs := $(addprefix run_, $(_programs)) +_rs_src := $(wildcard ../src/**.rs) ../Cargo.lock -all: $(bins) +all: $(_bins) clean: rm -r out || true rm include/servicepoint.h || true cargo clean -PHONY: all clean sizes $(run_programs) +PHONY: all clean sizes $(_run_programs) -$(unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a +$(_unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a mkdir -p out || true ${CC} $^ \ -I $(SERVICEPOINT_HEADER_OUT) \ @@ -69,18 +72,18 @@ $(unstripped_bins): out/%_unstripped: %.c $(SERVICEPOINT_HEADER_OUT)/servicepoin $(CCFLAGS) \ -o $@ -$(bins): out/%: out/%_unstripped +$(_bins): out/%: out/%_unstripped strip $(STRIPFLAGS) $^ -o $@ -$(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a: $(rs_src) +$(SERVICEPOINT_HEADER_OUT)/servicepoint.h $(RUST_TARGET_DIR)/libservicepoint_binding_c.a: $(_rs_src) mkdir -p include || true # generate servicepoint header and binary to link against ${CARGO} rustc $(CARGOFLAGS) -- $(RUSTFLAGS) -$(run_programs): run_%: out/% FORCE +$(_run_programs): run_%: out/% FORCE ./$< -sizes: $(bins) +sizes: $(_bins) ls -lB out #analyze-size: out/example_unstripped @@ -88,6 +91,4 @@ sizes: $(bins) # | awk '{size=$$2+0; print size "\t" $$4}' \ # | less - - FORCE: ; diff --git a/example/announce.c b/example/announce.c index d7a55fb..9220242 100644 --- a/example/announce.c +++ b/example/announce.c @@ -1,16 +1,17 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); + //UdpConnection *connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); + UdpConnection *connection = sp_udp_open_ipv4(127, 0, 0, 1, 2342); if (connection == NULL) return 1; - sp_udp_send_command(connection, sp_command_clear()); + sp_udp_send_header(connection, (Header) {.command_code = COMMAND_CODE_CLEAR}); CharGrid *grid = sp_char_grid_new(5, 2); if (grid == NULL) return 1; - + sp_char_grid_set(grid, 0, 0, 'H'); sp_char_grid_set(grid, 1, 0, 'e'); sp_char_grid_set(grid, 2, 0, 'l'); @@ -22,7 +23,6 @@ int main(void) { sp_char_grid_set(grid, 3, 1, 'l'); sp_char_grid_set(grid, 4, 1, 'd'); - TypedCommand *command = sp_command_char_grid(0, 0, grid); sp_udp_send_command(connection, command); diff --git a/include/servicepoint.h b/include/servicepoint.h index aa7893f..0a0d340 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -95,6 +95,36 @@ enum BinaryOperation typedef uint8_t BinaryOperation; #endif // __cplusplus +/** + * The u16 command codes used for the [Command]s. + */ +enum CommandCode +#ifdef __cplusplus + : uint16_t +#endif // __cplusplus + { + COMMAND_CODE_CLEAR = 2, + COMMAND_CODE_CP437_DATA = 3, + COMMAND_CODE_CHAR_BRIGHTNESS = 5, + COMMAND_CODE_BRIGHTNESS = 7, + COMMAND_CODE_HARD_RESET = 11, + COMMAND_CODE_FADE_OUT = 13, + COMMAND_CODE_BITMAP_LEGACY = 16, + COMMAND_CODE_BITMAP_LINEAR = 18, + COMMAND_CODE_BITMAP_LINEAR_WIN_UNCOMPRESSED = 19, + COMMAND_CODE_BITMAP_LINEAR_AND = 20, + COMMAND_CODE_BITMAP_LINEAR_OR = 21, + COMMAND_CODE_BITMAP_LINEAR_XOR = 22, + COMMAND_CODE_BITMAP_LINEAR_WIN_ZLIB = 23, + COMMAND_CODE_BITMAP_LINEAR_WIN_BZIP2 = 24, + COMMAND_CODE_BITMAP_LINEAR_WIN_LZMA = 25, + COMMAND_CODE_UTF8_DATA = 32, + COMMAND_CODE_BITMAP_LINEAR_WIN_ZSTD = 26, +}; +#ifndef __cplusplus +typedef uint16_t CommandCode; +#endif // __cplusplus + /** * Specifies the kind of compression to use. Availability depends on features. * @@ -683,7 +713,7 @@ BrightnessGrid *sp_brightness_grid_load(size_t width, * * # Examples * ```C - * UdpConnection connection = sp_connection_open("127.0.0.1:2342"); + * UdpConnection connection = sp_udp_open("127.0.0.1:2342"); * if (connection == NULL) * return 1; * @@ -692,7 +722,7 @@ BrightnessGrid *sp_brightness_grid_load(size_t width, * sp_brightness_grid_set(grid, 1, 1, 10); * * TypedCommand command = sp_command_char_brightness(grid); - * sp_connection_free(connection); + * sp_udp_free(connection); * ``` */ BrightnessGrid */*notnull*/ sp_brightness_grid_new(size_t width, size_t height); @@ -899,7 +929,7 @@ TypedCommand */*notnull*/ sp_command_char_grid(size_t x, * # Examples * * ```C - * sp_connection_send_command(connection, sp_command_clear()); + * sp_udp_send_command(connection, sp_command_clear()); * ``` */ TypedCommand */*notnull*/ sp_command_clear(void); @@ -1122,6 +1152,8 @@ void sp_packet_set_payload(Packet */*notnull*/ packet, ByteSlice data); */ Packet *sp_packet_try_load(ByteSlice data); +bool sp_u16_to_command_code(uint16_t code, CommandCode *result); + /** * Closes and deallocates a [UdpConnection]. */ @@ -1135,9 +1167,9 @@ void sp_udp_free(UdpConnection */*notnull*/ connection); * # Examples * * ```C - * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); + * UdpConnection connection = sp_udp_open("172.23.42.29:2342"); * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); + * sp_udp_send_command(connection, sp_command_clear()); * ``` */ UdpConnection *sp_udp_open(char */*notnull*/ host); @@ -1150,9 +1182,9 @@ UdpConnection *sp_udp_open(char */*notnull*/ host); * # Examples * * ```C - * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); + * UdpConnection connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); + * sp_udp_send_command(connection, sp_command_clear()); * ``` */ UdpConnection *sp_udp_open_ipv4(uint8_t ip1, @@ -1171,13 +1203,26 @@ UdpConnection *sp_udp_open_ipv4(uint8_t ip1, * # Examples * * ```C - * sp_connection_send_command(connection, sp_command_clear()); - * sp_connection_send_command(connection, sp_command_brightness(5)); + * sp_udp_send_command(connection, sp_command_brightness(5)); * ``` */ bool sp_udp_send_command(UdpConnection */*notnull*/ connection, TypedCommand */*notnull*/ command); +/** + * Sends a [Header] to the display using the [UdpConnection]. + * + * returns: true in case of success + * + * # Examples + * + * ```C + * sp_udp_send_header(connection, sp_command_brightness(5)); + * ``` + */ +bool sp_udp_send_header(UdpConnection */*notnull*/ udp_connection, + Header header); + /** * Sends a [Packet] to the display using the [UdpConnection]. * diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index 823a1fd..dcde8cf 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -9,7 +9,7 @@ use std::ptr::NonNull; /// /// # Examples /// ```C -/// UdpConnection connection = sp_connection_open("127.0.0.1:2342"); +/// UdpConnection connection = sp_udp_open("127.0.0.1:2342"); /// if (connection == NULL) /// return 1; /// @@ -18,7 +18,7 @@ use std::ptr::NonNull; /// sp_brightness_grid_set(grid, 1, 1, 10); /// /// TypedCommand command = sp_command_char_brightness(grid); -/// sp_connection_free(connection); +/// sp_udp_free(connection); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_new( @@ -167,5 +167,5 @@ pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( const _: () = assert!(size_of::() == 1); let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() }; - unsafe { ByteSlice::from_slice(transmute(data)) } + unsafe { ByteSlice::from_slice(transmute::<&mut [Brightness], &mut [u8]>(data)) } } diff --git a/src/byte_slice.rs b/src/byte_slice.rs index 001a616..de7d0df 100644 --- a/src/byte_slice.rs +++ b/src/byte_slice.rs @@ -24,7 +24,7 @@ impl ByteSlice { unsafe { std::slice::from_raw_parts(self.start.as_ptr(), self.length) } } - pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] { + pub(crate) unsafe fn as_slice_mut(&mut self) -> &mut [u8] { unsafe { std::slice::from_raw_parts_mut(self.start.as_ptr(), self.length) } diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..1ea03d5 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,3 @@ +mod typed; + +pub use typed::*; diff --git a/src/command.rs b/src/commands/typed.rs similarity index 94% rename from src/command.rs rename to src/commands/typed.rs index 32d5acd..9e27540 100644 --- a/src/command.rs +++ b/src/commands/typed.rs @@ -40,7 +40,7 @@ pub unsafe extern "C" fn sp_command_clone( /// # Examples /// /// ```C -/// sp_connection_send_command(connection, sp_command_clear()); +/// sp_udp_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_command_clear() -> NonNull { @@ -115,10 +115,6 @@ pub unsafe extern "C" fn sp_command_bitvec( operation: BinaryOperation, ) -> *mut TypedCommand { let bit_vec = unsafe { *Box::from_raw(bit_vec.as_ptr()) }; - let compression = match compression.try_into() { - Ok(compression) => compression, - Err(_) => return std::ptr::null_mut(), - }; let command = servicepoint::BitVecCommand { offset, operation, @@ -182,10 +178,6 @@ pub unsafe extern "C" fn sp_command_bitmap( compression: CompressionCode, ) -> *mut TypedCommand { let bitmap = unsafe { *Box::from_raw(bitmap.as_ptr()) }; - let compression = match compression.try_into() { - Ok(compression) => compression, - Err(_) => return std::ptr::null_mut(), - }; let command = servicepoint::BitmapCommand { origin: servicepoint::Origin::new(x, y), bitmap, diff --git a/src/connection.rs b/src/connection.rs index 7b29e29..eec1f43 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,5 +1,5 @@ use crate::{heap_drop, heap_move}; -use servicepoint::{Connection, Packet, TypedCommand, UdpConnection}; +use servicepoint::{Connection, Header, Packet, TypedCommand, UdpConnection}; use std::ffi::{c_char, CStr}; use std::net::{Ipv4Addr, SocketAddrV4}; use std::ptr::NonNull; @@ -11,9 +11,9 @@ use std::ptr::NonNull; /// # Examples /// /// ```C -/// UdpConnection connection = sp_connection_open("172.23.42.29:2342"); +/// UdpConnection connection = sp_udp_open("172.23.42.29:2342"); /// if (connection != NULL) -/// sp_connection_send_command(connection, sp_command_clear()); +/// sp_udp_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_open( @@ -37,9 +37,9 @@ pub unsafe extern "C" fn sp_udp_open( /// # Examples /// /// ```C -/// UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); +/// UdpConnection connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); /// if (connection != NULL) -/// sp_connection_send_command(connection, sp_command_clear()); +/// sp_udp_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_open_ipv4( @@ -80,8 +80,7 @@ pub unsafe extern "C" fn sp_udp_send_packet( /// # Examples /// /// ```C -/// sp_connection_send_command(connection, sp_command_clear()); -/// sp_connection_send_command(connection, sp_command_brightness(5)); +/// sp_udp_send_command(connection, sp_command_brightness(5)); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_send_command( @@ -92,6 +91,27 @@ pub unsafe extern "C" fn sp_udp_send_command( unsafe { connection.as_ref().send(command) }.is_ok() } +/// Sends a [Header] to the display using the [UdpConnection]. +/// +/// returns: true in case of success +/// +/// # Examples +/// +/// ```C +/// sp_udp_send_header(connection, sp_command_brightness(5)); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn sp_udp_send_header( + udp_connection: NonNull, + header: Header, +) -> bool { + let packet = Packet { + header, + payload: vec![], + }; + unsafe { udp_connection.as_ref() }.send(packet).is_ok() +} + /// Closes and deallocates a [UdpConnection]. #[no_mangle] pub unsafe extern "C" fn sp_udp_free(connection: NonNull) { diff --git a/src/lib.rs b/src/lib.rs index f90e93d..c434ab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ //! #include "servicepoint.h" //! //! int main(void) { -//! UdpConnection *connection = sp_connection_open("172.23.42.29:2342"); +//! UdpConnection *connection = sp_udp_open("172.23.42.29:2342"); //! if (connection == NULL) //! return 1; //! @@ -17,10 +17,10 @@ //! sp_bitmap_fill(pixels, true); //! //! TypedCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, Uncompressed); -//! while (sp_connection_send_command(connection, sp_command_clone(command))); +//! while (sp_udp_send_command(connection, sp_command_clone(command))); //! //! sp_command_free(command); -//! sp_connection_free(connection); +//! sp_udp_free(connection); //! return 0; //! } //! ``` @@ -30,10 +30,11 @@ pub use crate::bitvec::*; pub use crate::brightness_grid::*; pub use crate::byte_slice::*; pub use crate::char_grid::*; -pub use crate::command::*; +pub use crate::commands::*; pub use crate::connection::*; pub use crate::cp437_grid::*; pub use crate::packet::*; +pub use servicepoint::CommandCode; use std::ptr::NonNull; mod bitmap; @@ -41,7 +42,7 @@ mod bitvec; mod brightness_grid; mod byte_slice; mod char_grid; -mod command; +mod commands; mod connection; mod cp437_grid; mod packet; diff --git a/src/packet.rs b/src/packet.rs index a9def67..4a30b51 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,5 +1,5 @@ use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; -use servicepoint::{Header, Packet, TypedCommand}; +use servicepoint::{CommandCode, Header, Packet, TypedCommand}; use std::ptr::NonNull; /// Turns a [TypedCommand] into a [Packet]. @@ -65,7 +65,7 @@ pub unsafe extern "C" fn sp_packet_get_header( pub unsafe extern "C" fn sp_packet_get_payload( packet: NonNull, ) -> ByteSlice { - unsafe { ByteSlice::from_slice(&mut *(*packet.as_ptr()).payload) } + unsafe { ByteSlice::from_slice(&mut (*packet.as_ptr()).payload) } } /// Sets the payload of the provided packet to the provided data. @@ -87,7 +87,7 @@ pub unsafe extern "C" fn sp_packet_set_payload( #[no_mangle] pub unsafe extern "C" fn sp_packet_serialize_to( packet: NonNull, - buffer: ByteSlice, + mut buffer: ByteSlice, ) { unsafe { packet.as_ref().serialize_to(buffer.as_slice_mut()); @@ -107,3 +107,19 @@ pub unsafe extern "C" fn sp_packet_clone( pub unsafe extern "C" fn sp_packet_free(packet: NonNull) { unsafe { heap_drop(packet) } } + +#[no_mangle] +pub unsafe extern "C" fn sp_u16_to_command_code( + code: u16, + result: *mut CommandCode, +) -> bool { + match CommandCode::try_from(code) { + Ok(code) => { + unsafe { + *result = code; + } + true + } + Err(_) => false, + } +} From a87f228c32ea3bf3160cb1fc3a39c2ce0ecc9590 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 21:56:07 +0200 Subject: [PATCH 3/4] heap_remove, sp_brightness_grid_into_packet --- include/servicepoint.h | 4 ++++ src/bitmap.rs | 6 +++--- src/brightness_grid.rs | 27 ++++++++++++++++++++++++--- src/connection.rs | 8 ++++---- src/lib.rs | 6 +++++- src/packet.rs | 4 ++-- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/include/servicepoint.h b/include/servicepoint.h index 0a0d340..1ece5e6 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -695,6 +695,10 @@ Brightness sp_brightness_grid_get(BrightnessGrid */*notnull*/ brightness_grid, */ size_t sp_brightness_grid_height(BrightnessGrid */*notnull*/ brightness_grid); +Packet *sp_brightness_grid_into_packet(BrightnessGrid */*notnull*/ grid, + size_t x, + size_t y); + /** * Loads a [BrightnessGrid] with the specified dimensions from the provided data. * diff --git a/src/bitmap.rs b/src/bitmap.rs index f203395..71753a5 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -1,5 +1,5 @@ use crate::byte_slice::ByteSlice; -use crate::{heap_drop, heap_move, heap_move_nonnull, SPBitVec}; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, SPBitVec}; use servicepoint::{Bitmap, DataRef, Grid}; use std::ptr::NonNull; @@ -78,7 +78,7 @@ pub unsafe extern "C" fn sp_bitmap_from_bitvec( width: usize, bitvec: NonNull, ) -> *mut Bitmap { - let bitvec = unsafe { *Box::from_raw(bitvec.as_ptr()) }; + let bitvec = unsafe { heap_remove(bitvec) }; if let Ok(bitmap) = Bitmap::from_bitvec(width, bitvec.0) { heap_move(bitmap) } else { @@ -196,6 +196,6 @@ pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref( pub unsafe extern "C" fn sp_bitmap_into_bitvec( bitmap: NonNull, ) -> NonNull { - let bitmap = unsafe { *Box::from_raw(bitmap.as_ptr()) }; + let bitmap = unsafe { heap_remove(bitmap) }; heap_move_nonnull(SPBitVec(bitmap.into())) } diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index dcde8cf..f85602a 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -1,5 +1,8 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; -use servicepoint::{Brightness, BrightnessGrid, ByteGrid, DataRef, Grid}; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, ByteSlice}; +use servicepoint::{ + Brightness, BrightnessGrid, BrightnessGridCommand, ByteGrid, DataRef, Grid, + Origin, Packet, +}; use std::mem::transmute; use std::ptr::NonNull; @@ -167,5 +170,23 @@ pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( const _: () = assert!(size_of::() == 1); let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() }; - unsafe { ByteSlice::from_slice(transmute::<&mut [Brightness], &mut [u8]>(data)) } + unsafe { + ByteSlice::from_slice(transmute::<&mut [Brightness], &mut [u8]>(data)) + } +} + +#[no_mangle] +pub unsafe extern "C" fn sp_brightness_grid_into_packet( + grid: NonNull, + x: usize, + y: usize, +) -> *mut Packet { + let grid = unsafe { heap_remove(grid) }; + match Packet::try_from(BrightnessGridCommand { + grid, + origin: Origin::new(x, y), + }) { + Ok(packet) => heap_move(packet), + Err(_) => std::ptr::null_mut(), + } } diff --git a/src/connection.rs b/src/connection.rs index eec1f43..93e0a21 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move}; +use crate::{heap_drop, heap_move, heap_remove}; use servicepoint::{Connection, Header, Packet, TypedCommand, UdpConnection}; use std::ffi::{c_char, CStr}; use std::net::{Ipv4Addr, SocketAddrV4}; @@ -67,8 +67,8 @@ pub unsafe extern "C" fn sp_udp_send_packet( connection: NonNull, packet: NonNull, ) -> bool { - let packet = unsafe { Box::from_raw(packet.as_ptr()) }; - unsafe { connection.as_ref().send(*packet) }.is_ok() + let packet = unsafe { heap_remove(packet) }; + unsafe { connection.as_ref().send(packet) }.is_ok() } /// Sends a [TypedCommand] to the display using the [UdpConnection]. @@ -87,7 +87,7 @@ pub unsafe extern "C" fn sp_udp_send_command( connection: NonNull, command: NonNull, ) -> bool { - let command = *unsafe { Box::from_raw(command.as_ptr()) }; + let command = unsafe { heap_remove(command) }; unsafe { connection.as_ref().send(command) }.is_ok() } diff --git a/src/lib.rs b/src/lib.rs index c434ab1..05fb009 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,5 +61,9 @@ pub(crate) fn heap_move_nonnull(x: T) -> NonNull { } pub(crate) unsafe fn heap_drop(x: NonNull) { - drop(unsafe { Box::from_raw(x.as_ptr()) }); + drop(unsafe { heap_remove(x) }); +} + +pub(crate) unsafe fn heap_remove(x: NonNull) -> T { + unsafe { *Box::from_raw(x.as_ptr()) } } diff --git a/src/packet.rs b/src/packet.rs index 4a30b51..a891ee3 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,4 +1,4 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, ByteSlice}; use servicepoint::{CommandCode, Header, Packet, TypedCommand}; use std::ptr::NonNull; @@ -10,7 +10,7 @@ use std::ptr::NonNull; pub unsafe extern "C" fn sp_packet_from_command( command: NonNull, ) -> *mut Packet { - let command = unsafe { *Box::from_raw(command.as_ptr()) }; + let command = unsafe { heap_remove(command) }; if let Ok(packet) = command.try_into() { heap_move(packet) } else { From 3589a90385b7bf33f165fe8fb663f2798bd523d7 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 12 Apr 2025 22:13:29 +0200 Subject: [PATCH 4/4] add functions to convert containers directly into packet --- example/announce.c | 6 ++-- example/brightness_tester.c | 11 ++++--- example/random_stuff.c | 9 +++--- include/servicepoint.h | 61 ++++++++++++++++++++++++++++++++++++- src/bitmap.rs | 25 ++++++++++++++- src/bitvec.rs | 28 +++++++++++++++-- src/brightness_grid.rs | 5 +++ src/char_grid.rs | 25 +++++++++++++-- src/cp437_grid.rs | 25 +++++++++++++-- src/packet.rs | 3 ++ 10 files changed, 178 insertions(+), 20 deletions(-) diff --git a/example/announce.c b/example/announce.c index 9220242..737eff5 100644 --- a/example/announce.c +++ b/example/announce.c @@ -23,8 +23,10 @@ int main(void) { sp_char_grid_set(grid, 3, 1, 'l'); sp_char_grid_set(grid, 4, 1, 'd'); - TypedCommand *command = sp_command_char_grid(0, 0, grid); - sp_udp_send_command(connection, command); + Packet *packet = sp_char_grid_into_packet(grid, 0, 0); + if (packet == NULL) + return 1; + sp_udp_send_packet(connection, packet); sp_udp_free(connection); return 0; diff --git a/example/brightness_tester.c b/example/brightness_tester.c index 93e64ce..d06d30d 100644 --- a/example/brightness_tester.c +++ b/example/brightness_tester.c @@ -8,11 +8,12 @@ int main(void) { Bitmap *all_on = sp_bitmap_new_max_sized(); sp_bitmap_fill(all_on, true); - TypedCommand *cmd = sp_command_bitmap(0, 0, all_on, COMPRESSION_CODE_UNCOMPRESSED); - if (cmd == NULL) + + Packet *packet = sp_bitmap_into_packet(all_on, 0, 0, COMPRESSION_CODE_UNCOMPRESSED); + if (packet == NULL) return -1; - sp_udp_send_command(connection, cmd); + sp_udp_send_packet(connection, packet); BrightnessGrid *grid = sp_brightness_grid_new(TILE_WIDTH, TILE_HEIGHT); @@ -21,8 +22,8 @@ int main(void) { slice.start[index] = (uint8_t) (index % ((size_t) Brightness_MAX)); } - TypedCommand *command = sp_command_brightness_grid(0, 0, grid); - sp_udp_send_command(connection, command); + packet = sp_brightness_grid_into_packet(grid, 0, 0); + sp_udp_send_packet(connection, packet); sp_udp_free(connection); return 0; diff --git a/example/random_stuff.c b/example/random_stuff.c index 80c3847..ca5a14d 100644 --- a/example/random_stuff.c +++ b/example/random_stuff.c @@ -1,3 +1,4 @@ +#include #include "servicepoint.h" int main(void) { @@ -11,14 +12,12 @@ int main(void) { sp_bitmap_fill(pixels, true); - TypedCommand *command = sp_command_bitmap(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); - if (command == NULL) + Packet *packet = sp_bitmap_into_packet(pixels, 0, 0, COMPRESSION_CODE_UNCOMPRESSED); + if (packet == NULL) return 1; - Packet *packet = sp_packet_from_command(command); - Header *header = sp_packet_get_header(packet); - //printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d); + printf("[%d, %d, %d, %d, %d]\n", header->command_code, header->a, header->b, header->c, header->d); sp_udp_send_packet(connection, packet); diff --git a/include/servicepoint.h b/include/servicepoint.h index 1ece5e6..77d2e36 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -455,6 +455,18 @@ size_t sp_bitmap_height(Bitmap */*notnull*/ bitmap); */ SPBitVec */*notnull*/ sp_bitmap_into_bitvec(Bitmap */*notnull*/ bitmap); +/** + * Creates a [BitmapCommand] and immediately turns that into a [Packet]. + * + * The provided [Bitmap] gets consumed. + * + * Returns NULL in case of an error. + */ +Packet *sp_bitmap_into_packet(Bitmap */*notnull*/ bitmap, + size_t x, + size_t y, + CompressionCode compression); + /** * Loads a [Bitmap] with the specified dimensions from the provided data. * @@ -580,6 +592,18 @@ void sp_bitvec_free(SPBitVec */*notnull*/ bit_vec); */ bool sp_bitvec_get(SPBitVec */*notnull*/ bit_vec, size_t index); +/** + * Creates a [BitVecCommand] and immediately turns that into a [Packet]. + * + * The provided [SPBitVec] gets consumed. + * + * Returns NULL in case of an error. + */ +Packet *sp_bitvec_into_packet(SPBitVec */*notnull*/ bitvec, + size_t offset, + BinaryOperation operation, + CompressionCode compression); + /** * Returns true if length is 0. * @@ -695,6 +719,13 @@ Brightness sp_brightness_grid_get(BrightnessGrid */*notnull*/ brightness_grid, */ size_t sp_brightness_grid_height(BrightnessGrid */*notnull*/ brightness_grid); +/** + * Creates a [BrightnessGridCommand] and immediately turns that into a [Packet]. + * + * The provided [BrightnessGrid] gets consumed. + * + * Returns NULL in case of an error. + */ Packet *sp_brightness_grid_into_packet(BrightnessGrid */*notnull*/ grid, size_t x, size_t y); @@ -818,6 +849,17 @@ uint32_t sp_char_grid_get(CharGrid */*notnull*/ char_grid, size_t x, size_t y); */ size_t sp_char_grid_height(CharGrid */*notnull*/ char_grid); +/** + * Creates a [CharGridCommand] and immediately turns that into a [Packet]. + * + * The provided [CharGrid] gets consumed. + * + * Returns NULL in case of an error. + */ +Packet *sp_char_grid_into_packet(CharGrid */*notnull*/ grid, + size_t x, + size_t y); + /** * Loads a [CharGrid] with the specified dimensions from the provided data. * @@ -1045,6 +1087,17 @@ uint8_t sp_cp437_grid_get(Cp437Grid */*notnull*/ cp437_grid, */ size_t sp_cp437_grid_height(Cp437Grid */*notnull*/ cp437_grid); +/** + * Creates a [Cp437GridCommand] and immediately turns that into a [Packet]. + * + * The provided [Cp437Grid] gets consumed. + * + * Returns NULL in case of an error. + */ +Packet *sp_cp437_grid_into_packet(Cp437Grid */*notnull*/ grid, + size_t x, + size_t y); + /** * Loads a [Cp437Grid] with the specified dimensions from the provided data. */ @@ -1156,7 +1209,13 @@ void sp_packet_set_payload(Packet */*notnull*/ packet, ByteSlice data); */ Packet *sp_packet_try_load(ByteSlice data); -bool sp_u16_to_command_code(uint16_t code, CommandCode *result); +/** + * Converts u16 into [CommandCode]. + * + * If the provided value is not valid, false is returned and result is not changed. + */ +bool sp_u16_to_command_code(uint16_t code, + CommandCode *result); /** * Closes and deallocates a [UdpConnection]. diff --git a/src/bitmap.rs b/src/bitmap.rs index 71753a5..358be48 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -1,6 +1,6 @@ use crate::byte_slice::ByteSlice; use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, SPBitVec}; -use servicepoint::{Bitmap, DataRef, Grid}; +use servicepoint::{Bitmap, BitmapCommand, CompressionCode, DataRef, Grid, Origin, Packet}; use std::ptr::NonNull; /// Creates a new [Bitmap] with the specified dimensions. @@ -199,3 +199,26 @@ pub unsafe extern "C" fn sp_bitmap_into_bitvec( let bitmap = unsafe { heap_remove(bitmap) }; heap_move_nonnull(SPBitVec(bitmap.into())) } + +/// Creates a [BitmapCommand] and immediately turns that into a [Packet]. +/// +/// The provided [Bitmap] gets consumed. +/// +/// Returns NULL in case of an error. +#[no_mangle] +pub unsafe extern "C" fn sp_bitmap_into_packet( + bitmap: NonNull, + x: usize, + y: usize, + compression: CompressionCode +) -> *mut Packet { + let bitmap = unsafe { heap_remove(bitmap) }; + match Packet::try_from(BitmapCommand { + bitmap, + origin: Origin::new(x, y), + compression, + }) { + Ok(packet) => heap_move(packet), + Err(_) => std::ptr::null_mut(), + } +} diff --git a/src/bitvec.rs b/src/bitvec.rs index e5ce720..22f7545 100644 --- a/src/bitvec.rs +++ b/src/bitvec.rs @@ -1,5 +1,5 @@ -use crate::{heap_drop, heap_move_nonnull, ByteSlice}; -use servicepoint::BitVecU8Msb0; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, ByteSlice}; +use servicepoint::{BinaryOperation, BitVecCommand, BitVecU8Msb0, CompressionCode, Packet}; use std::ptr::NonNull; /// A vector of bits @@ -146,3 +146,27 @@ pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref( ) -> ByteSlice { unsafe { ByteSlice::from_slice((*bit_vec.as_ptr()).0.as_raw_mut_slice()) } } + +/// Creates a [BitVecCommand] and immediately turns that into a [Packet]. +/// +/// The provided [SPBitVec] gets consumed. +/// +/// Returns NULL in case of an error. +#[no_mangle] +pub unsafe extern "C" fn sp_bitvec_into_packet( + bitvec: NonNull, + offset: usize, + operation: BinaryOperation, + compression: CompressionCode +) -> *mut Packet { + let bitvec = unsafe { heap_remove(bitvec) }.0; + match Packet::try_from(BitVecCommand { + bitvec, + offset, + operation, + compression, + }) { + Ok(packet) => heap_move(packet), + Err(_) => std::ptr::null_mut(), + } +} diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs index f85602a..1099be0 100644 --- a/src/brightness_grid.rs +++ b/src/brightness_grid.rs @@ -175,6 +175,11 @@ pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref( } } +/// Creates a [BrightnessGridCommand] and immediately turns that into a [Packet]. +/// +/// The provided [BrightnessGrid] gets consumed. +/// +/// Returns NULL in case of an error. #[no_mangle] pub unsafe extern "C" fn sp_brightness_grid_into_packet( grid: NonNull, diff --git a/src/char_grid.rs b/src/char_grid.rs index cdcc4b5..bfb2585 100644 --- a/src/char_grid.rs +++ b/src/char_grid.rs @@ -1,5 +1,5 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; -use servicepoint::{CharGrid, Grid}; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, ByteSlice}; +use servicepoint::{CharGrid, CharGridCommand, Grid, Origin, Packet}; use std::ptr::NonNull; /// Creates a new [CharGrid] with the specified dimensions. @@ -132,3 +132,24 @@ pub unsafe extern "C" fn sp_char_grid_height( ) -> usize { unsafe { char_grid.as_ref().height() } } + +/// Creates a [CharGridCommand] and immediately turns that into a [Packet]. +/// +/// The provided [CharGrid] gets consumed. +/// +/// Returns NULL in case of an error. +#[no_mangle] +pub unsafe extern "C" fn sp_char_grid_into_packet( + grid: NonNull, + x: usize, + y: usize, +) -> *mut Packet { + let grid = unsafe { heap_remove(grid) }; + match Packet::try_from(CharGridCommand { + grid, + origin: Origin::new(x, y), + }) { + Ok(packet) => heap_move(packet), + Err(_) => std::ptr::null_mut(), + } +} diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs index e22a0ed..01aeb1e 100644 --- a/src/cp437_grid.rs +++ b/src/cp437_grid.rs @@ -1,5 +1,5 @@ -use crate::{heap_drop, heap_move, heap_move_nonnull, ByteSlice}; -use servicepoint::{Cp437Grid, DataRef, Grid}; +use crate::{heap_drop, heap_move, heap_move_nonnull, heap_remove, ByteSlice}; +use servicepoint::{Cp437Grid, Cp437GridCommand, DataRef, Grid, Origin, Packet}; use std::ptr::NonNull; /// Creates a new [Cp437Grid] with the specified dimensions. @@ -132,3 +132,24 @@ pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref( ) -> ByteSlice { unsafe { ByteSlice::from_slice((*cp437_grid.as_ptr()).data_ref_mut()) } } + +/// Creates a [Cp437GridCommand] and immediately turns that into a [Packet]. +/// +/// The provided [Cp437Grid] gets consumed. +/// +/// Returns NULL in case of an error. +#[no_mangle] +pub unsafe extern "C" fn sp_cp437_grid_into_packet( + grid: NonNull, + x: usize, + y: usize, +) -> *mut Packet { + let grid = unsafe { heap_remove(grid) }; + match Packet::try_from(Cp437GridCommand { + grid, + origin: Origin::new(x, y), + }) { + Ok(packet) => heap_move(packet), + Err(_) => std::ptr::null_mut(), + } +} diff --git a/src/packet.rs b/src/packet.rs index a891ee3..d8b1579 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -108,6 +108,9 @@ pub unsafe extern "C" fn sp_packet_free(packet: NonNull) { unsafe { heap_drop(packet) } } +/// Converts u16 into [CommandCode]. +/// +/// If the provided value is not valid, false is returned and result is not changed. #[no_mangle] pub unsafe extern "C" fn sp_u16_to_command_code( code: u16,