ergot_base/interface_manager/utils/
cobs_stream.rs

1//! Cobs Stream
2//!
3//! The "Cobs Stream" is one flavor of interface sinks. It is intended for serial-like
4//! interfaces that require framing in software.
5
6use bbq2::{prod_cons::stream::StreamProducer, traits::bbqhdl::BbqHandle};
7use postcard::ser_flavors::{self, Flavor};
8use serde::Serialize;
9
10use crate::{
11    AnyAllAppendix, FrameKind, ProtocolError,
12    interface_manager::InterfaceSink,
13    wire_frames::{self, CommonHeader},
14};
15
16pub struct Sink<Q>
17where
18    Q: BbqHandle,
19{
20    pub(crate) mtu: u16,
21    pub(crate) prod: StreamProducer<Q>,
22}
23
24#[allow(clippy::result_unit_err)] // todo
25impl<Q> Sink<Q>
26where
27    Q: BbqHandle,
28{
29    pub fn new_from_handle(q: Q, mtu: u16) -> Self {
30        Self {
31            mtu,
32            prod: q.stream_producer(),
33        }
34    }
35
36    pub const fn new(prod: StreamProducer<Q>, mtu: u16) -> Self {
37        Self { mtu, prod }
38    }
39}
40
41#[allow(clippy::result_unit_err)] // todo
42impl<Q> InterfaceSink for Sink<Q>
43where
44    Q: BbqHandle,
45{
46    fn send_ty<T: Serialize>(
47        &mut self,
48        hdr: &CommonHeader,
49        apdx: Option<&AnyAllAppendix>,
50        body: &T,
51    ) -> Result<(), ()> {
52        let is_err = hdr.kind == FrameKind::PROTOCOL_ERROR;
53
54        if is_err {
55            // todo: use a different interface for this
56            return Err(());
57        }
58
59        let max_len = cobs::max_encoding_length(self.mtu as usize);
60        let mut wgr = self.prod.grant_exact(max_len).map_err(drop)?;
61
62        let ser = ser_flavors::Cobs::try_new(ser_flavors::Slice::new(&mut wgr)).map_err(drop)?;
63        let used = wire_frames::encode_frame_ty(ser, hdr, apdx, body).map_err(drop)?;
64        let len = used.len();
65        wgr.commit(len);
66
67        Ok(())
68    }
69
70    fn send_raw(&mut self, hdr: &CommonHeader, hdr_raw: &[u8], body: &[u8]) -> Result<(), ()> {
71        let is_err = hdr.kind == FrameKind::PROTOCOL_ERROR;
72
73        if is_err {
74            // todo: use a different interface for this
75            return Err(());
76        }
77
78        let max_len = cobs::max_encoding_length(hdr_raw.len() + body.len());
79        let mut wgr = self.prod.grant_exact(max_len).map_err(drop)?;
80
81        let mut ser =
82            ser_flavors::Cobs::try_new(ser_flavors::Slice::new(&mut wgr)).map_err(drop)?;
83        ser.try_extend(hdr_raw).map_err(drop)?;
84        ser.try_extend(body).map_err(drop)?;
85        let fin = ser.finalize().map_err(drop)?;
86        let len = fin.len();
87        wgr.commit(len);
88
89        Ok(())
90    }
91
92    fn send_err(&mut self, hdr: &CommonHeader, err: ProtocolError) -> Result<(), ()> {
93        let is_err = hdr.kind == FrameKind::PROTOCOL_ERROR;
94
95        // note: here it SHOULD be an err!
96        if !is_err {
97            // todo: use a different interface for this
98            return Err(());
99        }
100
101        let max_len = cobs::max_encoding_length(self.mtu as usize);
102        let mut wgr = self.prod.grant_exact(max_len).map_err(drop)?;
103
104        let ser = ser_flavors::Cobs::try_new(ser_flavors::Slice::new(&mut wgr)).map_err(drop)?;
105        let used = wire_frames::encode_frame_err(ser, hdr, err).map_err(drop)?;
106        let len = used.len();
107        wgr.commit(len);
108
109        Ok(())
110    }
111}