1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use crate::command;
use anyhow::{anyhow, Error as AnyError, Result as AnyResult};
use std::convert::TryFrom;

pub trait Data {
    fn serialize(&self) -> Vec<u8>;
}

pub struct Frame {
    frame_type: Type,
    id: ID,
    feature: command::Feature,
}

impl Frame {
    pub fn serialize(&self, sequence_id: u8) -> Vec<u8> {
        // Frame size without data
        let mut buf = Vec::with_capacity(10);
        buf.push(self.frame_type.into());
        buf.push(self.id.into());
        buf.push(sequence_id);
        // frame size as u32
        buf.extend(&[0; 4]);
        buf.extend(self.feature.serialize());

        let buf_size = buf.len();
        buf[3] = (buf_size) as u8;
        buf[4] = (buf_size >> 8) as u8;
        buf[5] = (buf_size >> 16) as u8;
        buf[6] = (buf_size >> 24) as u8;

        buf
    }
}

// frame: [
// Type,
// ID,
// SequenceID,
// ???4294967295-struct.calcsize(">BBBIBBHBbb")*8???,
// ARCOMMANDS_ID_FEATURE_JUMPINGSUMO, Feature
// ARCOMMANDS_ID_JUMPINGSUMO_CLASS_PILOTING, Class
// ARCOMMANDS_ID_JUMPINGSUMO_PILOTING_CMD_PCMD,
// PCMD_FLAG,
// PCMD SPEED,
// PCMD TURN,
// ]

// --------------------- Types --------------------- //

#[derive(Debug, PartialEq, Clone, Copy)]
enum Type {
    Uninitialized, // ARNETWORKAL_FRAME_TYPE_UNINITIALIZED
    Ack,           // ARNETWORKAL_FRAME_TYPE_ACK
    Data,          // ARNETWORKAL_FRAME_TYPE_DATA
    LowLatency,    // ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY
    DataWithAck,   // ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK
    Max,           // ARNETWORKAL_FRAME_TYPE_MAX
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum ID {
    CDNonAck,    //#define BD_NET_CD_NONACK_ID 10
    CDAck,       //#define BD_NET_CD_ACK_ID 11
    CDEmergency, // #define BD_NET_CD_EMERGENCY_ID 12
    CDVideoAck,  // #define BD_NET_CD_VIDEO_ACK_ID 13
    DCVideo,     // #define BD_NET_DC_VIDEO_DATA_ID 125
    DCEvent,     // #define BD_NET_DC_EVENT_ID 126
    DCNavdata,   // #define BD_NET_DC_NAVDATA_ID 127
}

// --------------------- Conversion impls --------------------- //
impl TryFrom<u8> for Type {
    type Error = AnyError;
    fn try_from(v: u8) -> AnyResult<Self> {
        match v {
            0 => Ok(Self::Uninitialized),
            1 => Ok(Self::Ack),
            2 => Ok(Self::Data),
            3 => Ok(Self::LowLatency),
            4 => Ok(Self::DataWithAck),
            5 => Ok(Self::Max),
            _ => Err(anyhow!("{} is not a valid Type variant", v)),
        }
    }
}

impl Into<u8> for Type {
    fn into(self) -> u8 {
        match self {
            Self::Uninitialized => 0,
            Self::Ack => 1,
            Self::Data => 2,
            Self::LowLatency => 3,
            Self::DataWithAck => 4,
            Self::Max => 5,
        }
    }
}

impl TryFrom<u8> for ID {
    type Error = AnyError;
    fn try_from(v: u8) -> AnyResult<Self> {
        match v {
            10 => Ok(Self::CDNonAck),
            11 => Ok(Self::CDAck),
            12 => Ok(Self::CDEmergency),
            13 => Ok(Self::CDVideoAck),
            125 => Ok(Self::DCVideo),
            126 => Ok(Self::DCEvent),
            127 => Ok(Self::DCNavdata),
            _ => Err(anyhow!("{} is not a valid frame ID variant", v)),
        }
    }
}

impl Into<u8> for ID {
    fn into(self) -> u8 {
        match self {
            Self::CDNonAck => 10,
            Self::CDAck => 11,
            Self::CDEmergency => 12,
            Self::CDVideoAck => 13,
            Self::DCVideo => 125,
            Self::DCEvent => 126,
            Self::DCNavdata => 127,
        }
    }
}

// --------------------- Tests --------------------- //

#[cfg(test)]
mod frame_tests {
    use super::*;
    use std::convert::TryInto;

    #[test]
    fn test_frame() {
        assert_frame(Type::Uninitialized, 0);
        assert_frame(Type::Ack, 1);
        assert_frame(Type::Data, 2);
        assert_frame(Type::LowLatency, 3);
        assert_frame(Type::DataWithAck, 4);
        assert_frame(Type::Max, 5);
    }

    #[test]
    fn test_command() {
        assert_command(ID::CDNonAck, 10);
        assert_command(ID::CDAck, 11);
        assert_command(ID::CDEmergency, 12);
        assert_command(ID::CDVideoAck, 13);
        assert_command(ID::DCVideo, 125);
        assert_command(ID::DCEvent, 126);
        assert_command(ID::DCNavdata, 127);
    }

    fn assert_frame(t: Type, v: u8) {
        assert_eq!(t, v.try_into().unwrap());
        let as_u8: u8 = t.into();
        assert_eq!(v, as_u8);
    }

    fn assert_command(c: ID, v: u8) {
        assert_eq!(c, v.try_into().unwrap());
        let as_u8: u8 = c.into();
        assert_eq!(v, as_u8);
    }
}