use crate::{ commands::{CommandTag, SPCommand}, mem::{heap_drop, heap_move_ok, heap_remove}, }; use servicepoint::{Header, Packet, UdpSocketExt}; use std::{ ffi::{c_char, CStr}, net::{Ipv4Addr, SocketAddrV4, UdpSocket}, ptr::NonNull, }; /// 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()); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_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()); /// ``` #[no_mangle] 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); 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 #[no_mangle] pub unsafe extern "C" fn sp_udp_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)); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_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.bitvec)), 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)); /// ``` #[no_mangle] pub unsafe extern "C" fn sp_udp_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() } /// Closes and deallocates a [UdpSocket]. #[no_mangle] pub unsafe extern "C" fn sp_udp_free(connection: NonNull) { unsafe { heap_drop(connection) } }