1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4
5pub mod messages;
6
7use crate::messages::{LinkStatisticsPayload, RcChannelsPayload};
8use crsf::{LinkStatistics, Packet, PacketAddress, PacketParser, RcChannels};
9use cu29::cubridge::{
10 BridgeChannel, BridgeChannelConfig, BridgeChannelInfo, BridgeChannelSet, CuBridge,
11};
12use cu29::prelude::*;
13use cu29::resources;
14use embedded_io::{Read, Write};
15
16const READ_BUFFER_SIZE: usize = 1024;
17const PARSER_BUFFER_SIZE: usize = 1024;
18
19rx_channels! {
20 lq_rx => LinkStatisticsPayload,
21 rc_rx => RcChannelsPayload
22 }
24
25tx_channels! {
26 lq_tx => LinkStatisticsPayload,
27 rc_tx => RcChannelsPayload
28}
29
30resources!(for<S, E> where S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static {
31 serial => Owned<S>,
32});
33
34#[derive(Reflect)]
36#[reflect(from_reflect = false, no_field_bounds, type_path = false)]
37pub struct CrsfBridge<S, E>
38where
39 S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static,
40 E: 'static,
41{
42 #[reflect(ignore)]
43 serial_port: S,
44 #[reflect(ignore)]
45 parser: PacketParser<PARSER_BUFFER_SIZE>,
46 #[reflect(ignore)]
47 last_lq: Option<LinkStatistics>,
48 #[reflect(ignore)]
49 last_rc: Option<RcChannels>,
50}
51
52impl<S, E> CrsfBridge<S, E>
53where
54 S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static,
55 E: 'static,
56{
57 fn from_serial(serial_port: S) -> Self {
58 Self {
59 serial_port,
60 parser: PacketParser::<PARSER_BUFFER_SIZE>::new(),
61 last_lq: None,
62 last_rc: None,
63 }
64 }
65
66 fn write_packet(&mut self, packet: Packet) -> CuResult<()> {
67 let raw_packet = packet.into_raw(PacketAddress::Transmitter);
68 self.serial_port
69 .write_all(raw_packet.data())
70 .map_err(|_| CuError::from("CRSF: Serial port write error"))
71 }
72
73 fn update(&mut self) -> CuResult<()> {
75 let mut buf = [0; READ_BUFFER_SIZE];
76 match self.serial_port.read(buf.as_mut_slice()) {
77 Ok(n) => {
78 if n > 0 {
79 self.parser.push_bytes(&buf[..n]);
80 while let Some(Ok((_, packet))) = self.parser.next_packet() {
81 match packet {
82 Packet::LinkStatistics(link_statistics) => {
83 debug!(
84 "LinkStatistics: Download LQ:{}",
85 link_statistics.downlink_link_quality
86 );
87 self.last_lq = Some(link_statistics);
88 }
89 Packet::RcChannels(channels) => {
90 self.last_rc = Some(channels);
91 for (i, value) in self.last_rc.iter().enumerate() {
92 debug!("RC Channel {}: {}", i, value.as_ref());
93 }
94 }
95 _ => {
96 info!("CRSF: Received other packet");
97 }
98 }
99 }
100 }
101 }
102 _ => {
103 error!("CRSF: Serial port read error");
104 }
105 }
106 Ok(())
107 }
108}
109
110impl<S, E> cu29::reflect::TypePath for CrsfBridge<S, E>
111where
112 S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static,
113 E: 'static,
114{
115 fn type_path() -> &'static str {
116 "cu_crsf::CrsfBridge"
117 }
118
119 fn short_type_path() -> &'static str {
120 "CrsfBridge"
121 }
122
123 fn type_ident() -> Option<&'static str> {
124 Some("CrsfBridge")
125 }
126
127 fn crate_name() -> Option<&'static str> {
128 Some("cu_crsf")
129 }
130
131 fn module_path() -> Option<&'static str> {
132 Some("cu_crsf")
133 }
134}
135
136impl<S, E> Freezable for CrsfBridge<S, E>
137where
138 S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static,
139 E: 'static,
140{
141}
142
143impl<S, E> CuBridge for CrsfBridge<S, E>
144where
145 S: Write<Error = E> + Read<Error = E> + Send + Sync + 'static,
146 E: 'static,
147{
148 type Tx = TxChannels;
149 type Rx = RxChannels;
150 type Resources<'r> = Resources<S, E>;
151
152 fn new(
153 config: Option<&ComponentConfig>,
154 tx_channels: &[BridgeChannelConfig<<Self::Tx as BridgeChannelSet>::Id>],
155 rx_channels: &[BridgeChannelConfig<<Self::Rx as BridgeChannelSet>::Id>],
156 resources: Self::Resources<'_>,
157 ) -> CuResult<Self>
158 where
159 Self: Sized,
160 {
161 let _ = tx_channels;
162 let _ = rx_channels;
163
164 let _ = config;
165
166 Ok(Self::from_serial(resources.serial.0))
167 }
168
169 fn send<'a, Payload>(
170 &mut self,
171 _ctx: &CuContext,
172 channel: &'static BridgeChannel<<Self::Tx as BridgeChannelSet>::Id, Payload>,
173 msg: &CuMsg<Payload>,
174 ) -> CuResult<()>
175 where
176 Payload: CuMsgPayload + 'a,
177 {
178 match channel.id() {
179 TxId::LqTx => {
180 let lsi: &CuMsg<LinkStatisticsPayload> = msg.downcast_ref()?;
181 if let Some(lq) = lsi.payload() {
182 debug!(
183 "CRSF: Sent LinkStatistics: Downlink LQ:{}",
184 lq.0.downlink_link_quality
185 );
186 self.write_packet(Packet::LinkStatistics(lq.0.clone()))?;
187 }
188 }
189 TxId::RcTx => {
190 let rccs: &CuMsg<RcChannelsPayload> = msg.downcast_ref()?;
191 if let Some(rc) = rccs.payload() {
192 for (i, value) in rc.0.iter().enumerate() {
193 debug!("Sending RC Channel {}: {}", i, value);
194 }
195 self.write_packet(Packet::RcChannels(rc.0.clone()))?;
196 }
197 }
198 }
199 Ok(())
200 }
201
202 fn receive<'a, Payload>(
203 &mut self,
204 ctx: &CuContext,
205 channel: &'static BridgeChannel<<Self::Rx as BridgeChannelSet>::Id, Payload>,
206 msg: &mut CuMsg<Payload>,
207 ) -> CuResult<()>
208 where
209 Payload: CuMsgPayload + 'a,
210 {
211 self.update()?;
212 msg.tov = Tov::Time(ctx.now());
213 match channel.id() {
214 RxId::LqRx => {
215 if let Some(lq) = self.last_lq.as_ref() {
216 let lqp = LinkStatisticsPayload::from(lq.clone());
217 let lq_msg: &mut CuMsg<LinkStatisticsPayload> = msg.downcast_mut()?;
218 lq_msg.set_payload(lqp);
219 }
220 }
221 RxId::RcRx => {
222 if let Some(rc) = self.last_rc.as_ref() {
223 let rc = RcChannelsPayload::from(rc.clone());
224 let rc_msg: &mut CuMsg<RcChannelsPayload> = msg.downcast_mut()?;
225 rc_msg.set_payload(rc);
226 }
227 }
228 }
229 Ok(())
230 }
231}
232
233#[cfg(feature = "std")]
235pub type CrsfBridgeStd = CrsfBridge<cu_linux_resources::LinuxSerialPort, std::io::Error>;