arduino-tnc

git clone https://git.bradleygannon.com/arduino-tnc.git
Log | Files | Refs

kiss.rs (4536B)


      1 pub(crate) enum KissAction {
      2     PushTx(u8),
      3     ClearTx,
      4     SendTx,
      5     _SetTxDelay { tx_delay_10ms: u8 },
      6     _SetPersistence { persistence: u8 },
      7     _SetSlotTime { slot_time_10ms: u8 },
      8     _SetTxTail { tx_tail_10ms: u8 },
      9     _SetFullDuplex { full_duplex: bool },
     10     _SetHardware { argument: u8 },
     11     _Return,
     12 }
     13 
     14 enum KissCommand {
     15     DataFrame,
     16     TxDelay,
     17     Persistence,
     18     SlotTime,
     19     TxTail,
     20     FullDuplex,
     21     SetHardware,
     22     Return,
     23     #[allow(dead_code)]
     24     Invalid(u8),
     25 }
     26 
     27 enum KissPort {
     28     Port0,
     29     Port1,
     30     Port2,
     31     Port3,
     32     Port4,
     33     Port5,
     34     Port6,
     35     Port7,
     36     Port8,
     37     Port9,
     38     Port10,
     39     Port11,
     40     Port12,
     41     Port13,
     42     Port14,
     43     Port15,
     44 }
     45 
     46 struct KissHostTypeIndicator {
     47     _function: KissCommand,
     48     _port: KissPort,
     49 }
     50 
     51 impl From<u8> for KissHostTypeIndicator {
     52     fn from(value: u8) -> Self {
     53         let function_number = (value & 0b1111_0000) >> 4;
     54         let function = match function_number {
     55             0 => KissCommand::DataFrame,
     56             1 => KissCommand::TxDelay,
     57             2 => KissCommand::Persistence,
     58             3 => KissCommand::SlotTime,
     59             4 => KissCommand::TxTail,
     60             5 => KissCommand::FullDuplex,
     61             6 => KissCommand::SetHardware,
     62             15 => KissCommand::Return,
     63             f => KissCommand::Invalid(f),
     64         };
     65         let port_index = value & 0b0000_1111;
     66         let port = match port_index {
     67             0 => KissPort::Port0,
     68             1 => KissPort::Port1,
     69             2 => KissPort::Port2,
     70             3 => KissPort::Port3,
     71             4 => KissPort::Port4,
     72             5 => KissPort::Port5,
     73             6 => KissPort::Port6,
     74             7 => KissPort::Port7,
     75             8 => KissPort::Port8,
     76             9 => KissPort::Port9,
     77             10 => KissPort::Port10,
     78             11 => KissPort::Port11,
     79             12 => KissPort::Port12,
     80             13 => KissPort::Port13,
     81             14 => KissPort::Port14,
     82             15 => KissPort::Port15,
     83             p => unreachable!("Expected port index in range [0, 15] but got {p}"),
     84         };
     85         KissHostTypeIndicator {
     86             _function: function,
     87             _port: port,
     88         }
     89     }
     90 }
     91 
     92 pub(crate) enum KissTncState {
     93     Idle,
     94     Fend,
     95     TypeIndicator,
     96     Data,
     97     Fesc,
     98 }
     99 
    100 impl KissTncState {
    101     const FEND: u8 = 0xc0;
    102     const FESC: u8 = 0xdb;
    103     const TFEND: u8 = 0xdc;
    104     const TFESC: u8 = 0xdd;
    105 
    106     pub(crate) fn update(&mut self, byte: u8) -> Option<KissAction> {
    107         match (&self, byte) {
    108             // FEND after data means the frame is complete and ready to send
    109             (KissTncState::Data, Self::FEND) => {
    110                 *self = KissTncState::Fend;
    111                 Some(KissAction::SendTx)
    112             }
    113 
    114             // FEND anywhere else means the frame is incomplete and should not be sent, but a new
    115             // frame is beginning
    116             (_, Self::FEND) => {
    117                 *self = KissTncState::Fend;
    118                 Some(KissAction::ClearTx)
    119             }
    120 
    121             // Idle state waits for FEND
    122             (KissTncState::Idle, _) => {
    123                 *self = KissTncState::Idle;
    124                 None
    125             }
    126 
    127             // Type indicator follows FEND
    128             (KissTncState::Fend, _) => {
    129                 *self = KissTncState::TypeIndicator;
    130                 None
    131             }
    132 
    133             // FESC can follow frame type indicator or data
    134             (KissTncState::TypeIndicator, Self::FESC) => {
    135                 *self = KissTncState::Fesc;
    136                 None
    137             }
    138             (KissTncState::Data, Self::FESC) => {
    139                 *self = KissTncState::Fesc;
    140                 None
    141             }
    142 
    143             // Data follows type indicator
    144             (KissTncState::TypeIndicator, _) => {
    145                 *self = KissTncState::Data;
    146                 None
    147             }
    148 
    149             // Handle escaped bytes
    150             (KissTncState::Fesc, Self::TFEND) => {
    151                 *self = KissTncState::Data;
    152                 Some(KissAction::PushTx(Self::FEND))
    153             }
    154             (KissTncState::Fesc, Self::TFESC) => {
    155                 *self = KissTncState::Data;
    156                 Some(KissAction::PushTx(Self::FESC))
    157             }
    158             (KissTncState::Fesc, b) => {
    159                 *self = KissTncState::Data;
    160                 Some(KissAction::PushTx(b))
    161             }
    162 
    163             // Data follows data
    164             (KissTncState::Data, b) => {
    165                 *self = KissTncState::Data;
    166                 Some(KissAction::PushTx(b))
    167             }
    168         }
    169     }
    170 }