]>
code.octet-stream.net Git - m17rt/blob - m17app/src/app.rs
2 use m17core
::kiss
::KissFrame
;
3 use m17core
::protocol
::PacketType
;
4 use m17core
::traits
::{PacketListener
, StreamListener
};
7 use std
::collections
::HashMap
;
8 use std
::io
::{Read
, Write
};
10 use std
::sync
::{Arc
, RwLock
};
13 listeners
: Arc
<RwLock
<Listeners
>>,
14 event_tx
: mpsc
::SyncSender
<TncControlEvent
>,
18 pub fn new
<T
: Tnc
+ Send
+ '
static>(mut tnc
: T
) -> Self {
19 let write_tnc
= tnc
.try_clone().unwrap
();
20 let (event_tx
, event_rx
) = mpsc
::sync_channel(128);
21 let listeners
= Arc
::new(RwLock
::new(Listeners
::new()));
22 spawn_reader(tnc
, listeners
.clone());
23 spawn_writer(write_tnc
, event_rx
);
30 pub fn add_packet_listener
<P
: PacketListener
+ '
static>(&self, listener
: P
) -> usize {
31 let mut listeners
= self.listeners
.write().unwrap
();
32 let id
= listeners
.next
;
34 listeners
.packet
.insert
(id
, Box
::new(listener
));
38 pub fn add_stream_listener
<S
: StreamListener
+ '
static>(&self, listener
: S
) -> usize {
39 let mut listeners
= self.listeners
.write().unwrap
();
40 let id
= listeners
.next
;
42 listeners
.stream
.insert
(id
, Box
::new(listener
));
46 pub fn remove_packet_listener(&self, id
: usize) {
47 self.listeners
.write().unwrap
().packet
.remove(&id
);
50 pub fn remove_stream_listener(&self, id
: usize) {
51 self.listeners
.write().unwrap
().stream
.remove(&id
);
54 pub fn transmit_packet(&self, type_code
: PacketType
, payload
: &[u8]) {
55 // hang on where do we get the LSF details from? We need a destination obviously
56 // our source address needs to be configured here too
57 // also there is possible CAN, encryption, meta payload
59 // we will immediately convert this into a KISS payload before sending into channel so we only need borrow on data
62 // add more methods here for stream outgoing
64 pub fn transmit_stream_start(&self /* lsf?, payload? what needs to be configured ?! */) {}
66 // as long as there is only one TNC it is implied there is only ever one stream transmission in flight
68 pub fn transmit_stream_next(&self, /* next payload, */ end_of_stream
: bool
) {}
71 let _
= self.event_tx
.send(TncControlEvent
::Start
);
75 let _
= self.event_tx
.send(TncControlEvent
::Close
);
79 /// Synchronised structure for listeners subscribing to packets and streams.
81 /// Each listener will be notified in turn of each event.
83 /// Identifier to be assigned to the next listener, starting from 0
85 packet
: HashMap
<usize, Box
<dyn PacketListener
>>,
86 stream
: HashMap
<usize, Box
<dyn StreamListener
>>,
93 packet
: HashMap
::new(),
94 stream
: HashMap
::new(),
99 /// Carries a request from a method on M17App to the TNC's writer thread, which will execute it.
100 enum TncControlEvent
{
106 fn spawn_reader
<T
: Tnc
+ Send
+ '
static>(mut tnc
: T
, listeners
: Arc
<RwLock
<Listeners
>>) {
107 std
::thread
::spawn(move || {
108 let mut buf
= [0u8; 1713];
111 // I want to call tnc.read() here
112 // Probably these needs a helper in m17core::kiss? It will be common to both TNC and host
115 // if this does not start with FEND, forget all data up until first FEND
116 // if we start with a FEND, see if there is another FEND with at least one byte between
117 // for each such case, turn that FEND..=FEND slice into a KissFrame and attempt to parse it
118 // once all such pairs have been handled...
119 // move the last FEND onwards back to the start of the buffer
120 // - if there is no room to do so, this is an oversize frame. purge everything and carry on.
121 // perform next read from end
126 fn spawn_writer
<T
: Tnc
+ Send
+ '
static>(mut tnc
: T
, event_rx
: mpsc
::Receiver
<TncControlEvent
>) {
127 std
::thread
::spawn(move || {
128 while let Ok(ev
) = event_rx
.recv() {
130 TncControlEvent
::Kiss(k
) => {
131 if let Err(e
) = tnc
.write_all(&k
.as_bytes()) {
132 debug
!("kiss send err: {:?}", e
);
136 TncControlEvent
::Start
=> {
137 if let Err(e
) = tnc
.start() {
138 debug
!("tnc start err: {:?}", e
);
142 TncControlEvent
::Close
=> {
143 if let Err(e
) = tnc
.close() {
144 debug
!("tnc close err: {:?}", e
);