WIP: type per command #4

Draft
vinzenz wants to merge 49 commits from next into main
7 changed files with 485 additions and 485 deletions
Showing only changes of commit b79a2534fc - Show all commits

View file

@ -633,12 +633,6 @@ typedef struct Header {
extern "C" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
/**
* Call this function at the beginning of main to enable rust logging controlled by the
* `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/).
*/
void init_env_logger(void);
/** /**
*Clones a [`Bitmap`] instance. *Clones a [`Bitmap`] instance.
* *
@ -1655,7 +1649,7 @@ void sp_cmd_clear_free(struct ClearCommand */*notnull*/ instance);
* *
* Does not affect brightness. * Does not affect brightness.
* *
* Returns: a new [ClearCommand] instance. * Returns: a new [`ClearCommand`] instance.
* *
* This function is part of the sp_cmd_clear module. * This function is part of the sp_cmd_clear module.
*/ */
@ -1752,7 +1746,7 @@ void sp_cmd_fade_out_free(struct FadeOutCommand */*notnull*/ instance);
/** /**
* A yet-to-be-tested command. * A yet-to-be-tested command.
* *
* Returns: a new [FadeOutCommand] instance. * Returns: a new [`FadeOutCommand`] instance.
* *
* This function is part of the sp_cmd_fade_out module. * This function is part of the sp_cmd_fade_out module.
*/ */
@ -1762,6 +1756,8 @@ struct FadeOutCommand */*notnull*/ sp_cmd_fade_out_new(void);
* Clones an [SPCommand] instance. * Clones an [SPCommand] instance.
* *
* returns: a new [SPCommand] instance. * returns: a new [SPCommand] instance.
*
* This function is part of the sp_cmd_generic module.
*/ */
struct Command sp_cmd_generic_clone(struct Command command); struct Command sp_cmd_generic_clone(struct Command command);
@ -1776,6 +1772,8 @@ struct Command sp_cmd_generic_clone(struct Command command);
* SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new()); * SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new());
* sp_command_free(c); * sp_command_free(c);
* ``` * ```
*
* This function is part of the sp_cmd_generic module.
*/ */
void sp_cmd_generic_free(struct Command command); void sp_cmd_generic_free(struct Command command);
@ -1784,6 +1782,8 @@ void sp_cmd_generic_free(struct Command command);
* The [SPCommand] gets consumed. * The [SPCommand] gets consumed.
* *
* Returns tag [CommandTag::Invalid] in case of an error. * Returns tag [CommandTag::Invalid] in case of an error.
*
* This function is part of the sp_cmd_generic module.
*/ */
struct Packet *sp_cmd_generic_into_packet(struct Command command); struct Packet *sp_cmd_generic_into_packet(struct Command command);
@ -1793,6 +1793,8 @@ struct Packet *sp_cmd_generic_into_packet(struct Command command);
* The packet is dropped in the process. * The packet is dropped in the process.
* *
* Returns: pointer to new [SPCommand] instance or NULL if parsing failed. * Returns: pointer to new [SPCommand] instance or NULL if parsing failed.
*
* This function is part of the sp_cmd_generic module.
*/ */
struct Command sp_cmd_generic_try_from_packet(struct Packet */*notnull*/ packet); struct Command sp_cmd_generic_try_from_packet(struct Packet */*notnull*/ packet);
@ -1808,7 +1810,7 @@ void sp_cmd_hard_reset_free(struct HardResetCommand */*notnull*/ instance);
* *
* Please do not send this in your normal program flow. * Please do not send this in your normal program flow.
* *
* Returns: a new [HardResetCommand] instance. * Returns: a new [`HardResetCommand`] instance.
* *
* This function is part of the sp_cmd_hard_reset module. * This function is part of the sp_cmd_hard_reset module.
*/ */
@ -1942,6 +1944,14 @@ void sp_cp437_grid_set(Cp437Grid */*notnull*/ instance,
*/ */
size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ instance); size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ instance);
/**
* Call this function at the beginning of main to enable rust logging controlled by the
* `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/).
*
* This function is part of the sp_envlogger module.
*/
void sp_envlogger_init(void);
/** /**
*Clones a [`Packet`] instance. *Clones a [`Packet`] instance.
* *
@ -1960,6 +1970,8 @@ void sp_packet_free(struct Packet */*notnull*/ instance);
* Creates a raw [Packet] from parts. * Creates a raw [Packet] from parts.
* *
* returns: new instance. Will never return null. * returns: new instance. Will never return null.
*
* This function is part of the sp_packet module.
*/ */
struct Packet */*notnull*/ sp_packet_from_parts(struct Header header, struct Packet */*notnull*/ sp_packet_from_parts(struct Header header,
struct ByteSlice payload); struct ByteSlice payload);
@ -1972,11 +1984,14 @@ struct Packet */*notnull*/ sp_packet_from_parts(struct Header header,
struct Header sp_packet_get_header(struct Packet */*notnull*/ instance); struct Header sp_packet_get_header(struct Packet */*notnull*/ instance);
/** /**
* Returns a pointer to the header field of the provided packet. * Gets a reference to the field `header` of the [`servicepoint::Packet`].
* *
* The returned header can be changed and will be valid for the lifetime of the packet. * - The returned reference inherits the lifetime of object in which it is contained.
* - The returned pointer may not be used in a function that consumes the instance, e.g. to create a command.
*
* This function is part of the sp_packet module.
*/ */
struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ packet); struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ instance);
/** /**
* Returns a pointer to the current payload of the provided packet. * Returns a pointer to the current payload of the provided packet.
@ -1984,6 +1999,8 @@ struct Header */*notnull*/ sp_packet_get_header_mut(struct Packet */*notnull*/ p
* Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload. * Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload.
* *
* The returned memory can be changed and will be valid until a new payload is set. * The returned memory can be changed and will be valid until a new payload is set.
*
* This function is part of the sp_packet module.
*/ */
struct ByteSlice sp_packet_get_payload(struct Packet */*notnull*/ packet); struct ByteSlice sp_packet_get_payload(struct Packet */*notnull*/ packet);
@ -1993,8 +2010,10 @@ struct ByteSlice sp_packet_get_payload(struct Packet */*notnull*/ packet);
* # Panics * # Panics
* *
* - if the buffer is not big enough to hold header+payload. * - if the buffer is not big enough to hold header+payload.
*
* This function is part of the sp_packet module.
*/ */
void sp_packet_serialize_to(struct Packet */*notnull*/ packet, size_t sp_packet_serialize_to(struct Packet */*notnull*/ packet,
struct ByteSlice buffer); struct ByteSlice buffer);
/** /**
@ -2009,6 +2028,8 @@ void sp_packet_set_header(struct Packet */*notnull*/ instance,
* Sets the payload of the provided packet to the provided data. * Sets the payload of the provided packet to the provided data.
* *
* This makes previous payload pointers invalid. * This makes previous payload pointers invalid.
*
* This function is part of the sp_packet module.
*/ */
void sp_packet_set_payload(struct Packet */*notnull*/ packet, void sp_packet_set_payload(struct Packet */*notnull*/ packet,
struct ByteSlice data); struct ByteSlice data);
@ -2017,6 +2038,8 @@ void sp_packet_set_payload(struct Packet */*notnull*/ packet,
* Tries to load a [Packet] from the passed array with the specified length. * Tries to load a [Packet] from the passed array with the specified length.
* *
* returns: NULL in case of an error, pointer to the allocated packet otherwise * returns: NULL in case of an error, pointer to the allocated packet otherwise
*
* This function is part of the sp_packet module.
*/ */
struct Packet *sp_packet_try_load(struct ByteSlice data); struct Packet *sp_packet_try_load(struct ByteSlice data);
@ -2024,6 +2047,8 @@ struct Packet *sp_packet_try_load(struct ByteSlice data);
* Converts u16 into [CommandCode]. * Converts u16 into [CommandCode].
* *
* If the provided value is not valid, false is returned and result is not changed. * If the provided value is not valid, false is returned and result is not changed.
*
* This function is part of the sp module.
*/ */
bool sp_u16_to_command_code(uint16_t code, bool sp_u16_to_command_code(uint16_t code,
CommandCode *result); CommandCode *result);
@ -2047,6 +2072,8 @@ void sp_udp_free(struct UdpSocket */*notnull*/ instance);
* if (connection != NULL) * if (connection != NULL)
* sp_udp_send_command(connection, sp_command_clear()); * sp_udp_send_command(connection, sp_command_clear());
* ``` * ```
*
* This function is part of the sp_udp module.
*/ */
struct UdpSocket *sp_udp_open(char */*notnull*/ host); struct UdpSocket *sp_udp_open(char */*notnull*/ host);
@ -2062,6 +2089,8 @@ struct UdpSocket *sp_udp_open(char */*notnull*/ host);
* if (connection != NULL) * if (connection != NULL)
* sp_udp_send_command(connection, sp_command_clear()); * sp_udp_send_command(connection, sp_command_clear());
* ``` * ```
*
* This function is part of the sp_udp module.
*/ */
struct UdpSocket *sp_udp_open_ipv4(uint8_t ip1, struct UdpSocket *sp_udp_open_ipv4(uint8_t ip1,
uint8_t ip2, uint8_t ip2,
@ -2081,6 +2110,8 @@ struct UdpSocket *sp_udp_open_ipv4(uint8_t ip1,
* ```C * ```C
* sp_udp_send_command(connection, sp_command_brightness(5)); * sp_udp_send_command(connection, sp_command_brightness(5));
* ``` * ```
*
* This function is part of the sp_udp module.
*/ */
bool sp_udp_send_command(struct UdpSocket */*notnull*/ connection, bool sp_udp_send_command(struct UdpSocket */*notnull*/ connection,
struct Command command); struct Command command);
@ -2095,6 +2126,8 @@ bool sp_udp_send_command(struct UdpSocket */*notnull*/ connection,
* ```C * ```C
* sp_udp_send_header(connection, sp_command_brightness(5)); * sp_udp_send_header(connection, sp_command_brightness(5));
* ``` * ```
*
* This function is part of the sp_udp module.
*/ */
bool sp_udp_send_header(struct UdpSocket */*notnull*/ udp_connection, bool sp_udp_send_header(struct UdpSocket */*notnull*/ udp_connection,
struct Header header); struct Header header);
@ -2105,6 +2138,8 @@ bool sp_udp_send_header(struct UdpSocket */*notnull*/ udp_connection,
* The passed `packet` gets consumed. * The passed `packet` gets consumed.
* *
* returns: true in case of success * returns: true in case of success
*
* This function is part of the sp_udp module.
*/ */
bool sp_udp_send_packet(struct UdpSocket */*notnull*/ connection, bool sp_udp_send_packet(struct UdpSocket */*notnull*/ connection,
struct Packet */*notnull*/ packet); struct Packet */*notnull*/ packet);

View file

@ -5,39 +5,33 @@ use crate::{
use servicepoint::{ClearCommand, FadeOutCommand, HardResetCommand}; use servicepoint::{ClearCommand, FadeOutCommand, HardResetCommand};
use std::ptr::NonNull; use std::ptr::NonNull;
wrap_functions!(sp_cmd_clear; macro_rules! wrap_cc_only {
($prefix:ident :: $typ:ident ; $(#[$meta:meta])*) => {
wrap_functions!($prefix;
$(#[$meta])*
///
#[doc = concat!(" Returns: a new [`",stringify!($typ),"`] instance.")]
fn new() -> NonNull<$typ> {
heap_move_nonnull($typ)
}
);
wrap_free!($prefix :: $typ);
};
}
wrap_cc_only!(sp_cmd_clear::ClearCommand;
/// Set all pixels to the off state. /// Set all pixels to the off state.
/// ///
/// Does not affect brightness. /// Does not affect brightness.
///
/// Returns: a new [ClearCommand] instance.
fn new() -> NonNull<ClearCommand> {
heap_move_nonnull(ClearCommand)
}
); );
wrap_free!(sp_cmd_clear::ClearCommand); wrap_cc_only!(sp_cmd_hard_reset::HardResetCommand;
wrap_functions!(sp_cmd_hard_reset;
/// Kills the udp daemon on the display, which usually results in a restart. /// Kills the udp daemon on the display, which usually results in a restart.
/// ///
/// Please do not send this in your normal program flow. /// Please do not send this in your normal program flow.
///
/// Returns: a new [HardResetCommand] instance.
fn new() -> NonNull<HardResetCommand> {
heap_move_nonnull(HardResetCommand)
}
); );
wrap_free!(sp_cmd_hard_reset::HardResetCommand); wrap_cc_only!(sp_cmd_fade_out::FadeOutCommand;
wrap_functions!(sp_cmd_fade_out;
/// A yet-to-be-tested command. /// A yet-to-be-tested command.
///
/// Returns: a new [FadeOutCommand] instance.
fn new() -> NonNull<FadeOutCommand> {
heap_move_nonnull(FadeOutCommand)
}
); );
wrap_free!(sp_cmd_fade_out::FadeOutCommand);

View file

@ -1,6 +1,9 @@
use crate::mem::{ use crate::{
macros::wrap_functions,
mem::{
heap_clone, heap_drop, heap_move, heap_move_nonnull, heap_move_ok, heap_clone, heap_drop, heap_move, heap_move_nonnull, heap_move_ok,
heap_remove, heap_remove,
},
}; };
use servicepoint::{ use servicepoint::{
BitVecCommand, BitmapCommand, BrightnessGridCommand, CharGridCommand, BitVecCommand, BitmapCommand, BrightnessGridCommand, CharGridCommand,
@ -66,15 +69,16 @@ impl SPCommand {
}; };
} }
/// Tries to turn a [Packet] into a [SPCommand]. wrap_functions!(sp_cmd_generic;
///
/// The packet is dropped in the process. /// Tries to turn a [Packet] into a [SPCommand].
/// ///
/// Returns: pointer to new [SPCommand] instance or NULL if parsing failed. /// The packet is dropped in the process.
#[no_mangle] ///
pub unsafe extern "C" fn sp_cmd_generic_try_from_packet( /// Returns: pointer to new [SPCommand] instance or NULL if parsing failed.
fn try_from_packet(
packet: NonNull<Packet>, packet: NonNull<Packet>,
) -> SPCommand { ) -> SPCommand {
let packet = *unsafe { Box::from_raw(packet.as_ptr()) }; let packet = *unsafe { Box::from_raw(packet.as_ptr()) };
servicepoint::TypedCommand::try_from(packet) servicepoint::TypedCommand::try_from(packet)
.map(|value| match value { .map(|value| match value {
@ -144,13 +148,12 @@ pub unsafe extern "C" fn sp_cmd_generic_try_from_packet(
tag: CommandTag::Invalid, tag: CommandTag::Invalid,
data: CommandUnion { null: null_mut() }, data: CommandUnion { null: null_mut() },
}) })
} }
/// Clones an [SPCommand] instance. /// Clones an [SPCommand] instance.
/// ///
/// returns: a new [SPCommand] instance. /// returns: a new [SPCommand] instance.
#[no_mangle] fn clone(command: SPCommand) -> SPCommand {
pub unsafe extern "C" fn sp_cmd_generic_clone(command: SPCommand) -> SPCommand {
unsafe { unsafe {
match command.tag { match command.tag {
CommandTag::Clear => SPCommand { CommandTag::Clear => SPCommand {
@ -219,20 +222,19 @@ pub unsafe extern "C" fn sp_cmd_generic_clone(command: SPCommand) -> SPCommand {
CommandTag::Invalid => SPCommand::INVALID, CommandTag::Invalid => SPCommand::INVALID,
} }
} }
} }
/// Deallocates an [SPCommand]. /// Deallocates an [SPCommand].
/// ///
/// Commands with an invalid `tag` do not have to be freed as the `data` pointer should be null. /// Commands with an invalid `tag` do not have to be freed as the `data` pointer should be null.
/// ///
/// # Examples /// # Examples
/// ///
/// ```C /// ```C
/// SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new()); /// SPCommand c = sp_cmd_clear_into_generic(sp_cmd_clear_new());
/// sp_command_free(c); /// sp_command_free(c);
/// ``` /// ```
#[no_mangle] fn free(command: SPCommand) {
pub unsafe extern "C" fn sp_cmd_generic_free(command: SPCommand) {
unsafe { unsafe {
match command.tag { match command.tag {
CommandTag::Invalid => (), CommandTag::Invalid => (),
@ -252,16 +254,15 @@ pub unsafe extern "C" fn sp_cmd_generic_free(command: SPCommand) {
CommandTag::BitmapLegacy => heap_drop(command.data.bitmap_legacy), CommandTag::BitmapLegacy => heap_drop(command.data.bitmap_legacy),
} }
} }
} }
/// Tries to turn a [SPCommand] into a [Packet]. /// Tries to turn a [SPCommand] into a [Packet].
/// The [SPCommand] gets consumed. /// The [SPCommand] gets consumed.
/// ///
/// Returns tag [CommandTag::Invalid] in case of an error. /// Returns tag [CommandTag::Invalid] in case of an error.
#[no_mangle] fn into_packet(
pub unsafe extern "C" fn sp_cmd_generic_into_packet(
command: SPCommand, command: SPCommand,
) -> *mut Packet { ) -> *mut Packet {
match command.tag { match command.tag {
CommandTag::Invalid => null_mut(), CommandTag::Invalid => null_mut(),
CommandTag::Bitmap => { CommandTag::Bitmap => {
@ -295,4 +296,6 @@ pub unsafe extern "C" fn sp_cmd_generic_into_packet(
heap_move(unsafe { heap_remove(command.data.bitmap_legacy).into() }) heap_move(unsafe { heap_remove(command.data.bitmap_legacy).into() })
} }
} }
} }
);

View file

@ -35,7 +35,7 @@ impl ByteSlice {
unsafe { std::slice::from_raw_parts(self.start, self.length) } unsafe { std::slice::from_raw_parts(self.start, self.length) }
} }
pub(crate) unsafe fn as_slice_mut(&mut self) -> &mut [u8] { pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.start, self.length) } unsafe { std::slice::from_raw_parts_mut(self.start, self.length) }
} }

View file

@ -47,10 +47,13 @@ pub struct DisplayBitVec;
#[cfg(feature = "env_logger")] #[cfg(feature = "env_logger")]
mod feature_env_logger { mod feature_env_logger {
use crate::macros::wrap_functions;
wrap_functions!(sp_envlogger;
/// Call this function at the beginning of main to enable rust logging controlled by the /// Call this function at the beginning of main to enable rust logging controlled by the
/// `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/). /// `RUST_LOG` environment variable. See [env_logger](https://docs.rs/env_logger/latest/env_logger/).
#[no_mangle] fn init() {
pub unsafe extern "C" fn init_env_logger() {
env_logger::init(); env_logger::init();
} }
);
} }

View file

@ -1,28 +1,25 @@
use crate::{ use crate::{
containers::ByteSlice, containers::ByteSlice,
macros::{wrap_clone, wrap_fields, wrap_free}, macros::{wrap_clone, wrap_fields, wrap_free, wrap_functions},
mem::{heap_move_nonnull, heap_move_ok}, mem::{heap_move_nonnull, heap_move_ok},
}; };
use servicepoint::{CommandCode, Header, Packet}; use servicepoint::{CommandCode, Header, Packet};
use std::ptr::NonNull; use std::ptr::NonNull;
/// Tries to load a [Packet] from the passed array with the specified length. wrap_functions!(sp_packet;
///
/// returns: NULL in case of an error, pointer to the allocated packet otherwise /// Tries to load a [Packet] from the passed array with the specified length.
#[no_mangle] ///
pub unsafe extern "C" fn sp_packet_try_load(data: ByteSlice) -> *mut Packet { /// returns: NULL in case of an error, pointer to the allocated packet otherwise
fn try_load(data: ByteSlice) -> *mut Packet {
let data = unsafe { data.as_slice() }; let data = unsafe { data.as_slice() };
heap_move_ok(servicepoint::Packet::try_from(data)) heap_move_ok(servicepoint::Packet::try_from(data))
} }
/// Creates a raw [Packet] from parts. /// Creates a raw [Packet] from parts.
/// ///
/// returns: new instance. Will never return null. /// returns: new instance. Will never return null.
#[no_mangle] fn from_parts(header: Header, payload: ByteSlice) -> NonNull<Packet> {
pub unsafe extern "C" fn sp_packet_from_parts(
header: Header,
payload: ByteSlice,
) -> NonNull<Packet> {
let payload = if payload == ByteSlice::INVALID { let payload = if payload == ByteSlice::INVALID {
None None
} else { } else {
@ -30,43 +27,26 @@ pub unsafe extern "C" fn sp_packet_from_parts(
}; };
heap_move_nonnull(Packet { header, payload }) heap_move_nonnull(Packet { header, payload })
} }
/// Returns a pointer to the header field of the provided packet. /// Returns a pointer to the current payload of the provided packet.
/// ///
/// The returned header can be changed and will be valid for the lifetime of the packet. /// Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload.
#[no_mangle] ///
pub unsafe extern "C" fn sp_packet_get_header_mut( /// The returned memory can be changed and will be valid until a new payload is set.
packet: NonNull<Packet>, fn get_payload(packet: NonNull<Packet>) -> ByteSlice {
) -> NonNull<Header> {
NonNull::from(unsafe { &mut (*packet.as_ptr()).header })
}
/// Returns a pointer to the current payload of the provided packet.
///
/// Returns an [ByteSlice::INVALID] instance in case the packet does not have any payload.
///
/// The returned memory can be changed and will be valid until a new payload is set.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_get_payload(
packet: NonNull<Packet>,
) -> ByteSlice {
unsafe { unsafe {
match &mut (*packet.as_ptr()).payload { match &mut (*packet.as_ptr()).payload {
None => ByteSlice::INVALID, None => ByteSlice::INVALID,
Some(payload) => ByteSlice::from_slice(payload), Some(payload) => ByteSlice::from_slice(payload),
} }
} }
} }
/// Sets the payload of the provided packet to the provided data. /// Sets the payload of the provided packet to the provided data.
/// ///
/// This makes previous payload pointers invalid. /// This makes previous payload pointers invalid.
#[no_mangle] fn set_payload(packet: NonNull<Packet>, data: ByteSlice) {
pub unsafe extern "C" fn sp_packet_set_payload(
packet: NonNull<Packet>,
data: ByteSlice,
) {
unsafe { unsafe {
(*packet.as_ptr()).payload = if data == ByteSlice::INVALID { (*packet.as_ptr()).payload = if data == ByteSlice::INVALID {
None None
@ -74,22 +54,19 @@ pub unsafe extern "C" fn sp_packet_set_payload(
Some(data.as_slice().to_vec()) Some(data.as_slice().to_vec())
} }
} }
}
/// Serialize the packet into the provided buffer.
///
/// # Panics
///
/// - if the buffer is not big enough to hold header+payload.
#[no_mangle]
pub unsafe extern "C" fn sp_packet_serialize_to(
packet: NonNull<Packet>,
mut buffer: ByteSlice,
) {
unsafe {
packet.as_ref().serialize_to(buffer.as_slice_mut());
} }
}
/// Serialize the packet into the provided buffer.
///
/// # Panics
///
/// - if the buffer is not big enough to hold header+payload.
fn serialize_to(packet: NonNull<Packet>, buffer: ByteSlice) -> usize {
unsafe {
packet.as_ref().serialize_to(buffer.as_slice_mut()).unwrap_or(0)
}
}
);
wrap_clone!(sp_packet::Packet); wrap_clone!(sp_packet::Packet);
wrap_free!(sp_packet::Packet); wrap_free!(sp_packet::Packet);
@ -98,18 +75,20 @@ wrap_fields!(
sp_packet::Packet; sp_packet::Packet;
prop header: Header { prop header: Header {
get(); get();
mut get();
set(value); set(value);
}; };
); );
/// Converts u16 into [CommandCode]. wrap_functions!(sp;
///
/// If the provided value is not valid, false is returned and result is not changed. /// Converts u16 into [CommandCode].
#[no_mangle] ///
pub unsafe extern "C" fn sp_u16_to_command_code( /// If the provided value is not valid, false is returned and result is not changed.
fn u16_to_command_code(
code: u16, code: u16,
result: *mut CommandCode, result: *mut CommandCode,
) -> bool { ) -> bool {
match CommandCode::try_from(code) { match CommandCode::try_from(code) {
Ok(code) => { Ok(code) => {
unsafe { unsafe {
@ -119,4 +98,6 @@ pub unsafe extern "C" fn sp_u16_to_command_code(
} }
Err(_) => false, Err(_) => false,
} }
} }
);

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
commands::{CommandTag, SPCommand}, commands::{CommandTag, SPCommand},
macros::wrap_free, macros::{wrap_free, wrap_functions},
mem::{heap_move_ok, heap_remove}, mem::{heap_move_ok, heap_remove},
}; };
use servicepoint::{Header, Packet, UdpSocketExt}; use servicepoint::{Header, Packet, UdpSocketExt};
@ -10,79 +10,67 @@ use std::{
ptr::NonNull, ptr::NonNull,
}; };
/// Creates a new instance of [UdpSocket]. wrap_free!(sp_udp::UdpSocket);
///
/// returns: NULL if connection fails, or connected instance wrap_functions!(sp_udp;
///
/// # Examples /// Creates a new instance of [UdpSocket].
/// ///
/// ```C /// returns: NULL if connection fails, or connected instance
/// UdpSocket connection = sp_udp_open("172.23.42.29:2342"); ///
/// if (connection != NULL) /// # Examples
/// sp_udp_send_command(connection, sp_command_clear()); ///
/// ``` /// ```C
#[no_mangle] /// UdpSocket connection = sp_udp_open("172.23.42.29:2342");
pub unsafe extern "C" fn sp_udp_open(host: NonNull<c_char>) -> *mut UdpSocket { /// if (connection != NULL)
/// sp_udp_send_command(connection, sp_command_clear());
/// ```
fn open(host: NonNull<c_char>) -> *mut UdpSocket {
let host = unsafe { CStr::from_ptr(host.as_ptr()) } let host = unsafe { CStr::from_ptr(host.as_ptr()) }
.to_str() .to_str()
.expect("Bad encoding"); .expect("Bad encoding");
heap_move_ok(UdpSocket::bind_connect(host)) heap_move_ok(UdpSocket::bind_connect(host))
} }
/// Creates a new instance of [UdpSocket]. /// Creates a new instance of [UdpSocket].
/// ///
/// returns: NULL if connection fails, or connected instance /// returns: NULL if connection fails, or connected instance
/// ///
/// # Examples /// # Examples
/// ///
/// ```C /// ```C
/// UdpSocket connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); /// UdpSocket connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342);
/// if (connection != NULL) /// if (connection != NULL)
/// sp_udp_send_command(connection, sp_command_clear()); /// sp_udp_send_command(connection, sp_command_clear());
/// ``` /// ```
#[no_mangle] fn open_ipv4(ip1: u8, ip2: u8, ip3: u8, ip4: u8, port: u16) -> *mut UdpSocket {
pub unsafe extern "C" fn sp_udp_open_ipv4(
ip1: u8,
ip2: u8,
ip3: u8,
ip4: u8,
port: u16,
) -> *mut UdpSocket {
let addr = SocketAddrV4::new(Ipv4Addr::from([ip1, ip2, ip3, ip4]), port); let addr = SocketAddrV4::new(Ipv4Addr::from([ip1, ip2, ip3, ip4]), port);
heap_move_ok(UdpSocket::bind_connect(addr)) heap_move_ok(UdpSocket::bind_connect(addr))
} }
/// Sends a [Packet] to the display using the [UdpSocket]. /// Sends a [Packet] to the display using the [UdpSocket].
/// ///
/// The passed `packet` gets consumed. /// The passed `packet` gets consumed.
/// ///
/// returns: true in case of success /// returns: true in case of success
#[no_mangle] fn send_packet(connection: NonNull<UdpSocket>, packet: NonNull<Packet>) -> bool {
pub unsafe extern "C" fn sp_udp_send_packet(
connection: NonNull<UdpSocket>,
packet: NonNull<Packet>,
) -> bool {
let packet = unsafe { heap_remove(packet) }; let packet = unsafe { heap_remove(packet) };
unsafe { connection.as_ref().send(&Vec::from(packet)) }.is_ok() unsafe { connection.as_ref().send(&Vec::from(packet)) }.is_ok()
} }
/// Sends a [SPCommand] to the display using the [UdpSocket]. /// Sends a [SPCommand] to the display using the [UdpSocket].
/// ///
/// The passed `command` gets consumed. /// The passed `command` gets consumed.
/// ///
/// returns: true in case of success /// returns: true in case of success
/// ///
/// # Examples /// # Examples
/// ///
/// ```C /// ```C
/// sp_udp_send_command(connection, sp_command_brightness(5)); /// sp_udp_send_command(connection, sp_command_brightness(5));
/// ``` /// ```
#[no_mangle] fn send_command(connection: NonNull<UdpSocket>, command: SPCommand) -> bool {
pub unsafe extern "C" fn sp_udp_send_command(
connection: NonNull<UdpSocket>,
command: SPCommand,
) -> bool {
unsafe { unsafe {
match command.tag { match command.tag {
CommandTag::Invalid => return false, CommandTag::Invalid => return false,
@ -119,22 +107,18 @@ pub unsafe extern "C" fn sp_udp_send_command(
} }
} }
.is_some() .is_some()
} }
/// Sends a [Header] to the display using the [UdpSocket]. /// Sends a [Header] to the display using the [UdpSocket].
/// ///
/// returns: true in case of success /// returns: true in case of success
/// ///
/// # Examples /// # Examples
/// ///
/// ```C /// ```C
/// sp_udp_send_header(connection, sp_command_brightness(5)); /// sp_udp_send_header(connection, sp_command_brightness(5));
/// ``` /// ```
#[no_mangle] fn send_header(udp_connection: NonNull<UdpSocket>, header: Header) -> bool {
pub unsafe extern "C" fn sp_udp_send_header(
udp_connection: NonNull<UdpSocket>,
header: Header,
) -> bool {
let packet = Packet { let packet = Packet {
header, header,
payload: None, payload: None,
@ -142,6 +126,6 @@ pub unsafe extern "C" fn sp_udp_send_header(
unsafe { udp_connection.as_ref() } unsafe { udp_connection.as_ref() }
.send(&Vec::from(packet)) .send(&Vec::from(packet))
.is_ok() .is_ok()
} }
wrap_free!(sp_udp::UdpSocket); );