2024-05-15 20:34:51 +02:00
|
|
|
use std::mem::size_of;
|
|
|
|
|
2024-05-12 01:30:55 +02:00
|
|
|
/// A raw header. Should probably not be used directly.
|
2024-05-10 21:27:34 +02:00
|
|
|
#[derive(Debug)]
|
2024-05-10 00:53:12 +02:00
|
|
|
pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
|
|
|
|
|
2024-05-12 01:30:55 +02:00
|
|
|
/// The raw payload. Should probably not be used directly.
|
2024-05-10 00:53:12 +02:00
|
|
|
pub type Payload = Vec<u8>;
|
|
|
|
|
2024-05-12 01:30:55 +02:00
|
|
|
/// The raw packet. Should probably not be used directly.
|
2024-05-10 21:27:34 +02:00
|
|
|
#[derive(Debug)]
|
2024-05-10 00:53:12 +02:00
|
|
|
pub struct Packet(pub Header, pub Payload);
|
|
|
|
|
2024-05-15 20:34:51 +02:00
|
|
|
impl From<Packet> for Vec<u8> {
|
|
|
|
/// Turn the packet into raw bytes ready to send
|
|
|
|
fn from(value: Packet) -> Self {
|
|
|
|
let Packet(Header(mode, a, b, c, d), payload) = value;
|
2024-05-10 00:53:12 +02:00
|
|
|
|
2024-05-11 23:28:08 +02:00
|
|
|
let mut packet = vec![0u8; 10 + payload.len()];
|
2024-05-15 23:08:54 +02:00
|
|
|
packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode));
|
2024-05-10 19:55:18 +02:00
|
|
|
packet[2..=3].copy_from_slice(&u16::to_be_bytes(a));
|
|
|
|
packet[4..=5].copy_from_slice(&u16::to_be_bytes(b));
|
|
|
|
packet[6..=7].copy_from_slice(&u16::to_be_bytes(c));
|
|
|
|
packet[8..=9].copy_from_slice(&u16::to_be_bytes(d));
|
2024-05-10 00:53:12 +02:00
|
|
|
|
2024-05-15 23:08:54 +02:00
|
|
|
packet[10..].copy_from_slice(&payload);
|
2024-05-10 00:53:12 +02:00
|
|
|
|
2024-05-15 23:08:54 +02:00
|
|
|
packet
|
2024-05-10 00:53:12 +02:00
|
|
|
}
|
2024-05-10 20:08:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn u16_from_be_slice(slice: &[u8]) -> u16 {
|
|
|
|
let mut bytes = [0u8; 2];
|
|
|
|
bytes[0] = slice[0];
|
|
|
|
bytes[1] = slice[1];
|
|
|
|
u16::from_be_bytes(bytes)
|
|
|
|
}
|
|
|
|
|
2024-05-15 20:34:51 +02:00
|
|
|
impl TryFrom<&[u8]> for Packet {
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
/// Tries to interpret the bytes as a `Packet`.
|
|
|
|
///
|
|
|
|
/// returns: `Error` if slice is not long enough to be a `Packet`
|
|
|
|
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
|
|
|
if value.len() < size_of::<Header>() {
|
|
|
|
return Err(());
|
|
|
|
}
|
|
|
|
|
2024-05-10 20:08:56 +02:00
|
|
|
let mode = u16_from_be_slice(&value[0..=1]);
|
|
|
|
let a = u16_from_be_slice(&value[2..=3]);
|
|
|
|
let b = u16_from_be_slice(&value[4..=5]);
|
|
|
|
let c = u16_from_be_slice(&value[6..=7]);
|
|
|
|
let d = u16_from_be_slice(&value[8..=9]);
|
|
|
|
let payload = value[10..].to_vec();
|
|
|
|
|
2024-05-15 20:34:51 +02:00
|
|
|
Ok(Packet(Header(mode, a, b, c, d), payload))
|
2024-05-10 20:08:56 +02:00
|
|
|
}
|
2024-05-11 23:28:08 +02:00
|
|
|
}
|
2024-05-12 17:15:30 +02:00
|
|
|
|
2024-05-15 20:34:51 +02:00
|
|
|
#[cfg(feature = "c-api")]
|
|
|
|
mod c_api {
|
|
|
|
use std::ptr::null_mut;
|
|
|
|
|
|
|
|
use crate::{Command, Packet};
|
2024-05-12 17:15:30 +02:00
|
|
|
|
2024-05-15 20:34:51 +02:00
|
|
|
/// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn sp2_packet_from_command(command: *mut Command) -> *mut Packet {
|
|
|
|
let command = *Box::from_raw(command);
|
|
|
|
let packet = command.into();
|
|
|
|
Box::into_raw(Box::new(packet))
|
2024-05-12 17:15:30 +02:00
|
|
|
}
|
2024-05-15 20:34:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn sp2_packet_try_load(data: *const u8, length: usize) -> *mut Packet {
|
|
|
|
let data = std::slice::from_raw_parts(data, length);
|
|
|
|
match Packet::try_from(data) {
|
|
|
|
Err(_) => null_mut(),
|
|
|
|
Ok(packet) => Box::into_raw(Box::new(packet))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deallocates a `Packet`.
|
|
|
|
///
|
|
|
|
/// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn sp2_packet_dealloc(this: *mut Packet) {
|
|
|
|
_ = Box::from_raw(this)
|
|
|
|
}
|
|
|
|
}
|