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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
### 5.4. PULL_RESP packet ###
That packet type is used by the server to send RF packets and associated
metadata that will have to be emitted by the gateway.

Bytes  | Function
:------:|---------------------------------------------------------------------
0      | protocol version = 2
1-2    | random token
3      | PULL_RESP identifier 0x03
4-end  | JSON object, starting with {, ending with }, see section 6
 */
use super::{
    tx_ack, write_preamble, CodingRate, DataRate, Error as PktError, Identifier, MacAddress,
    Modulation, SerializablePacket, Tmst,
};
use serde::{Deserialize, Serialize};
use std::io::{Cursor, Write};

#[derive(Debug, Clone)]
pub struct Packet {
    pub random_token: u16,
    pub data: Data,
}

impl Packet {
    pub fn into_ack_for_gateway(self, gateway_mac: MacAddress) -> tx_ack::Packet {
        tx_ack::Packet {
            gateway_mac,
            random_token: self.random_token,
            data: tx_ack::Data::default(),
        }
    }

    pub fn into_nack_with_error_for_gateway(
        self,
        error: super::tx_ack::Error,
        gateway_mac: MacAddress,
    ) -> tx_ack::Packet {
        tx_ack::Packet {
            gateway_mac,
            random_token: self.random_token,
            data: super::tx_ack::Data::new_with_error(error),
        }
    }

    // sets a default Gateway value
    pub fn into_nack_with_error(self, e: super::tx_ack::Error) -> tx_ack::Packet {
        self.into_nack_with_error_for_gateway(e, MacAddress::from([0; 8]))
    }

    // sets a default Gateway value
    pub fn into_ack(self) -> tx_ack::Packet {
        self.into_ack_for_gateway(MacAddress::from([0; 8]))
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Data {
    pub txpk: TxPk,
}

impl Data {
    pub fn from_txpk(txpk: TxPk) -> Data {
        Data { txpk }
    }
}

/*
 Name |  Type  | Function
:----:|:------:|--------------------------------------------------------------
 imme | bool   | Send packet immediately (will ignore tmst & time)
 tmst | number | Send packet on a certain timestamp value (will ignore time)
 tmms | number | Send packet at a certain GPS time (GPS synchronization required)
 freq | number | TX central frequency in MHz (unsigned float, Hz precision)
 rfch | number | Concentrator "RF chain" used for TX (unsigned integer)
 powe | number | TX output power in dBm (unsigned integer, dBm precision)
 modu | string | Modulation identifier "LORA" or "FSK"
 datr | string | LoRa datarate identifier (eg. SF12BW500)
 datr | number | FSK datarate (unsigned, in bits per second)
 codr | string | LoRa ECC coding rate identifier
 fdev | number | FSK frequency deviation (unsigned integer, in Hz)
 ipol | bool   | Lora modulation polarization inversion
 prea | number | RF preamble size (unsigned integer)
 size | number | RF packet payload size in bytes (unsigned integer)
 data | string | Base64 encoded RF packet payload, padding optional
 ncrc | bool   | If true, disable the CRC of the physical layer (optional)
 */

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TxPk {
    #[serde(flatten)]
    pub time: Time,
    pub freq: f64,        // TX central frequency in MHz (unsigned float, Hz precision)
    pub rfch: u64,        // Concentrator "RF chain" used for TX (unsigned integer)
    pub powe: u64,        // TX output power in dBm (unsigned integer, dBm precision)
    pub modu: Modulation, // Modulation identifier "LORA" or "FSK"
    pub datr: DataRate,   // LoRa datarate identifier (eg. SF12BW500)
    pub codr: CodingRate, // LoRa ECC coding rate identifier
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fdev: Option<u64>, //FSK frequency deviation (unsigned integer, in Hz)
    pub ipol: bool,       // Lora modulation polarization inversion
    pub prea: Option<u64>, // RF preamble size (unsigned integer)
    #[serde(flatten)]
    pub data: PhyData,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ncrc: Option<bool>, // If true, disable the CRC of the physical layer (optional)
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Time {
    imme: bool, // Send packet immediately (will ignore tmst & time)
    #[serde(skip_serializing_if = "Option::is_none")]
    tmst: Option<Tmst>, // Send packet on a certain timestamp value (will ignore time)
    #[serde(skip_serializing_if = "Option::is_none")]
    tmms: Option<Tmst>, // Send packet at a certain GPS time (GPS synchronization required)
}

impl Time {
    pub fn is_immediate(&self) -> bool {
        self.imme
    }

    pub fn tmst(&self) -> Option<u32> {
        if let Some(Tmst::Tmst(val)) = self.tmst {
            Some(val)
        } else {
            None
        }
    }

    pub fn tmms(&self) -> Option<u32> {
        if let Some(Tmst::Tmst(val)) = self.tmms {
            Some(val)
        } else {
            None
        }
    }

    pub fn immediate() -> Time {
        Time {
            imme: true,
            tmst: None,
            tmms: None,
        }
    }

    pub fn by_tmst(tmst: u32) -> Time {
        Time {
            imme: false,
            tmst: Some(Tmst::Tmst(tmst)),
            tmms: None,
        }
    }

    pub fn by_tmms(tmms: u32) -> Time {
        Time {
            imme: false,
            tmst: None,
            tmms: Some(Tmst::Tmst(tmms)),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PhyData {
    #[serde(with = "crate::packet::types::base64")]
    data: Vec<u8>,
    size: usize,
}

impl AsRef<[u8]> for PhyData {
    fn as_ref(&self) -> &[u8] {
        self.data.as_ref()
    }
}

impl PhyData {
    pub fn new(data: Vec<u8>) -> Self {
        Self {
            size: data.len(),
            data,
        }
    }
    pub fn set(&mut self, data: Vec<u8>) {
        self.size = data.len();
        self.data = data;
    }
}

impl TxPk {
    pub fn is_immediate(&self) -> bool {
        self.time.imme
    }

    pub fn get_tmst(&self) -> Option<u32> {
        if let Some(Tmst::Tmst(tmst)) = self.time.tmst {
            Some(tmst)
        } else {
            None
        }
    }
}

use std::fmt;
impl fmt::Display for TxPk {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}, {:.2} MHz, {:?}, len: {}",
            if let Some(Tmst::Tmst(time)) = self.time.tmst {
                format!("@{time} us")
            } else {
                "immediately".into()
            },
            self.freq,
            self.datr,
            self.data.size
        )
    }
}

impl SerializablePacket for Packet {
    fn serialize(&self, buffer: &mut [u8]) -> std::result::Result<u64, PktError> {
        let mut w = Cursor::new(buffer);
        write_preamble(&mut w, self.random_token)?;
        w.write_all(&[Identifier::PullResp as u8])?;
        w.write_all(serde_json::to_string(&self.data)?.as_bytes())?;
        Ok(w.position())
    }
}

impl From<Packet> for super::Packet {
    fn from(packet: Packet) -> super::Packet {
        super::Packet::Down(super::Down::PullResp(Box::new(packet)))
    }
}

impl From<Box<Packet>> for super::Packet {
    fn from(packet: Box<Packet>) -> super::Packet {
        super::Packet::Down(super::Down::PullResp(packet))
    }
}