aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 0a562ee8241d4cf5e6324f58a44fc3aed542c910 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// 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<File> {
    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();
}