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, + } +}