diff --git a/Cargo.lock b/Cargo.lock index c0b11c4..f87ecea 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#971bee5065139f220022e8108cfaa9c263b8a8a0" +source = "git+https://git.berlin.ccc.de/servicepoint/servicepoint/?branch=next#531d4e6b4a368dc126cab9dc12b64d2ca8a81694" dependencies = [ "bitvec", "bzip2", diff --git a/example/Makefile b/example/Makefile index e7d858f..d3f346f 100644 --- a/example/Makefile +++ b/example/Makefile @@ -63,11 +63,19 @@ out/example_unstripped: dependencies main.c $(CCFLAGS) \ -o out/example_unstripped out/example: out/example_unstripped - strip -s -R .comment -R .gnu.version --strip-unneeded out/example_unstripped -o out/example -#strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag + strip -s --strip-unneeded \ + -R .comment -R .gnu.version -R .comment -R .note -R .note.gnu.build-id -R .note.ABI-tag \ + out/example_unstripped \ + -o out/example dependencies: FORCE 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 + FORCE: ; diff --git a/example/main.c b/example/main.c index e3cfc8f..9c0ec9e 100644 --- a/example/main.c +++ b/example/main.c @@ -2,7 +2,7 @@ #include "servicepoint.h" int main(void) { - UdpConnection *connection = sp_connection_open_ipv4(127,0,0,1,2342); + UdpConnection *connection = sp_udp_open_ipv4(127, 0, 0, 1, 2342); if (connection == NULL) return 1; @@ -12,17 +12,17 @@ int main(void) { sp_bitmap_fill(pixels, true); - TypedCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); + TypedCommand *command = sp_command_bitmap(0, 0, pixels, COMPRESSION_CODE_UNCOMPRESSED); if (command == 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_connection_send_packet(connection, packet); + sp_udp_send_packet(connection, packet); - sp_connection_free(connection); + sp_udp_free(connection); return 0; } diff --git a/include/servicepoint.h b/include/servicepoint.h index 7c0c819..8f7ca75 100644 --- a/include/servicepoint.h +++ b/include/servicepoint.h @@ -66,6 +66,35 @@ */ #define TILE_WIDTH 56 +/** + * Binary operations for use with the [`BitVecCommand`] command. + */ +enum BinaryOperation +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + /** + * r := a + */ + BINARY_OPERATION_OVERWRITE, + /** + * r := a && b + */ + BINARY_OPERATION_AND, + /** + * r := a || b + */ + BINARY_OPERATION_OR, + /** + * r := (a || b) && (a != b) + */ + BINARY_OPERATION_XOR, +}; +#ifndef __cplusplus +typedef uint8_t BinaryOperation; +#endif // __cplusplus + /** * Specifies the kind of compression to use. Availability depends on features. * @@ -428,7 +457,7 @@ Bitmap *sp_bitmap_new(size_t width, size_t height); * * returns: [Bitmap] initialized to all pixels off. */ -Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void); +Bitmap */*notnull*/ sp_bitmap_new_max_sized(void); /** * Sets the value of the specified position in the [Bitmap]. @@ -791,81 +820,36 @@ void sp_char_grid_set(CharGrid */*notnull*/ char_grid, */ size_t sp_char_grid_width(CharGrid */*notnull*/ char_grid); +/** + * Sets a window of pixels to the specified values. + * + * The passed [Bitmap] gets consumed. + * + * Returns: a new [servicepoint::BitmapCommand] instance. + */ +TypedCommand *sp_command_bitmap(size_t x, + size_t y, + Bitmap */*notnull*/ bitmap, + CompressionCode compression); + /** * Set pixel data starting at the pixel offset on screen. * * The screen will continuously overwrite more pixel data without regarding the offset, meaning * once the starting row is full, overwriting will continue on column 0. * - * The contained [SPBitVec] is always uncompressed. + * The [`BinaryOperation`] will be applied on the display comparing old and sent bit. * - * The passed [SPBitVec] gets consumed. + * `new_bit = old_bit op sent_bit` * - * Returns: a new [servicepoint::Command::BitmapLinear] instance. + * For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. + * + * The contained [`BitVecU8Msb0`] is always uncompressed. */ -TypedCommand *sp_command_bitmap_linear(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Set pixel data according to an and-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. - */ -TypedCommand *sp_command_bitmap_linear_and(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Set pixel data according to an or-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearOr] instance. - */ -TypedCommand *sp_command_bitmap_linear_or(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); - -/** - * Sets a window of pixels to the specified values. - * - * The passed [Bitmap] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearWin] instance. - */ -TypedCommand *sp_command_bitmap_linear_win(size_t x, - size_t y, - Bitmap */*notnull*/ bitmap, - CompressionCode compression); - -/** - * Set pixel data according to a xor-mask starting at the offset. - * - * The screen will continuously overwrite more pixel data without regarding the offset, meaning - * once the starting row is full, overwriting will continue on column 0. - * - * The contained [SPBitVec] is always uncompressed. - * - * The passed [SPBitVec] gets consumed. - * - * Returns: a new [servicepoint::Command::BitmapLinearXor] instance. - */ -TypedCommand *sp_command_bitmap_linear_xor(size_t offset, - SPBitVec */*notnull*/ bit_vec, - CompressionCode compression); +TypedCommand *sp_command_bitvec(size_t offset, + SPBitVec */*notnull*/ bit_vec, + CompressionCode compression, + BinaryOperation operation); /** * Set the brightness of all tiles to the same value. @@ -885,6 +869,17 @@ TypedCommand */*notnull*/ sp_command_char_brightness(size_t x, size_t y, BrightnessGrid */*notnull*/ grid); +/** + * Show UTF-8 encoded text on the screen. + * + * The passed [CharGrid] gets consumed. + * + * Returns: a new [servicepoint::CharGridCommand] instance. + */ +TypedCommand */*notnull*/ sp_command_char_grid(size_t x, + size_t y, + CharGrid */*notnull*/ grid); + /** * Set all pixels to the off state. * @@ -912,9 +907,9 @@ TypedCommand */*notnull*/ sp_command_clone(TypedCommand */*notnull*/ command); * * The passed [Cp437Grid] gets consumed. * - * Returns: a new [servicepoint::Command::Cp437Data] instance. + * Returns: a new [servicepoint::Cp437GridCommand] instance. */ -TypedCommand */*notnull*/ sp_command_cp437_data(size_t x, +TypedCommand */*notnull*/ sp_command_cp437_grid(size_t x, size_t y, Cp437Grid */*notnull*/ grid); @@ -955,83 +950,6 @@ TypedCommand */*notnull*/ sp_command_hard_reset(void); */ TypedCommand *sp_command_try_from_packet(Packet */*notnull*/ packet); -/** - * Show UTF-8 encoded text on the screen. - * - * The passed [CharGrid] gets consumed. - * - * Returns: a new [servicepoint::Command::Utf8Data] instance. - */ -TypedCommand */*notnull*/ sp_command_utf8_data(size_t x, - size_t y, - CharGrid */*notnull*/ grid); - -/** - * Closes and deallocates a [UdpConnection]. - */ -void sp_connection_free(UdpConnection */*notnull*/ connection); - -/** - * Creates a new instance of [UdpConnection]. - * - * returns: NULL if connection fails, or connected instance - * - * # Examples - * - * ```C - * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); - * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); - * ``` - */ -UdpConnection *sp_connection_open(char */*notnull*/ host); - -/** - * Creates a new instance of [UdpConnection]. - * - * returns: NULL if connection fails, or connected instance - * - * # Examples - * - * ```C - * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); - * if (connection != NULL) - * sp_connection_send_command(connection, sp_command_clear()); - * ``` - */ -UdpConnection *sp_connection_open_ipv4(uint8_t ip1, - uint8_t ip2, - uint8_t ip3, - uint8_t ip4, - uint16_t port); - -/** - * Sends a [TypedCommand] to the display using the [UdpConnection]. - * - * The passed `command` gets consumed. - * - * returns: true in case of success - * - * # Examples - * - * ```C - * sp_connection_send_command(connection, sp_command_clear()); - * sp_connection_send_command(connection, sp_command_brightness(5)); - * ``` - */ -bool sp_connection_send_command(UdpConnection */*notnull*/ connection, - TypedCommand */*notnull*/ command); - -/** - * Sends a [Packet] to the display using the [UdpConnection]. - * - * The passed `packet` gets consumed. - * - * returns: true in case of success - */ -bool sp_connection_send_packet(UdpConnection */*notnull*/ connection, - Packet */*notnull*/ packet); - /** * Clones a [Cp437Grid]. */ @@ -1188,6 +1106,72 @@ void sp_packet_set_payload(Packet */*notnull*/ packet, ByteSlice data); */ Packet *sp_packet_try_load(ByteSlice data); +/** + * Closes and deallocates a [UdpConnection]. + */ +void sp_udp_free(UdpConnection */*notnull*/ connection); + +/** + * Creates a new instance of [UdpConnection]. + * + * returns: NULL if connection fails, or connected instance + * + * # Examples + * + * ```C + * UdpConnection connection = sp_connection_open("172.23.42.29:2342"); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +UdpConnection *sp_udp_open(char */*notnull*/ host); + +/** + * Creates a new instance of [UdpConnection]. + * + * returns: NULL if connection fails, or connected instance + * + * # Examples + * + * ```C + * UdpConnection connection = sp_connection_open_ipv4(172, 23, 42, 29, 2342); + * if (connection != NULL) + * sp_connection_send_command(connection, sp_command_clear()); + * ``` + */ +UdpConnection *sp_udp_open_ipv4(uint8_t ip1, + uint8_t ip2, + uint8_t ip3, + uint8_t ip4, + uint16_t port); + +/** + * Sends a [TypedCommand] to the display using the [UdpConnection]. + * + * The passed `command` gets consumed. + * + * returns: true in case of success + * + * # Examples + * + * ```C + * sp_connection_send_command(connection, sp_command_clear()); + * sp_connection_send_command(connection, sp_command_brightness(5)); + * ``` + */ +bool sp_udp_send_command(UdpConnection */*notnull*/ connection, + TypedCommand */*notnull*/ command); + +/** + * Sends a [Packet] to the display using the [UdpConnection]. + * + * The passed `packet` gets consumed. + * + * returns: true in case of success + */ +bool sp_udp_send_packet(UdpConnection */*notnull*/ connection, + Packet */*notnull*/ packet); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/src/bitmap.rs b/src/bitmap.rs index f9b6882..d1d8522 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs @@ -42,7 +42,7 @@ pub unsafe extern "C" fn sp_bitmap_new( /// /// returns: [Bitmap] initialized to all pixels off. #[no_mangle] -pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull { +pub unsafe extern "C" fn sp_bitmap_new_max_sized() -> NonNull { let result = Box::new(Bitmap::max_sized()); NonNull::from(Box::leak(result)) } diff --git a/src/command.rs b/src/command.rs index b867eba..80a2b22 100644 --- a/src/command.rs +++ b/src/command.rs @@ -104,106 +104,15 @@ pub unsafe extern "C" fn sp_command_char_brightness( /// The screen will continuously overwrite more pixel data without regarding the offset, meaning /// once the starting row is full, overwriting will continue on column 0. /// -/// The contained [SPBitVec] is always uncompressed. +/// The [`BinaryOperation`] will be applied on the display comparing old and sent bit. /// -/// The passed [SPBitVec] gets consumed. +/// `new_bit = old_bit op sent_bit` /// -/// Returns: a new [servicepoint::Command::BitmapLinear] instance. +/// For example, [`BinaryOperation::Or`] can be used to turn on some pixels without affecting other pixels. +/// +/// The contained [`BitVecU8Msb0`] is always uncompressed. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Overwrite, - ) - } -} - -/// Set pixel data according to an and-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearAnd] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_and( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Xor, - ) - } -} - -/// Set pixel data according to an or-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearOr] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_or( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Or, - ) - } -} - -/// Set pixel data according to a xor-mask starting at the offset. -/// -/// The screen will continuously overwrite more pixel data without regarding the offset, meaning -/// once the starting row is full, overwriting will continue on column 0. -/// -/// The contained [SPBitVec] is always uncompressed. -/// -/// The passed [SPBitVec] gets consumed. -/// -/// Returns: a new [servicepoint::Command::BitmapLinearXor] instance. -#[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_xor( - offset: usize, - bit_vec: NonNull, - compression: CompressionCode, -) -> *mut TypedCommand { - unsafe { - sp_command_bitmap_linear_internal( - offset, - bit_vec, - compression, - BinaryOperation::Xor, - ) - } -} - -unsafe fn sp_command_bitmap_linear_internal( +pub unsafe extern "C" fn sp_command_bitvec( offset: usize, bit_vec: NonNull, compression: CompressionCode, @@ -220,7 +129,7 @@ unsafe fn sp_command_bitmap_linear_internal( bitvec: bit_vec.0, compression, } - .into(); + .into(); Box::leak(Box::new(command)) } @@ -228,9 +137,9 @@ unsafe fn sp_command_bitmap_linear_internal( /// /// The passed [Cp437Grid] gets consumed. /// -/// Returns: a new [servicepoint::Command::Cp437Data] instance. +/// Returns: a new [servicepoint::Cp437GridCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_cp437_data( +pub unsafe extern "C" fn sp_command_cp437_grid( x: usize, y: usize, grid: NonNull, @@ -250,9 +159,9 @@ pub unsafe extern "C" fn sp_command_cp437_data( /// /// The passed [CharGrid] gets consumed. /// -/// Returns: a new [servicepoint::Command::Utf8Data] instance. +/// Returns: a new [servicepoint::CharGridCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_utf8_data( +pub unsafe extern "C" fn sp_command_char_grid( x: usize, y: usize, grid: NonNull, @@ -272,9 +181,9 @@ pub unsafe extern "C" fn sp_command_utf8_data( /// /// The passed [Bitmap] gets consumed. /// -/// Returns: a new [servicepoint::Command::BitmapLinearWin] instance. +/// Returns: a new [servicepoint::BitmapCommand] instance. #[no_mangle] -pub unsafe extern "C" fn sp_command_bitmap_linear_win( +pub unsafe extern "C" fn sp_command_bitmap( x: usize, y: usize, bitmap: NonNull, diff --git a/src/connection.rs b/src/connection.rs index d6ffb83..b49225d 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -15,7 +15,7 @@ use std::ptr::NonNull; /// sp_connection_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_open( +pub unsafe extern "C" fn sp_udp_open( host: NonNull, ) -> *mut UdpConnection { let host = unsafe { CStr::from_ptr(host.as_ptr()) } @@ -41,7 +41,7 @@ pub unsafe extern "C" fn sp_connection_open( /// sp_connection_send_command(connection, sp_command_clear()); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_open_ipv4( +pub unsafe extern "C" fn sp_udp_open_ipv4( ip1: u8, ip2: u8, ip3: u8, ip4: u8, port: u16, ) -> *mut UdpConnection { @@ -53,29 +53,13 @@ pub unsafe extern "C" fn sp_connection_open_ipv4( Box::into_raw(Box::new(connection)) } -// /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything. -// /// -// /// returns: a new instance. -// /// -// /// # Safety -// /// -// /// The caller has to make sure that: -// /// -// /// - the returned instance is freed in some way, either by using a consuming function or -// /// by explicitly calling `sp_connection_free`. -// #[no_mangle] -// pub unsafe extern "C" fn sp_connection_fake() -> NonNull { -// let result = Box::new(SPUdpConnection(servicepoint::Connection::Fake)); -// NonNull::from(Box::leak(result)) -// } - /// Sends a [Packet] to the display using the [UdpConnection]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success #[no_mangle] -pub unsafe extern "C" fn sp_connection_send_packet( +pub unsafe extern "C" fn sp_udp_send_packet( connection: NonNull, packet: NonNull, ) -> bool { @@ -96,7 +80,7 @@ pub unsafe extern "C" fn sp_connection_send_packet( /// sp_connection_send_command(connection, sp_command_brightness(5)); /// ``` #[no_mangle] -pub unsafe extern "C" fn sp_connection_send_command( +pub unsafe extern "C" fn sp_udp_send_command( connection: NonNull, command: NonNull, ) -> bool { @@ -106,7 +90,7 @@ pub unsafe extern "C" fn sp_connection_send_command( /// Closes and deallocates a [UdpConnection]. #[no_mangle] -pub unsafe extern "C" fn sp_connection_free( +pub unsafe extern "C" fn sp_udp_free( connection: NonNull, ) { _ = unsafe { Box::from_raw(connection.as_ptr()) };