pub enum Message {
Version {
station: String,
firmware: String,
package: String,
model: String,
protocol: u32,
features: String,
},
RouterConfig {
net_id: Option<Vec<u32>>,
join_eui: Vec<(u64, u64)>,
region: String,
max_eirp: f64,
hwspec: String,
freq_range: (u32, u32),
data_rates: Vec<Option<(u8, u32, bool)>>,
},
JoinRequest {
mhdr: u8,
join_eui: Eui,
dev_eui: Eui,
dev_nonce: u16,
mic: i32,
data_rate: u8,
frequency_hz: u32,
levels: Levels,
},
Uplink {
mhdr: u8,
dev_addr: i32,
fctrl: u8,
fcnt: u16,
fopts: Vec<u8>,
fport: Option<u8>,
payload: Vec<u8>,
mic: i32,
data_rate: u8,
frequency_hz: u32,
levels: Levels,
},
Proprietary {
payload: Vec<u8>,
data_rate: u8,
frequency_hz: u32,
levels: Levels,
},
Downlink {
dev_eui: Eui,
class: u8,
diid: i64,
pdu: Vec<u8>,
rx_delay: Option<u8>,
rx1: Option<(u8, u32)>,
rx2: Option<(u8, u32)>,
ping_slot: Option<(u8, u32)>,
priority: u8,
xtime: Option<i64>,
rctx: Option<i64>,
gpstime: Option<i64>,
},
Schedule {
frames: Vec<Broadcast>,
},
Transmitted {
diid: i64,
dev_eui: Eui,
rctx: i64,
xtime: i64,
txtime: f64,
gpstime: Option<i64>,
},
TimeSync {
txtime: Option<i64>,
xtime: Option<i64>,
gpstime: Option<i64>,
},
Other {
msgtype: String,
},
}Expand description
Every message the websocket carries once the session is open.
Variants§
Version
What the station is, sent first thing after the websocket opens.
Fields
RouterConfig
How the server tells the station to configure its radios.
Fields
net_id: Option<Vec<u32>>The networks whose data frames the station forwards, or None to forward every
network’s.
A station matches each entry against the top seven bits of a frame’s device
address, so an empty list forwards no data frame at all, while None, written as
null, filters nothing.
join_eui: Vec<(u64, u64)>The join identifier ranges whose join requests are forwarded, as inclusive pairs; an empty list filters nothing.
data_rates: Vec<Option<(u8, u32, bool)>>The data rates, indexed by data-rate number, each a spreading factor, a bandwidth in hertz, and whether it is downlink only.
A spreading factor of 0 is FSK. None is a number the table leaves undefined,
which the protocol writes as a spreading factor of -1 so the entries after it keep
their numbers.
JoinRequest
A join request the station heard.
Fields
Uplink
A data frame the station heard.
Fields
Proprietary
A frame this protocol does not describe, which the station heard and passes on whole.
Fields
Downlink
A frame the server asks the station to transmit.
A class A frame, and a class C frame answering an uplink, are timed from that uplink’s
xtime and go out in rx1 or rx2, the first preferred. A class B frame goes out at
gpstime in a ping slot. A class C frame answering nothing names rx2 alone.
Fields
Schedule
Frames the server asks the station to transmit to a group at a given time.
A station reports nothing back about these, unlike a Message::Downlink.
Transmitted
What became of a frame the station was asked to transmit.
Fields
TimeSync
The clock the two keep between them.
Fields
Other
A message this crate does not read, kept so a caller can see what arrived.
Implementations§
Source§impl Message
impl Message
Sourcepub fn heard(
frame: &[u8],
data_rate: u8,
frequency_hz: u32,
levels: Levels,
) -> Result<Message, ProtocolError>
pub fn heard( frame: &[u8], data_rate: u8, frequency_hz: u32, levels: Levels, ) -> Result<Message, ProtocolError>
Reads a frame the radio heard into the message that reports it.
A station holds no key, so nothing is verified here: the frame is split into the
fields the protocol names and the server judges them. A join request becomes
Message::JoinRequest and a data frame Message::Uplink.
§Arguments
frame- the bytes as they arrived, header through message integrity code.data_rate- the data rate it arrived at.frequency_hz- the frequency it arrived on, in hertz.levels- how it was heard.
§Returns
The message to send up.
§Errors
Returns ProtocolError::Payload when the frame is shorter than the fields its
header names, or carries a kind a station does not send up.
§Examples
use pamoja_gateway::station::{Levels, Message};
use pamoja_lorawan::{Session, Uplink};
// A node's seventh uplink, a reading on port 2, as its radio sent it.
let node = Session::new(0x2601_1BDA, [7; 16], [8; 16]);
let frame = node
.encode_uplink(&Uplink::new(7, 2, b"21.5"))
.expect("an uplink frame");
let heard = Message::heard(frame.as_bytes(), 5, 868_100_000, Levels::default())
.expect("a station sends this one up");
match heard {
Message::Uplink { dev_addr, fcnt, fport, payload, .. } => {
assert_eq!(dev_addr as u32, node.dev_addr());
assert_eq!(fcnt, 7);
assert_eq!(fport, Some(2));
assert_eq!(payload.len(), 4, "still encrypted: a station holds no key");
}
other => panic!("that is a data frame, not {}", other.msgtype()),
}Sourcepub fn from_json(body: &[u8]) -> Result<Message, ProtocolError>
pub fn from_json(body: &[u8]) -> Result<Message, ProtocolError>
Reads a message off the websocket.
A kind this crate does not build is returned as Message::Other rather than
refused, because a station and a server may each speak more than the other does.
§Arguments
body- the message text.
§Returns
What arrived.
§Errors
Returns ProtocolError::Payload when the body is not a JSON object, carries no
message kind, or is missing an identifier the kind it names requires.