use crc::{Crc, CRC_16_IBM_3740}; use crate::ldpc::ldpc_encode; const TEXT_MESSAGE_LEN: usize = 252; const FEC_PACKET_LEN: usize = 256 + 2 + 65; pub enum Packet { TextMessage(u8, [u8; TEXT_MESSAGE_LEN]), } impl Packet { // Cuts off messages that are too long pub fn new_text_message(msg: &str) -> Self { let mut out = [0x55; TEXT_MESSAGE_LEN]; // this technically would allow part of a character to be sent // (unicode multi-byte character that gets cut off at the end) // ideally, we would iterate over characters and add them, so that // we could abort before adding a partial character for (i, b) in msg.as_bytes().iter().enumerate().take(TEXT_MESSAGE_LEN) { out[i] = *b; } let len = msg .as_bytes() .len() .min(TEXT_MESSAGE_LEN) .try_into() .unwrap(); Self::TextMessage(len, out) } } impl Packet { // increments text_id if we're sending a text message packet pub fn into_raw(self, text_id: &mut u16) -> RawPacket { match self { Packet::TextMessage(len, txt) => { let id = *text_id; *text_id = text_id.wrapping_add(1); let mut out = [0; 256]; out[0] = 0x00; // packet type out[1] = len; out[2..4].clone_from_slice(&id.to_be_bytes()); out[4..].clone_from_slice(&txt); RawPacket(out) } } } } pub struct RawPacket(pub [u8; 256]); pub struct FecPacket(pub [u8; FEC_PACKET_LEN]); impl From<RawPacket> for FecPacket { fn from(value: RawPacket) -> Self { let crc = Crc::<u16>::new(&CRC_16_IBM_3740); let checksum = crc.checksum(&value.0); let mut data = [0; 256 + 2 + 65]; data[0..256].copy_from_slice(&value.0); data[256..258].copy_from_slice(&checksum.to_le_bytes()); ldpc_encode(&mut data); FecPacket(data) } }