aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2018-09-04 09:20:59 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2018-09-04 09:20:59 +0200
commit359a6ebaf59aa19699cbd61b07406999e6732373 (patch)
treed758f8dad49094ac6a7aa15dd0e817b2cf3c1cc5
parent4c9f3c8dbfc67d9e1f8479538ba9c9b6dc3be5c4 (diff)
downloadraspi-rfm95-kiss-master.tar.gz
raspi-rfm95-kiss-master.tar.bz2
raspi-rfm95-kiss-master.zip
Rework rfm95 and kissHEADmaster
-rw-r--r--src/kiss.rs23
-rw-r--r--src/lib.rs2
-rw-r--r--src/main.rs70
-rw-r--r--src/rfm95.rs412
4 files changed, 271 insertions, 236 deletions
diff --git a/src/kiss.rs b/src/kiss.rs
index 397922d..e9f4703 100644
--- a/src/kiss.rs
+++ b/src/kiss.rs
@@ -1,7 +1,6 @@
// Taken from ax25-rs, which is
// SPDX-License-Identifier: Apache-2.0
use std::io;
-use std::io::prelude::*;
use std::io::{Read, Write};
const FEND: u8 = 0xC0;
@@ -10,12 +9,12 @@ const TFEND: u8 = 0xDC;
const TFESC: u8 = 0xDD;
pub struct KissDecoder<'a> {
- stream: &'a Read,
+ stream: &'a mut Read,
buffer: Vec<u8>
}
impl<'a> KissDecoder<'a> {
- pub fn new<T>(stream: &T) -> io::Result<KissDecoder>
+ pub fn new<T>(stream: &'a mut T) -> io::Result<KissDecoder>
where T: Read
{
Ok(KissDecoder {
@@ -36,22 +35,21 @@ impl<'a> KissDecoder<'a> {
}
}
-/*
-pub struct KissEncoder {
- stream: Write,
- buffer: Vec<u8>
+pub struct KissEncoder<'a> {
+ stream: &'a mut Write,
}
-impl KissEncoder {
- pub fn new(stream: Write) -> io::Result<KissEncoder> {
+impl<'a> KissEncoder<'a> {
+ pub fn new<T>(stream: &'a mut T) -> io::Result<KissEncoder>
+ where T: Write
+ {
Ok(KissEncoder {
stream: stream,
- buffer: Vec::new()
})
}
pub fn send_frame(&mut self, frame: &[u8]) -> io::Result<()> {
- // 0x00 is the KISS command byte, which is two nybbles
+ // 0x00 is the KISS command byte, which is two nibbles
// port = 0
// command = 0 (all following bytes are a data frame to transmit)
self.stream.write(&[FEND, 0x00])?;
@@ -72,7 +70,7 @@ fn make_frame_from_buffer(buffer: &mut Vec<u8>) -> Option<Vec<u8>> {
}
let mut state = Scan::LookingForStartMarker;
let mut final_idx = 0;
-
+
// Check for possible frame read-only until we know we have a complete frame
// If we take one out, clear out buffer up to the final index
for (idx, &c) in buffer.iter().enumerate() {
@@ -180,4 +178,3 @@ fn test_two_frames_double_fend() {
assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x03, 0x04]));
assert_eq!(rx, vec![FEND]);
}
-*/
diff --git a/src/lib.rs b/src/lib.rs
index 980eac2..15e4720 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,4 +4,4 @@ extern crate spidev;
extern crate sysfs_gpio;
pub mod rfm95;
-//pub mod kiss;
+pub mod kiss;
diff --git a/src/main.rs b/src/main.rs
index 134ee11..0a562ee 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,12 +3,13 @@
extern crate libc;
extern crate raspi_rfm95_kiss;
-use raspi_rfm95_kiss::rfm95::{RF95, Bandwidth, CodingRate, SpreadingFactor};
+use raspi_rfm95_kiss::rfm95::{RF95EventType, RF95, Bandwidth, CodingRate, SpreadingFactor, MAX_MTU};
+use raspi_rfm95_kiss::kiss::{KissDecoder, KissEncoder};
use std::fs::{OpenOptions, File};
use std::ffi::{CStr, CString};
use std::os::unix::io::AsRawFd;
-
-const MAX_MTU: usize = 251;
+use std::thread;
+use std::sync::{Arc, Mutex};
extern {
fn kissattach(
@@ -41,7 +42,7 @@ fn create_pts_pair() -> std::io::Result<File> {
fn main() {
eprintln!("Creating PTY pair");
- let master_file = match create_pts_pair() {
+ let mut master_file = match create_pts_pair() {
Ok(fd) => fd,
Err(e) => panic!("create_pts_pair failed: {}", e)
};
@@ -61,7 +62,7 @@ fn main() {
eprintln!("PTS slave: {:?}", slice);
}
- match RF95::new(Bandwidth::Bw250, CodingRate::Cr8, SpreadingFactor::Sf10) {
+ let radio = match RF95::new(Bandwidth::Bw250, CodingRate::Cr8, SpreadingFactor::Sf10) {
Ok(mut radio) => {
radio.reset().expect("radio reset");
@@ -71,13 +72,14 @@ fn main() {
else {
eprintln!("Cannot read device version");
}
+ radio
},
Err(e) => panic!("Cannot create lora radio object, {}", e)
};
let callsign = CString::new("HB9EGM-1").expect("Failed to convert callsign to CString");
let speed : i32 = 9600;
- let mtu : i32 = 251;
+ let mtu = MAX_MTU as i32;
let allow_broadcast : i32 = 1;
let success = unsafe {
@@ -93,21 +95,57 @@ fn main() {
panic!("kissattach failed");
}
- let todo = "Read/Write from/to TTY and RFM95";
- /*
- let master_tty = Box::new(master_file);
+ let radio = Arc::new(Mutex::new(radio));
+
+ let mut pty_tx_side = master_file.try_clone()
+ .expect("Cannot clone PTY file");
+
+ let radio_tx = radio.clone();
+
+ let writer = thread::spawn(move || {
+ let mut kiss_decoder = KissDecoder::new(&mut pty_tx_side)
+ .expect("KissDecoder creation failed");
- let writer = thread::spawn(|| {
loop {
- let mut buffer = [0; MAX_MTU];
- match *master_tty.read(&mut buffer[..]) {
- Ok(n) => radio.write_buffer(buffer),
- Err(e) => panic!("TTY Read error {}", e);
- }
+ let frame_to_tx = match kiss_decoder.receive_frame() {
+ Ok(f) => f,
+ Err(e) => {
+ println!("Error decoding KISS: {}", e);
+ continue
+ }
+ };
+
+ radio_tx.lock().unwrap().send(frame_to_tx)
+ .expect("Failed to send frame");
}
});
+ let mut kiss_encoder = KissEncoder::new(&mut master_file)
+ .expect("KissEncoder creation failed");
+
+ loop {
+ let timeout = std::time::Duration::from_millis(100);
+ match radio.lock().unwrap().wait_for_event(timeout) {
+ Ok(msg) => match msg {
+ RF95EventType::None => println!("radio: None"),
+ RF95EventType::DataReceived(buf) => {
+ println!("radio: Data received {:?}", buf);
+
+ kiss_encoder.send_frame(buf.as_slice()).expect("Failed to encode frame");
+ },
+ RF95EventType::DataSent => println!("radio: Data sent"),
+ RF95EventType::ErrorPinConfig => println!("radio: Error pin config"),
+ RF95EventType::ErrorTimedOut => println!("radio: Timeout"),
+ RF95EventType::ErrorWrongCrc => println!("radio: Wrong CRC"),
+ RF95EventType::ErrorCommBus => println!("radio: Comm Bus"),
+ },
+ Err(e) => {
+ println!("Receiver channel closing: {}", e);
+ break;
+ },
+ }
+ }
+
writer.join().unwrap();
- */
}
diff --git a/src/rfm95.rs b/src/rfm95.rs
index 2922652..a73191b 100644
--- a/src/rfm95.rs
+++ b/src/rfm95.rs
@@ -1,21 +1,19 @@
// Taken from rfm95_rust_pi, which is
// SPDX-License-Identifier: MIT
use std;
-use sysfs_gpio;
use sysfs_gpio::{Direction, Edge, Pin};
use spidev::{Spidev, SpidevTransfer, SpidevOptions, SPI_MODE_0};
use std::io;
use std::thread;
use std::time::Duration;
use std::io::{Read, Write, ErrorKind};
-use std::sync::mpsc::{Receiver};
-use std::sync::mpsc;
-use std::sync::atomic::{AtomicBool, Ordering};
const RST_BCM_PIN : u64 = 22;
const DIO_BCM_PIN : u64 = 25;
const CS_BCM_PIN : u64 = 8;
+pub const MAX_MTU: usize = 251;
+
const SPI_MAX_SPEED_HZ : u32 = 5_000_000;
#[derive(Copy, Clone)]
@@ -286,7 +284,7 @@ impl ToFlag for u8 {
pub enum RF95EventType {
None,
- DataReceived,
+ DataReceived(Vec<u8>),
DataSent,
ErrorPinConfig,
ErrorTimedOut,
@@ -302,39 +300,75 @@ pub struct RF95 {
crc_check_enabled : bool,
implicit_header_enabled : bool,
pwr_db : u8,
- thread_run : std::sync::Arc<AtomicBool>,
- thread_handle : Option<std::thread::JoinHandle<()>>,
rst_pin : Pin,
+ cs_pin : Pin,
+ dio_pin : Pin,
+ spi : Spidev,
}
impl RF95 {
pub fn new(bw : Bandwidth, cr : CodingRate, sf : SpreadingFactor) -> io::Result<RF95> {
let tmp_rst_pin = Pin::new(RST_BCM_PIN);
- tmp_rst_pin.export().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot export pin {}", e)))?;
- tmp_rst_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ tmp_rst_pin.export().map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot export pin {}", e)))?;
+ tmp_rst_pin.set_direction(Direction::Low)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
thread::sleep(Duration::from_millis(2));
- tmp_rst_pin.set_value(1).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
+ tmp_rst_pin.set_value(1).map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
thread::sleep(Duration::from_millis(5));
- Ok(
- RF95 {
- ch : Channel::Ch10,
- bw,
- cr,
- sf,
- crc_check_enabled : false,
- implicit_header_enabled : false,
- pwr_db : 0,
- thread_run : std::sync::Arc::new(AtomicBool::new(false)),
- thread_handle : None,
- rst_pin : tmp_rst_pin,
- }
- )
+ let mut spi = Spidev::open("/dev/spidev0.0")?;
+ let spi_options = SpidevOptions::new()
+ .bits_per_word(8)
+ .max_speed_hz(SPI_MAX_SPEED_HZ)
+ .mode(SPI_MODE_0)
+ .build();
+ spi.configure(&spi_options)?;
+
+ let dio_pin = Pin::new(DIO_BCM_PIN);
+ dio_pin.export()
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot export pin {}", e)))?;
+ dio_pin.set_direction(Direction::In)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ dio_pin.set_edge(Edge::RisingEdge)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set edge for pin {}", e)))?;
+
+
+ let cs_pin = Pin::new(CS_BCM_PIN);
+ cs_pin.export()
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot export pin {}", e)))?;
+
+ let mut rf = RF95 {
+ ch : Channel::Ch10,
+ bw,
+ cr,
+ sf,
+ crc_check_enabled : false,
+ implicit_header_enabled : false,
+ pwr_db : 0,
+ rst_pin : tmp_rst_pin,
+ cs_pin : cs_pin,
+ dio_pin : dio_pin,
+ spi : spi,
+ };
+
+ let ver = rf.get_version()?;
+
+ if ver == 0 || ver == 0xff {
+ return Err(io::Error::new(ErrorKind::Other,
+ format!("Invalid chip version {}", ver)));
+ }
+
+ // We configure so that we can use the entire 256 byte FIFO for either
+ // receive or transmit, but not both at the same time.
+ rf.write_register(LoraRegister::RegFifoRxBaseAddr, 0)?;
+ rf.write_register(LoraRegister::RegFifoTxBaseAddr, 0)?;
+
+ Ok(rf)
}
pub fn get_version(&mut self) -> io::Result<u8> {
- let device_version = RF95::read_register(LoraRegister::RegVersion)?;
+ let device_version = self.read_register(LoraRegister::RegVersion)?;
Ok(device_version)
}
@@ -352,59 +386,59 @@ impl RF95 {
pub fn set_channel(&mut self, ch : Channel) -> io::Result<()> {
self.set_mode(LoraMode::Sleep)?;
self.ch = ch;
- RF95::write_register(LoraRegister::RegFrfMsb, ch.msb())?;
- RF95::write_register(LoraRegister::RegFrfMid, ch.mid())?;
- RF95::write_register(LoraRegister::RegFrfLsb, ch.lsb())
+ self.write_register(LoraRegister::RegFrfMsb, ch.msb())?;
+ self.write_register(LoraRegister::RegFrfMid, ch.mid())?;
+ self.write_register(LoraRegister::RegFrfLsb, ch.lsb())
}
pub fn set_spreading_factor(&mut self, sf : SpreadingFactor) -> io::Result<()> {
self.set_mode(LoraMode::Sleep)?;
self.sf = sf;
- let mut tmp = RF95::read_register(LoraRegister::RegModemConfig2)?;
+ let mut tmp = self.read_register(LoraRegister::RegModemConfig2)?;
tmp &= 0x0F;
tmp |= sf.as_u8() << 4;
- RF95::write_register(LoraRegister::RegModemConfig2, tmp)
+ self.write_register(LoraRegister::RegModemConfig2, tmp)
}
pub fn set_bandwidth(&mut self, bw : Bandwidth) -> io::Result<()> {
self.set_mode(LoraMode::Sleep)?;
self.bw = bw;
- let mut tmp = RF95::read_register(LoraRegister::RegModemConfig1)?;
+ let mut tmp = self.read_register(LoraRegister::RegModemConfig1)?;
tmp &= 0x0F;
tmp |= bw.as_u8() << 4;
- RF95::write_register(LoraRegister::RegModemConfig1, tmp)?;
+ self.write_register(LoraRegister::RegModemConfig1, tmp)?;
Ok(())
}
pub fn set_coding_rate(&mut self, cr : CodingRate) -> io::Result<()> {
self.set_mode(LoraMode::Sleep)?;
self.cr = cr;
- let mut tmp = RF95::read_register(LoraRegister::RegModemConfig1)?;
+ let mut tmp = self.read_register(LoraRegister::RegModemConfig1)?;
tmp &= 0xF1;
tmp |= cr.as_u8() << 1;
- RF95::write_register(LoraRegister::RegModemConfig1, tmp)
+ self.write_register(LoraRegister::RegModemConfig1, tmp)
}
pub fn enable_crc_check(&mut self, en : bool) -> io::Result<()> {
- let mut tmp = RF95::read_register(LoraRegister::RegModemConfig2)?;
+ let mut tmp = self.read_register(LoraRegister::RegModemConfig2)?;
if en {
tmp |= 1 << 2;
} else {
tmp &= !(1 << 2);
}
self.crc_check_enabled = en;
- RF95::write_register(LoraRegister::RegModemConfig2, tmp)
+ self.write_register(LoraRegister::RegModemConfig2, tmp)
}
pub fn enable_implicit_header(&mut self, en : bool) -> io::Result<()> {
- let mut tmp = RF95::read_register(LoraRegister::RegModemConfig1)?;
+ let mut tmp = self.read_register(LoraRegister::RegModemConfig1)?;
if en {
tmp |= 0x01;
} else {
tmp &= !0x01;
}
self.implicit_header_enabled = en;
- RF95::write_register(LoraRegister::RegModemConfig1, tmp)
+ self.write_register(LoraRegister::RegModemConfig1, tmp)
}
pub fn set_output_power(&mut self, pwr : u8) -> io::Result<()> {
@@ -414,241 +448,207 @@ impl RF95 {
}
self.pwr_db = pwr;
let out = (pwr - 2) & 0x0F;
- let mut tmp = RF95::read_register(LoraRegister::RegPaConfig)?;
+ let mut tmp = self.read_register(LoraRegister::RegPaConfig)?;
tmp |= 0x80;
tmp &= 0xF0;
tmp |= out & 0x0F;
- RF95::write_register(LoraRegister::RegPaConfig, tmp)
+ self.write_register(LoraRegister::RegPaConfig, tmp)
}
pub fn set_mode(&mut self, m : LoraMode) -> io::Result<()> {
- RF95::write_register(LoraRegister::RegOpMode, m.as_u8())
+ self.write_register(LoraRegister::RegOpMode, m.as_u8())
}
- pub fn listen_timed(&mut self, timeout : u32) -> io::Result<Receiver<RF95EventType>> {
- let (sender, receiver) = mpsc::channel();
- let input = Pin::new(DIO_BCM_PIN);
+ fn check_pending_events(&mut self) -> io::Result<Option<RF95EventType>> {
+ // TODO atomic read and clear of bits!
+ let mut regv = self.read_register(LoraRegister::RegIrqFlags)?;
+ if regv.flag_enabled(IrqFlagMasks::CadDetected) {
+ regv = regv & !IrqFlagMasks::CadDetected.as_u8();
+ }
+ if regv.flag_enabled(IrqFlagMasks::CadDone) {
+ regv = regv & !IrqFlagMasks::CadDone.as_u8();
+ }
+ if regv.flag_enabled(IrqFlagMasks::FhssChangeChannel) {
+ regv = regv & !IrqFlagMasks::FhssChangeChannel.as_u8();
+ }
+ if regv.flag_enabled(IrqFlagMasks::PayloadCrcError) {
+ regv = regv & !IrqFlagMasks::PayloadCrcError.as_u8();
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ return Ok(Some(RF95EventType::ErrorWrongCrc));
+ }
+ if regv.flag_enabled(IrqFlagMasks::RxDone) {
+ let len = self.read_register(LoraRegister::RegRxNbBytes)?;
- self.thread_run.store(true, Ordering::SeqCst);
- let run = self.thread_run.clone();
+ let curr_addr = self.read_register(LoraRegister::RegFifoRxCurrentAddr)?;
+ self.write_register(LoraRegister::RegFifoAddrPtr, curr_addr)?;
- self.thread_handle = Some(thread::spawn(move || {
- input.with_exported(|| {
- let timeout = std::time::Duration::from_secs(timeout as u64);
- let start = std::time::Instant::now();
- match input.set_direction(Direction::In) {
- Ok(_) => (),
- Err(e) => {
- sender.send(RF95EventType::ErrorPinConfig).unwrap();
- panic!("Error while setting DI0 pin direction : {:?}", e);
- },
- };
+ let mut buf = Vec::new();
- match input.set_edge(Edge::RisingEdge) {
- Ok(_) => (),
- Err(e) => {
- sender.send(RF95EventType::ErrorPinConfig).unwrap();
- panic!("Error while setting DI0 pin edge detection : {:?}", e);
- }
- };
+ self.read_buffer(LoraRegister::RegFifo, &mut buf, len)?;
+ regv = regv & !IrqFlagMasks::RxDone.as_u8();
- let mut poller = match input.get_poller() {
- Ok(p) => p,
- Err(e) => {
- sender.send(RF95EventType::ErrorPinConfig).unwrap();
- panic!("Error while creating poller on DI0 : {:?}", e);
- }
- };
-
- while run.load(Ordering::SeqCst) {
- match poller.poll(10).unwrap() {
- Some(_) => {
- let mut regv = match RF95::read_register(LoraRegister::RegIrqFlags) {
- Ok(r) => r,
- Err(_) => {
- sender.send(RF95EventType::ErrorCommBus).unwrap();
- return Err(sysfs_gpio::Error::from(io::Error::new(io::ErrorKind::Other, format!("Reading irq flag register"))));
- },
- };
- if regv.flag_enabled(IrqFlagMasks::CadDetected) {
- regv = regv & !IrqFlagMasks::CadDetected.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::CadDone) {
- regv = regv & !IrqFlagMasks::CadDone.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::FhssChangeChannel) {
- regv = regv & !IrqFlagMasks::FhssChangeChannel.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::PayloadCrcError) {
- sender.send(RF95EventType::ErrorWrongCrc).unwrap();
- regv = regv & !IrqFlagMasks::PayloadCrcError.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::RxDone) {
- sender.send(RF95EventType::DataSent).unwrap();
- regv = regv & !IrqFlagMasks::RxDone.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::TxDone) {
- sender.send(RF95EventType::DataReceived).unwrap();
- regv = regv & !IrqFlagMasks::TxDone.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::RxTimeout) {
- sender.send(RF95EventType::ErrorTimedOut).unwrap();
- regv = regv & !IrqFlagMasks::RxTimeout.as_u8();
- }
- if regv.flag_enabled(IrqFlagMasks::ValidHeader) {
- regv = regv & !IrqFlagMasks::ValidHeader.as_u8();
- }
- match RF95::write_register(LoraRegister::RegIrqFlags, regv) {
- Ok(_) => (),
- Err(_) => {
- sender.send(RF95EventType::ErrorCommBus).unwrap();
- return Err(sysfs_gpio::Error::from(io::Error::new(io::ErrorKind::Other, format!("Reading irq flag register"))));
- },
- };
- },
- None => (),
- };
- if timeout.as_secs() > 0 {
- if std::time::Instant::now().duration_since(start) > timeout {
- break;
- }
- }
- }
- Ok(())
- }).expect("Cannot export gpio");
- }));
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ return Ok(Some(RF95EventType::DataReceived(buf)));
+ }
+ if regv.flag_enabled(IrqFlagMasks::TxDone) {
+ regv = regv & !IrqFlagMasks::TxDone.as_u8();
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ return Ok(Some(RF95EventType::DataSent));
+ }
- Ok(receiver)
- }
+ if regv.flag_enabled(IrqFlagMasks::RxTimeout) {
+ regv = regv & !IrqFlagMasks::RxTimeout.as_u8();
- pub fn listen_continuous(&mut self) -> io::Result<Receiver<RF95EventType>> {
- self.listen_timed(0)
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ return Ok(Some(RF95EventType::ErrorTimedOut));
+ }
+
+ if regv.flag_enabled(IrqFlagMasks::ValidHeader) {
+ regv = regv & !IrqFlagMasks::ValidHeader.as_u8();
+ }
+
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ Ok(None)
}
- pub fn stop_listening(&mut self) -> Result<(), String> {
- self.thread_run.store(false, Ordering::SeqCst);
- match self.thread_handle.take() {
- Some(th) => {
- match th.join() {
- Ok(_) => return Ok(()),
- Err(_) => return Err(format!("Cannot join spawned thread")),
- };
- },
- None => return Err(format!("No thread spawned")),
- };
+ pub fn wait_for_event(&mut self, timeout : std::time::Duration) -> io::Result<RF95EventType> {
+ let start = std::time::Instant::now();
+ let mut poller = self.dio_pin.get_poller()
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot get poller for pin {}", e)))?;
+
+ loop {
+ match poller.poll(10).unwrap() {
+ Some(_) => {
+ if let Some(ev) = self.check_pending_events()? {
+ return Ok(ev);
+ }
+ }
+ None => (),
+ };
+
+ if timeout.as_secs() > 0 && std::time::Instant::now().duration_since(start) > timeout {
+ break;
+ }
+ }
+ Ok(RF95EventType::ErrorTimedOut)
}
pub fn get_snr(&mut self) -> io::Result<i16> {
- Ok((RF95::read_register(LoraRegister::RegPktSnrValue)? as i16) / 4)
+ Ok((self.read_register(LoraRegister::RegPktSnrValue)? as i16) / 4)
}
pub fn get_packet_rssi(&mut self) -> io::Result<i16> {
- Ok((RF95::read_register(LoraRegister::RegRssiValue)? as i16) - 137)
+ Ok((self.read_register(LoraRegister::RegRssiValue)? as i16) - 137)
}
pub fn get_rssi(&mut self) -> io::Result<i16> {
- Ok((RF95::read_register(LoraRegister::RegRssiValue)? as i16) - 137)
+ Ok((self.read_register(LoraRegister::RegRssiValue)? as i16) - 137)
}
pub fn reset(&mut self) -> io::Result<()> {
- self.rst_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ self.rst_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
thread::sleep(Duration::from_millis(2));
- self.rst_pin.set_value(1).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
+ self.rst_pin.set_value(1).map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
thread::sleep(Duration::from_millis(5));
Ok(())
}
pub fn set_dio_mapping(&mut self, df : DioFunction) -> io::Result<()> {
- let prev_mode = RF95::read_register(LoraRegister::RegOpMode)?;
+ let prev_mode = self.read_register(LoraRegister::RegOpMode)?;
self.set_mode(LoraMode::StandbyOokFsk)?;
- let mut tmp = RF95::read_register(LoraRegister::RegDioMapping1)?;
+ let mut tmp = self.read_register(LoraRegister::RegDioMapping1)?;
tmp &= 0x3F;
if df.as_u8() == DioFunction::TxDone.as_u8() {
tmp |= 0x40;
}
- RF95::write_register(LoraRegister::RegDioMapping1, tmp)?;
- RF95::write_register(LoraRegister::RegOpMode, prev_mode)
+ self.write_register(LoraRegister::RegDioMapping1, tmp)?;
+ self.write_register(LoraRegister::RegOpMode, prev_mode)
}
- fn write_register(reg : LoraRegister, data : u8) -> io::Result<()> {
- let mut spi = Spidev::open("/dev/spidev0.0")?;
- let spi_options = SpidevOptions::new()
- .bits_per_word(8)
- .max_speed_hz(SPI_MAX_SPEED_HZ)
- .mode(SPI_MODE_0)
- .build();
- spi.configure(&spi_options)?;
+ fn write_register(&mut self, reg : LoraRegister, data : u8) -> io::Result<()> {
+ self.cs_pin.set_direction(Direction::Low)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
- match spi.write(&[reg.as_u8(), data]) {
- Ok(_) => Ok(()),
- Err(_) => Err(io::Error::new(ErrorKind::Other, "Problem while writing to device"))
- }
+ self.spi.write(&[reg.as_u8(), data])?;
+
+ self.cs_pin.set_value(1)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))
}
- fn write_buffer(reg : LoraRegister, buffer : Vec<u8>) -> io::Result<()> {
- let mut spi = Spidev::open("/dev/spidev0.0")?;
- let spi_options = SpidevOptions::new()
- .bits_per_word(8)
- .max_speed_hz(SPI_MAX_SPEED_HZ)
- .mode(SPI_MODE_0)
- .build();
- spi.configure(&spi_options)?;
+ pub fn send(&mut self, buffer : Vec<u8>) -> io::Result<()> {
+ if buffer.len() > MAX_MTU {
+ return Err(io::Error::new(ErrorKind::Other, "Message larger than MTU"));
+ }
+
+ // TODO waitpacketsent
+ self.set_mode(LoraMode::Standby)?;
+
+ // TODO waitCAD
+
+ self.write_register(LoraRegister::RegFifoAddrPtr, 0)?;
+ // TODO RadioHead header?
+ let len = buffer.len() as u8;
+ self.write_buffer(LoraRegister::RegFifo, buffer)?;
+ self.write_register(LoraRegister::RegPayloadLength, len)?;
+ self.set_mode(LoraMode::Tx)?;
+
+ // Wait for TX to complete
+ loop {
+ // TODO protect IRQ clearing against concurrent access
+ let mut regv = self.read_register(LoraRegister::RegIrqFlags)?;
+ if regv.flag_enabled(IrqFlagMasks::TxDone) {
+ regv = regv & !IrqFlagMasks::TxDone.as_u8();
+ self.write_register(LoraRegister::RegIrqFlags, regv)?;
+ break;
+ }
+
+ thread::sleep(Duration::from_millis(2));
+ }
+ Ok(())
+ }
- let cs_pin = Pin::new(CS_BCM_PIN);
- cs_pin.export().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot export pin {}", e)))?;
- cs_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ fn write_buffer(&mut self, reg : LoraRegister, buffer : Vec<u8>) -> io::Result<()> {
+ self.cs_pin.set_direction(Direction::Low)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
let mut v2 = buffer;
v2.insert(0, reg.as_u8());
- spi.write(&v2)?;
- cs_pin.set_value(1).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set value for pin {}", e)))
+ self.spi.write(&v2)?;
+ self.cs_pin.set_value(1)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))
}
- fn read_register(reg : LoraRegister) -> io::Result<u8> {
- let mut spi = Spidev::open("/dev/spidev0.0")?;
- let spi_options = SpidevOptions::new()
- .bits_per_word(8)
- .max_speed_hz(SPI_MAX_SPEED_HZ)
- .mode(SPI_MODE_0)
- .build();
- spi.configure(&spi_options)?;
-
- let cs_pin = Pin::new(CS_BCM_PIN);
- cs_pin.export().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot export pin {}", e)))?;
- cs_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ fn read_register(&mut self, reg : LoraRegister) -> io::Result<u8> {
+ self.cs_pin.set_direction(Direction::Low)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
let mut rx_buf = [0; 2];
let tx_buf = vec![reg as u8, 0];
{
let mut transfer = SpidevTransfer::read_write(&tx_buf, &mut rx_buf);
- spi.transfer(&mut transfer).unwrap();
+ self.spi.transfer(&mut transfer).unwrap();
}
- cs_pin.set_value(1).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
+ self.cs_pin.set_value(1)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
+
Ok(rx_buf[1])
}
- fn read_buffer(reg : LoraRegister, buffer : &mut Vec<u8>, length : u8) -> io::Result<()> {
- let mut spi = Spidev::open("/dev/spidev0.0")?;
- let spi_options = SpidevOptions::new()
- .bits_per_word(8)
- .max_speed_hz(SPI_MAX_SPEED_HZ)
- .mode(SPI_MODE_0)
- .build();
- spi.configure(&spi_options)?;
+ fn read_buffer(&mut self, reg : LoraRegister, buffer : &mut Vec<u8>, length : u8) -> io::Result<()> {
- let cs_pin = Pin::new(CS_BCM_PIN);
- cs_pin.export().map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot export pin {}", e)))?;
- cs_pin.set_direction(Direction::Low).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
+ self.cs_pin.set_direction(Direction::Low)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set direction for pin {}", e)))?;
let mut tmp : Vec<u8> = Vec::with_capacity(length as usize);
- spi.write(&[reg.as_u8()])?;
- spi.read(tmp.as_mut_slice())?;
+ self.spi.write(&[reg.as_u8()])?;
+ self.spi.read(tmp.as_mut_slice())?;
buffer.clear();
buffer.write(&tmp)?;
- cs_pin.set_value(1).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
+ self.cs_pin.set_value(1)
+ .map_err(|e| io::Error::new(ErrorKind::Other, format!("Cannot set value for pin {}", e)))?;
Ok(())
}
}