Packet

Struct Packet 

Source
pub struct Packet<const T: usize> { /* private fields */ }

Implementations§

Source§

impl<const T: usize> Packet<T>

Source

pub fn new() -> Self

Creates a new Packet with a data buffer of const T: usize bytes

§Example
pub fn main() {
    let rx = flem::Packet::<100>::new(); // Create new packet that can send / receive up to 100 bytes per packet

}
Source

pub fn pack_data(&mut self, request: u16, data: &[u8]) -> Result<(), Status>

Convenience function to response with data. The response byte is automatically set to SUCCESS.

Source

pub fn pack_error( &mut self, request: u16, error: u16, data: &[u8], ) -> Result<(), Status>

Convenience function to respond quickly if an error occurs (without data).

Source

pub fn pack_id(&mut self, id: &DataId, ascii: bool) -> Result<(), Status>

Convenience function to respond with the ID. If communicating with UTF-8 partners, ascii should be true. This can only be used if the data packets are 30 bytes or longer (or twice that if ascii = false).

§Arguments
  • ascii - Packages the ID as a UTF-8 ID. Used when talking to C/C++ partners.
Source

pub fn pack(&mut self)

Pack a packet up: adds header and computes checksum.

§Example
pub fn main() {
    use flem::{Packet};

    const PACKET_SIZE: usize = 64; // 64 byte packet

    const FLEM_EXAMPLE_REQUEST: u16 = 0xF;

    let mut rx = Packet::<PACKET_SIZE>::new();

    let mut data = [0 as u8; PACKET_SIZE];

    /* Add data as needed to the data buffer */

    rx.add_data(&data);
    rx.set_request(FLEM_EXAMPLE_REQUEST);
     
    assert_ne!(rx.get_header(), 0x5555, "Packet header hasn't been set, should NOT be 0x5555");
     
    rx.pack();

    assert_eq!(rx.get_header(), 0x5555, "Packet header has been set, should be 0x5555");

    /* Send data */

}
Source

pub fn get_data(&self) -> [u8; T]

Returns a copy of the data part of the packet as a byte array

Source

pub fn add_data(&mut self, data: &[u8]) -> Result<(), Status>

Adds data to a packet if there is room.

Source

pub fn validate(&mut self) -> bool

Computes the Checksum on the packet and compares to the sent checksum. Returns true if there is a match, otherwise false.

Source

pub fn construct(&mut self, byte: u8) -> Result<(), Status>

Construct a packet one byte at a time. An internal counter keeps track of where the byte should go. The current return value is the Status and should be one of the following:

  • HeaderBytesNotFound - The packet header was not found
  • ChecksumError - The computed checksum does not match the sent checksum
  • PacketOverflow - Data is being added beyond length of the packet
  • PacketBuilding - This should be the default most of the time and indicates the packet is being built without issues so far.
  • PacketReceived - All data bytes have been received and the checksum has been validated
§Arguments
  • byte - A single byte to add to a packet.
§Example
pub fn main() {
    use flem::{Packet};

    const PACKET_SIZE: usize = 64; // 64 byte packet

    const FLEM_EXAMPLE_REQUEST: u16 = 0xF;

    let mut rx = Packet::<PACKET_SIZE>::new();
    let mut tx = Packet::<PACKET_SIZE>::new();

    let mut data = [0 as u8; PACKET_SIZE];

    /* Add data as needed to the data buffer */

    tx.add_data(&data);
    tx.set_request(FLEM_EXAMPLE_REQUEST);
    tx.pack();


    /* Send data */
     
    let tx_as_u8_array = tx.bytes();

    // We are sending bytes across a hardware bus
    let mut packet_received = false;
    for byte in tx_as_u8_array {
        // The received is getting bytes on the hardware bus
        match rx.construct(*byte) {
            Ok(_) => {
                packet_received = true;
            },
            Err(status) => {
                /* Handle other cases here */
            }
        }
    }

    assert!(packet_received, "Packet should have been constructed and validated.");

}
Source

pub fn get_byte(&mut self) -> Result<u8, Status>

This function treats the entire packet as a byte array and uses internal counters to determine the next byte. Keep calling this until either an error occurs or status is Status::GetByteFinished.

It is often easier to use .bytes(), but this function is meant to be used in an async nature, for example an interrupt driven UART transmit FIFO.

The return value is a Result composed of the byte requested if everything is going well, or a Status as an Error indicating all bytes have been gotten.

§Example
pub fn main() {
   use flem::{Packet};
   use heapless;
   const PACKET_SIZE: usize = 64; // 64 byte packet
   const FLEM_EXAMPLE_REQUEST: u16 = 0xF;
   
   let mut rx = Packet::<PACKET_SIZE>::new();
   let mut tx = Packet::<PACKET_SIZE>::new();
   
   let mut data = [0 as u8; PACKET_SIZE];
   
   /* Add data as needed to the data buffer */
   tx.add_data(&data);
   tx.set_request(FLEM_EXAMPLE_REQUEST);
   tx.pack();

   /* Send data */
   let mut tx_fifo_queue = heapless::spsc::Queue::<u8, 8>::new();
   let mut keep_sending = true;
   let mut packet_received = false;
   let mut status = flem::Status::Ok;
   
   while keep_sending {
       if !tx_fifo_queue.is_full() && status != flem::Status::GetByteFinished {
           match tx.get_byte() {
               Ok(byte) => {
                   tx_fifo_queue.enqueue(byte).unwrap();
               },                
               Err(x) => {
                   /* Tx code should stop transmitting */
                   status = x;

               }
           }
       }else{
           // Queue is full, Tx the data, Rx on the other end
           while !tx_fifo_queue.is_empty() {
               match rx.construct(tx_fifo_queue.dequeue().unwrap()) {
                   Ok(_) => {
                       packet_received = true;
                       keep_sending = false;
                   },
                   Err(status) => {
                       /* Catch other statuses here on the Rx side */
                   }
               }
           }
       }
   }

   assert!(packet_received, "Packet should have been transferred");

   // This test is redundant, since the checksums passed, still nice to see

   let rx_bytes = rx.bytes();
   let tx_bytes = tx.bytes();

   for i in 0..rx_bytes.len() {
       assert_eq!(rx_bytes[i], tx_bytes[i], "Rx and Tx packets don't match");
   }
}
Source

pub fn set_request(&mut self, request: u16)

Sets the Flem request field

Source

pub fn get_request(&self) -> u16

Gets the Flem request field

Source

pub fn get_checksum(&self) -> u16

Returns the stored checksum value

Source

pub fn set_response(&mut self, response: u16)

Sets the Flem response field

Source

pub fn get_response(&self) -> u16

Gets the Flem response field

Source

pub fn get_status(&mut self) -> Status

Gets the status byte from the packet

Source

pub fn get_header(&self) -> u16

Get the header byte as u16

Source

pub fn get_data_length(&self) -> usize

Source

pub fn bytes(&self) -> &[u8]

Returns the entire packet as a u8 byte array

Source

pub fn checksum(&mut self, store: bool) -> u16

Computes a CRC16 IBM style checksum on the packet, except the header and checksum bytes

Source

pub fn reset_lazy(&mut self)

Resets the packet to all 0’s, but does not clear the data array. Much faster than zeroing out the packet’s data buffer. Packets should be cleared before reusing, both Rx and Tx.

Source

pub fn reset(&mut self)

Resets the packet. The data array is cleared only if clear_data is true. Packets should be cleared before reusing, both Rx and Tx.

§Arguments
  • clear_data - Zero out the data array.
Source

pub fn length(&self) -> usize

Length of the packet, including the header and data.

§Example

pub fn main() {
    const PACKET_SIZE: usize = 100;

    let mut tx = flem::Packet::<PACKET_SIZE>::new();

    assert_eq!(tx.length() as usize, flem::FLEM_HEADER_SIZE as usize, "Length should be only {} bytes for the header", flem::FLEM_HEADER_SIZE);

    let data = [0 as u8; PACKET_SIZE];

    tx.add_data(&data);

    assert_eq!(tx.length() as usize, PACKET_SIZE + flem::FLEM_HEADER_SIZE as usize, "Length should be {} bytes (packet size) + {} bytes for the header", PACKET_SIZE, flem::FLEM_HEADER_SIZE);
}

Trait Implementations§

Source§

impl<const T: usize> Clone for Packet<T>

Source§

fn clone(&self) -> Packet<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<const T: usize> Debug for Packet<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<const T: usize> Copy for Packet<T>

Auto Trait Implementations§

§

impl<const T: usize> Freeze for Packet<T>

§

impl<const T: usize> RefUnwindSafe for Packet<T>

§

impl<const T: usize> Send for Packet<T>

§

impl<const T: usize> Sync for Packet<T>

§

impl<const T: usize> Unpin for Packet<T>

§

impl<const T: usize> UnwindSafe for Packet<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.