checkpointing

This commit is contained in:
John Goerzen 2020-09-20 18:18:20 -05:00
parent c7c90a8ff3
commit 869afe3a77
2 changed files with 86 additions and 78 deletions

133
src/xb.rs
View File

@ -27,6 +27,7 @@ use std::thread;
use std::time::{Duration, Instant};
use format_escape_default::format_escape_default;
use std::path::PathBuf;
use bytes::Bytes;
pub fn mkerror(msg: &str) -> Error {
Error::new(ErrorKind::Other, msg)
@ -42,59 +43,14 @@ pub struct ReceivedFrames(pub Vec<u8>, pub Option<(String, String)>);
pub struct XB {
ser: XBSer,
// Lines coming from the radio
readerlinesrx: crossbeam_channel::Receiver<String>,
/// My 64-bit MAC address
mymac: u64,
// Frames going to the app
readeroutput: crossbeam_channel::Sender<ReceivedFrames>,
/// Frames to transmit
writerrx: crossbeam_channel::Receiver<Bytes>,
// Blocks to transmit
txblockstx: crossbeam_channel::Sender<Vec<u8>>,
txblocksrx: crossbeam_channel::Receiver<Vec<u8>>,
// Whether or not to read quality data from the radio
readqual: bool,
// The wait before transmitting. Initialized from
// [`txwait`].
txwait: Duration,
// The transmit prevention timeout. Initialized from
// [`eotwait`].
eotwait: Duration,
// The maximum transmit time.
txslot: Option<Duration>,
// Extra data, to send before the next frame.
extradata: Vec<u8>,
// Maximum packet size
/// Maximum packet size
maxpacketsize: usize,
// Whether or not to always try to cram as much as possible into each TX frame
pack: bool,
// Whether we must delay before transmit. The Instant
// reflects the moment when the delay should end.
txdelay: Option<Instant>,
// When the current TX slot ends, if any.
txslotend: Option<Instant>,
}
/// Reads the lines from the radio and sends them down the channel to
/// the processing bits.
fn readerlinesthread(mut ser: XBSer, tx: crossbeam_channel::Sender<String>) {
loop {
let line = ser.readln().expect("Error reading line");
if let Some(l) = line {
tx.send(l).unwrap();
} else {
debug!("{:?}: EOF", ser.portname);
return;
}
}
}
/// Assert that a given response didn't indicate an EOF, and that it
@ -110,53 +66,74 @@ pub fn assert_response(resp: String, expected: String) -> io::Result<()> {
}
impl XB {
/// Creates a new XB. Returns an instance to be used for sending,
/// as well as a separate receiver to be used in a separate thread to handle
/// incoming frames. The bool specifies whether or not to read the quality
/// parameters after a read.
pub fn new(ser: XBSer) -> (XB, crossbeam_channel::Receiver<ReceivedFrames>) {
/** Creates a new XB. Returns an instance to be used for reading,
as well as a separate sender to be used in a separate thread to handle
outgoing frames. This will spawn a thread to handle the writing to XBee.
If initfile is given, its lines will be sent to the radio, one at a time,
expecting OK after each one, to initialize it.
May panic if an error occurs during initialization.
*/
pub fn new(ser: XBSer, initfile: Option<PathBuf>) -> (XB, crossbeam_channel::Sender<Bytes>) {
// FIXME: make this maximum of 5 configurable
let (writertx, writerrx) = crossbeam_channel::bounded(5);
debug!("Configuring radio");
thread::sleep(Duration::from_msecs(1100));
ser.swrite.lock().unwrap().write_all(b"+++")?;
ser.swrite.lock().unwrap().write_all(b"+++").unwrap();
ser.swrite.lock().unwrap().flush();
assert_response(ser.readln()?, "OK");
assert_response(ser.readln().unwrap(), "OK");
if let Some(file) = initfile {
let f = fs::File::open(file).unwrap();
let reader = BufReader::new(f);
for line in reader.lines() {
if line.len() > 0 {
self.ser.writeln(line).unwrap();
assert_response(ser.readln().unwrap(), "OK")
}
}
}
// Enter API mode
ser.writeln("ATAP 1")?;
assert_response(ser.readln()?, "OK");
ser.writeln("ATAP 1").unwrap();
assert_response(ser.readln().unwrap, "OK");
// Standard API output mode
ser.writeln("ATAO 0")?;
assert_response(ser.readln()?, "OK");
ser.writeln("ATAO 0").unwrap();
assert_response(ser.readln().unwrap(), "OK");
// Get our own MAC address
ser.writeln("ATSH")?;
let serialhigh = ser.readln()?;
ser.writeln("ATSH").unwrap();
let serialhigh = ser.readln().unwrap();
let serialhighu64 = u64::from(u32::from_be_bytes(hex::decode(serialhigh).unwrap()));
ser.writeln("ATSL")?;
let seriallow = ser.readln()?;
ser.writeln("ATSL").unwrap();
let seriallow = ser.readln().unwrap();
let seriallowu64 = u64::from(u32::from_be_bytes(hex::decode(seriallow).unwrap()));
let mymac = serialhighu64 << 32 | seriallowu64;
// Get maximum packet size
ser.writeln("ATNP")?;
let maxpacket = ser.readln()?;
ser.writeln("ATNP").unwrap();
let maxpacket = ser.readln().unwrap();
let maxpacketsize = usize::from(u16::from_be_bytes(hex::decode(maxpacket).unwrap()));
// Exit command mode
ser.writeln("ATCN")?;
assert_response(ser.readln()?, "OK");
ser.writeln("ATCN").unwrap();
assert_response(ser.readln().unwrap(), "OK");
let ser2 = ser.clone();
(XB { readqual, ser, readeroutput, readerlinesrx, txblockstx, txblocksrx, maxpacketsize, pack,
txdelay: None,
txwait: Duration::from_millis(txwait),
eotwait: Duration::from_millis(eotwait),
txslot: if txslot > 0 {
Some(Duration::from_millis(txslot))
} else { None },
txslotend: None,
extradata: vec![]}, readeroutputreader)
(XB {
ser,
mymac,
maxpacketsize,
writerrx,
}, writertx)
}
pub fn mainloop(&mut self) -> io::Result<()> {

View File

@ -95,6 +95,7 @@ impl XBTXRequest {
fullframe.put_u16(lenu16);
fullframe.put_slice(self.innerframe);
fullframe.put_u8(xbchecksum(self.innerframe));
Ok(fullframe.freeze())
} else {
Err(TXGenError::InvalidLen)
}
@ -106,3 +107,33 @@ pub fn xbchecksum(data: &[u8]) -> u8 {
let sumu64 = data.into_iter().map(|x| u64::from(x)).sum();
0xffu8 - (sumu64 as u8)
}
/** Return a 48-bit MAC given the 64-bit MAC. Truncates the most significant bits.
# Example
```
use xbnet::xbpacket::*;
let mac64 = 0x123456789abcdeffu64;
let mac48 = mac64to48(mac64);
assert_eq!([0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff], mac48);
assert_eq(mac64, mac48to64(mac48, mac64));
```
*/
pub fn mac64to48(mac64: u64) -> [u8; 6] {
let macbytes = mac64.to_be_bytes;
macbytes[2..]
}
/** Return a 64-bit MAC given a pattern 64-bit MAC and a 48-bit MAC. The 16 most
significant bits from the pattern will be used to complete the 48-bit MAC to 64-bit.
*/
pub fn mac48to64(mac48: &[u8; 6], pattern64: u64) -> u64 {
let mut mac64bytes = [0u8; 8];
mac64bytes[2..] = mac48;
let mut mac64 = u64::from_be_bytes(mac64bytes);
mac64 |= pattern64 & 0xffff000000000000;
mac64
}