From 359a6ebaf59aa19699cbd61b07406999e6732373 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Tue, 4 Sep 2018 09:20:59 +0200 Subject: Rework rfm95 and kiss --- src/kiss.rs | 23 ++-- src/lib.rs | 2 +- src/main.rs | 70 +++++++--- src/rfm95.rs | 412 +++++++++++++++++++++++++++++------------------------------ 4 files changed, 271 insertions(+), 236 deletions(-) (limited to 'src') 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 } impl<'a> KissDecoder<'a> { - pub fn new(stream: &T) -> io::Result + pub fn new(stream: &'a mut T) -> io::Result where T: Read { Ok(KissDecoder { @@ -36,22 +35,21 @@ impl<'a> KissDecoder<'a> { } } -/* -pub struct KissEncoder { - stream: Write, - buffer: Vec +pub struct KissEncoder<'a> { + stream: &'a mut Write, } -impl KissEncoder { - pub fn new(stream: Write) -> io::Result { +impl<'a> KissEncoder<'a> { + pub fn new(stream: &'a mut T) -> io::Result + 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) -> Option> { } 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 { 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), 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, - thread_handle : Option>, rst_pin : Pin, + cs_pin : Pin, + dio_pin : Pin, + spi : Spidev, } impl RF95 { pub fn new(bw : Bandwidth, cr : CodingRate, sf : SpreadingFactor) -> io::Result { 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 { - 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> { - let (sender, receiver) = mpsc::channel(); - let input = Pin::new(DIO_BCM_PIN); + fn check_pending_events(&mut self) -> io::Result> { + // 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> { - 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 { + 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 { - 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 { - 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 { - 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) -> 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) -> 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) -> 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 { - 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 { + 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, 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, 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 = 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(()) } } -- cgit v1.2.3