use super::{
tx_ack, types, write_preamble, Error as PktError, Identifier, MacAddress, SerializablePacket,
Tmst,
};
use serde::{Deserialize, Serialize};
use std::io::{Cursor, Write};
use types::{deserialize_codr, serialize_codr, DataRate, Modulation};
#[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),
}
}
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]))
}
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 }
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TxPk {
#[serde(flatten)]
pub time: Time,
pub freq: f64, pub rfch: u64, pub powe: u64, pub modu: Modulation, pub datr: DataRate, #[serde(
serialize_with = "serialize_codr",
deserialize_with = "deserialize_codr"
)]
pub codr: Option<lora_modulation::CodingRate>, #[serde(skip_serializing_if = "Option::is_none")]
pub fdev: Option<u64>, pub ipol: bool, pub prea: Option<u64>, #[serde(flatten)]
pub data: PhyData,
#[serde(skip_serializing_if = "Option::is_none")]
pub ncrc: Option<bool>, }
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Time {
imme: bool, #[serde(skip_serializing_if = "Option::is_none")]
tmst: Option<Tmst>, #[serde(skip_serializing_if = "Option::is_none")]
tmms: Option<Tmst>, }
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;
}
pub fn data(&self) -> &[u8] {
self.data.as_ref()
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
}
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))
}
}