use crate::{ commands::{CommandTag, SPCommand}, macros::{wrap_free, wrap_functions}, mem::{heap_move_ok, heap_remove}, }; use servicepoint::{Header, Packet, UdpSocketExt}; use std::{ ffi::{c_char, CStr}, net::{Ipv4Addr, SocketAddrV4, UdpSocket}, ptr::NonNull, }; wrap_free!(udp::UdpSocket); wrap_functions!(udp; /// 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)) } /// Sends a [Packet] to the display using the [UdpSocket]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success fn send_packet(connection: NonNull, packet: NonNull) -> bool { let packet = unsafe { heap_remove(packet) }; unsafe { connection.as_ref().send(&Vec::from(packet)) }.is_ok() } /// Sends a [SPCommand] 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(connection: NonNull, command: SPCommand) -> bool { unsafe { match command.tag { CommandTag::Invalid => return false, CommandTag::Bitmap => connection .as_ref() .send_command(heap_remove(command.data.bitmap)), CommandTag::BitVec => connection .as_ref() .send_command(heap_remove(command.data.bit_vec)), CommandTag::BrightnessGrid => connection .as_ref() .send_command(heap_remove(command.data.brightness_grid)), CommandTag::CharGrid => connection .as_ref() .send_command(heap_remove(command.data.char_grid)), CommandTag::Cp437Grid => connection .as_ref() .send_command(heap_remove(command.data.cp437_grid)), CommandTag::GlobalBrightness => connection .as_ref() .send_command(heap_remove(command.data.global_brightness)), CommandTag::Clear => connection .as_ref() .send_command(heap_remove(command.data.clear)), CommandTag::HardReset => connection .as_ref() .send_command(heap_remove(command.data.hard_reset)), CommandTag::FadeOut => connection .as_ref() .send_command(heap_remove(command.data.fade_out)), CommandTag::BitmapLegacy => connection .as_ref() .send_command(heap_remove(command.data.bitmap_legacy)), } } .is_some() } /// 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(udp_connection: NonNull, header: Header) -> bool { let packet = Packet { header, payload: None, }; unsafe { udp_connection.as_ref() } .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; }