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