// Copyright 2018 Matthias P. Braendli // SPDX-License-Identifier: GPL-2.0-only extern crate libc; extern crate raspi_rfm95_kiss; 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; use std::thread; use std::sync::{Arc, Mutex}; extern { fn kissattach( callsign: * const libc::c_char, speed: libc::int32_t, mtu: libc::int32_t, kttyname: * const libc::c_char, allow_broadcast: libc::int32_t) -> libc::int32_t; } fn create_pts_pair() -> std::io::Result { let master_file = OpenOptions::new() .read(true) .write(true) .open("/dev/ptmx")?; unsafe { let master_fd = master_file.as_raw_fd(); if libc::grantpt(master_fd) == -1 { return Err(std::io::Error::last_os_error()); } if libc::unlockpt(master_fd) == -1 { return Err(std::io::Error::last_os_error()); } } Ok(master_file) } fn main() { eprintln!("Creating PTY pair"); let mut master_file = match create_pts_pair() { Ok(fd) => fd, Err(e) => panic!("create_pts_pair failed: {}", e) }; eprintln!("PTS master: {:?}", master_file); let slavename; unsafe { slavename = libc::ptsname(master_file.as_raw_fd()); } if slavename.is_null() { panic!("Cannot get PTS slave name"); } unsafe { let slice = CStr::from_ptr(slavename); eprintln!("PTS slave: {:?}", slice); } let radio = match RF95::new(Bandwidth::Bw250, CodingRate::Cr8, SpreadingFactor::Sf10) { Ok(mut radio) => { radio.reset().expect("radio reset"); if let Ok(ver) = radio.get_version() { println!("Device version: {:02x}", ver); } 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 = MAX_MTU as i32; let allow_broadcast : i32 = 1; let success = unsafe { kissattach( callsign.as_ptr(), speed, mtu, slavename, allow_broadcast) }; if success == 0 { panic!("kissattach failed"); } 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"); loop { 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(); }