use crate::{ commands::{CommandTag, GenericCommand}, macros::{derive_free, wrap_functions, wrap_methods}, mem::{heap_move_ok, heap_remove}, }; use servicepoint::{Header, Packet, UdpSocketExt}; use std::{ ffi::{c_char, CStr}, net::{Ipv4Addr, SocketAddrV4, UdpSocket}, ptr::NonNull, }; derive_free!(UdpSocket); wrap_functions!(associate UdpSocket; /// Creates a new instance of [UdpSocket]. /// /// returns: NULL if connection fails, or connected instance /// /// # Examples /// /// ```C /// UdpSocket connection = sp_udp_open("172.23.42.29:2342"); /// if (connection != NULL) /// sp_udp_send_command(connection, sp_command_clear()); /// ``` fn open(host: NonNull) -> *mut UdpSocket { let host = unsafe { CStr::from_ptr(host.as_ptr()) } .to_str() .expect("Bad encoding"); heap_move_ok(UdpSocket::bind_connect(host)) } /// Creates a new instance of [UdpSocket]. /// /// returns: NULL if connection fails, or connected instance /// /// # Examples /// /// ```C /// UdpSocket connection = sp_udp_open_ipv4(172, 23, 42, 29, 2342); /// if (connection != NULL) /// sp_udp_send_command(connection, sp_command_clear()); /// ``` fn 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); heap_move_ok(UdpSocket::bind_connect(addr)) } ); wrap_methods! {UdpSocket; /// Sends a [Packet] to the display using the [UdpSocket]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success fn send_packet(ref connection, packet: NonNull) -> bool { let packet = unsafe { heap_remove(packet) }; connection.send(&Vec::from(packet)).is_ok() }; /// Sends a [GenericCommand] to the display using the [UdpSocket]. /// /// The passed `command` gets consumed. /// /// returns: true in case of success /// /// # Examples /// /// ```C /// sp_udp_send_command(connection, sp_command_brightness(5)); /// ``` fn send_command(ref connection, command: NonNull) -> bool { unsafe { let command = crate::macros::nonnull_as_mut!(command); let result = match command.tag { CommandTag::Invalid => return false, CommandTag::Bitmap => connection.send_command(heap_remove(command.data.bitmap)), CommandTag::BitVec => connection.send_command(heap_remove(command.data.bit_vec)), CommandTag::BrightnessGrid => connection.send_command(heap_remove(command.data.brightness_grid)), CommandTag::CharGrid => connection.send_command(heap_remove(command.data.char_grid)), CommandTag::Cp437Grid => connection.send_command(heap_remove(command.data.cp437_grid)), CommandTag::GlobalBrightness => connection.send_command(heap_remove(command.data.global_brightness)), CommandTag::Clear => connection.send_command(heap_remove(command.data.clear)), CommandTag::HardReset => connection.send_command(heap_remove(command.data.hard_reset)), CommandTag::FadeOut => connection.send_command(heap_remove(command.data.fade_out)), CommandTag::BitmapLegacy => connection.send_command(heap_remove(command.data.bitmap_legacy)), }.is_some(); *command = GenericCommand::INVALID; result } }; /// Sends a [Header] to the display using the [UdpSocket]. /// /// returns: true in case of success /// /// # Examples /// /// ```C /// sp_udp_send_header(connection, sp_command_brightness(5)); /// ``` fn send_header(ref udp_connection, header: Header) -> bool { let packet = Packet { header, payload: None, }; udp_connection.send(&Vec::from(packet)).is_ok() }; } mod _hidden { /// This is a type only used by cbindgen to have a type for pointers. /// /// See [servicepoint::UdpSocketExt]. #[allow(unused)] pub struct UdpSocket; }