use crate::{heap_drop, heap_move, heap_remove}; use servicepoint::{Header, Packet, TypedCommand, UdpSocketExt}; use std::ffi::{c_char, CStr}; use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket}; use std::ptr::NonNull; /// Creates a new instance of [UdpConnection]. /// /// returns: NULL if connection fails, or connected instance /// /// # Examples /// /// ```C /// UdpConnection 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"); let connection = match UdpSocket::bind_connect(host) { Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; heap_move(connection) } /// Creates a new instance of [UdpConnection]. /// /// returns: NULL if connection fails, or connected instance /// /// # Examples /// /// ```C /// UdpConnection 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); let connection = match UdpSocket::bind_connect(addr) { Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; heap_move(connection) } /// 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_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 [TypedCommand] to the display using the [UdpConnection]. /// /// 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: NonNull, ) -> bool { let command = unsafe { heap_remove(command) }; unsafe { connection.as_ref().send_command(command) }.is_some() } /// Sends a [Header] to the display using the [UdpConnection]. /// /// 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: vec![], }; unsafe { udp_connection.as_ref() } .send(&Vec::from(packet)) .is_ok() } /// Closes and deallocates a [UdpConnection]. #[no_mangle] pub unsafe extern "C" fn sp_udp_free(connection: NonNull) { unsafe { heap_drop(connection) } }