Skip to main content

obniz_rust/
uart.rs

1use serde::{Deserialize, Serialize};
2use serde_json::json;
3use tokio_tungstenite::tungstenite::protocol::Message;
4
5use crate::error::{ObnizError, ObnizResult};
6use crate::obniz::Obniz;
7
8/// UART parity settings
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "lowercase")]
11pub enum Parity {
12    Off,
13    Odd,
14    Even,
15}
16
17/// UART flow control settings
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19#[serde(rename_all = "lowercase")]
20pub enum FlowControl {
21    Off,
22    Rts,
23    Cts,
24    #[serde(rename = "rts-cts")]
25    RtsCts,
26}
27
28/// UART configuration
29#[derive(Debug, Clone)]
30pub struct UartConfig {
31    pub rx_pin: u8,
32    pub tx_pin: u8,
33    pub baud_rate: u32,
34    pub stop_bits: f32,
35    pub data_bits: u8,
36    pub parity: Parity,
37    pub flow_control: FlowControl,
38    pub rts_pin: Option<u8>,
39    pub cts_pin: Option<u8>,
40}
41
42impl Default for UartConfig {
43    fn default() -> Self {
44        Self {
45            rx_pin: 0,
46            tx_pin: 1,
47            baud_rate: 115200,
48            stop_bits: 1.0,
49            data_bits: 8,
50            parity: Parity::Off,
51            flow_control: FlowControl::Off,
52            rts_pin: None,
53            cts_pin: None,
54        }
55    }
56}
57
58/// UART communication manager
59#[derive(Debug)]
60pub struct UartChannel {
61    channel: u8,
62    obniz: Obniz,
63}
64
65impl UartChannel {
66    pub fn new(channel: u8, obniz: Obniz) -> Self {
67        Self { channel, obniz }
68    }
69
70    pub fn channel_key(&self) -> String {
71        format!("uart{}", self.channel)
72    }
73
74    /// Initialize UART with configuration
75    pub async fn init(&self, config: UartConfig) -> ObnizResult<()> {
76        // Validate pins
77        if config.rx_pin > 11 || config.tx_pin > 11 {
78            return Err(ObnizError::Generic("UART pins must be 0-11".to_string()));
79        }
80
81        if let Some(rts_pin) = config.rts_pin {
82            if rts_pin > 11 {
83                return Err(ObnizError::InvalidPin(rts_pin));
84            }
85        }
86
87        if let Some(cts_pin) = config.cts_pin {
88            if cts_pin > 11 {
89                return Err(ObnizError::InvalidPin(cts_pin));
90            }
91        }
92
93        // Validate baud rate
94        if config.baud_rate == 0 || config.baud_rate > 5_000_000 {
95            return Err(ObnizError::Generic(
96                "Baud rate must be between 1 and 5,000,000".to_string(),
97            ));
98        }
99
100        // Validate data bits
101        if config.data_bits < 5 || config.data_bits > 8 {
102            return Err(ObnizError::Generic(
103                "Data bits must be 5, 6, 7, or 8".to_string(),
104            ));
105        }
106
107        // Validate stop bits
108        if config.stop_bits != 1.0 && config.stop_bits != 1.5 && config.stop_bits != 2.0 {
109            return Err(ObnizError::Generic(
110                "Stop bits must be 1, 1.5, or 2".to_string(),
111            ));
112        }
113
114        let channel_key = self.channel_key();
115        let mut uart_config = json!({
116            "rx": config.rx_pin,
117            "tx": config.tx_pin,
118            "baud": config.baud_rate,
119            "stop": config.stop_bits,
120            "bits": config.data_bits,
121            "parity": config.parity
122        });
123
124        // Add flow control pins if specified
125        if let Some(rts_pin) = config.rts_pin {
126            uart_config["rts"] = json!(rts_pin);
127        }
128        if let Some(cts_pin) = config.cts_pin {
129            uart_config["cts"] = json!(cts_pin);
130        }
131
132        let request = json!([{&channel_key: uart_config}]);
133        let message = Message::from(request.to_string());
134
135        self.obniz
136            .send_message(message)
137            .map_err(|e| ObnizError::Connection(e.to_string()))
138    }
139
140    /// Send data via UART
141    pub async fn send(&self, data: Vec<u8>) -> ObnizResult<()> {
142        if data.is_empty() {
143            return Err(ObnizError::Generic("Data cannot be empty".to_string()));
144        }
145
146        // Data validation: u8 values are inherently 0-255, no additional check needed
147
148        let channel_key = self.channel_key();
149        let request = json!([{&channel_key: {"data": data}}]);
150        let message = Message::from(request.to_string());
151
152        self.obniz
153            .send_message(message)
154            .map_err(|e| ObnizError::Connection(e.to_string()))
155    }
156
157    /// Send string data via UART (converted to UTF-8 bytes)
158    pub async fn send_string(&self, text: &str) -> ObnizResult<()> {
159        let data = text.as_bytes().to_vec();
160        self.send(data).await
161    }
162
163    /// Register callback for received data
164    pub async fn on_receive<F>(&self, callback: F) -> ObnizResult<()>
165    where
166        F: Fn(Vec<u8>) + Send + Sync + 'static,
167    {
168        let channel_key = self.channel_key();
169        let channel_key_clone = channel_key.clone();
170
171        self.obniz
172            .register_callback(channel_key, move |response| {
173                if let Some(uart_data) = response.get(&channel_key_clone) {
174                    if let Some(data_array) = uart_data.get("data") {
175                        if let Some(data_vec) = data_array.as_array() {
176                            let bytes: Vec<u8> = data_vec
177                                .iter()
178                                .filter_map(|v| v.as_u64())
179                                .map(|v| v as u8)
180                                .collect();
181                            callback(bytes);
182                        }
183                    }
184                }
185            })
186            .map_err(|e| ObnizError::CallbackError(e.to_string()))?;
187
188        Ok(())
189    }
190
191    /// Register callback for received string data
192    pub async fn on_receive_string<F>(&self, callback: F) -> ObnizResult<()>
193    where
194        F: Fn(String) + Send + Sync + 'static,
195    {
196        self.on_receive(move |data| {
197            if let Ok(text) = String::from_utf8(data) {
198                callback(text);
199            }
200        })
201        .await
202    }
203
204    /// Remove receive callback
205    pub fn remove_callback(&self) -> ObnizResult<()> {
206        let channel_key = self.channel_key();
207        self.obniz
208            .unregister_callback(channel_key)
209            .map_err(|e| ObnizError::CallbackError(e.to_string()))
210    }
211
212    /// Deinitialize UART channel
213    pub async fn deinit(&self) -> ObnizResult<()> {
214        let channel_key = self.channel_key();
215        let request = json!([{&channel_key: null}]);
216        let message = Message::from(request.to_string());
217
218        self.obniz
219            .send_message(message)
220            .map_err(|e| ObnizError::Connection(e.to_string()))
221    }
222}
223
224/// UART manager for handling multiple channels
225#[derive(Debug, Clone)]
226pub struct UartManager {
227    obniz: Obniz,
228}
229
230impl UartManager {
231    pub fn new(obniz: Obniz) -> Self {
232        Self { obniz }
233    }
234
235    /// Get specific UART channel (typically uart0)
236    pub fn channel(&self, channel: u8) -> ObnizResult<UartChannel> {
237        // Most obniz devices support uart0, some may support more
238        if channel > 2 {
239            return Err(ObnizError::Generic("UART channel must be 0-2".to_string()));
240        }
241        Ok(UartChannel::new(channel, self.obniz.clone()))
242    }
243
244    /// Get primary UART channel (uart0)
245    pub fn uart0(&self) -> UartChannel {
246        UartChannel::new(0, self.obniz.clone())
247    }
248
249    /// Initialize UART channel with configuration
250    pub async fn init_channel(&self, channel: u8, config: UartConfig) -> ObnizResult<()> {
251        self.channel(channel)?.init(config).await
252    }
253
254    /// Send data on specific channel
255    pub async fn send_data(&self, channel: u8, data: Vec<u8>) -> ObnizResult<()> {
256        self.channel(channel)?.send(data).await
257    }
258
259    /// Send string on specific channel
260    pub async fn send_string(&self, channel: u8, text: &str) -> ObnizResult<()> {
261        self.channel(channel)?.send_string(text).await
262    }
263
264    /// Set receive callback for specific channel
265    pub async fn set_receive_callback<F>(&self, channel: u8, callback: F) -> ObnizResult<()>
266    where
267        F: Fn(Vec<u8>) + Send + Sync + 'static,
268    {
269        self.channel(channel)?.on_receive(callback).await
270    }
271
272    /// Set string receive callback for specific channel
273    pub async fn set_string_callback<F>(&self, channel: u8, callback: F) -> ObnizResult<()>
274    where
275        F: Fn(String) + Send + Sync + 'static,
276    {
277        self.channel(channel)?.on_receive_string(callback).await
278    }
279
280    /// Remove callback for specific channel
281    pub fn remove_channel_callback(&self, channel: u8) -> ObnizResult<()> {
282        self.channel(channel)?.remove_callback()
283    }
284
285    /// Deinitialize specific channel
286    pub async fn deinit_channel(&self, channel: u8) -> ObnizResult<()> {
287        self.channel(channel)?.deinit().await
288    }
289
290    /// Create simple UART configuration for common use cases
291    pub fn simple_config(rx_pin: u8, tx_pin: u8, baud_rate: u32) -> UartConfig {
292        UartConfig {
293            rx_pin,
294            tx_pin,
295            baud_rate,
296            ..Default::default()
297        }
298    }
299
300    /// Create UART configuration with flow control
301    pub fn flow_control_config(
302        rx_pin: u8,
303        tx_pin: u8,
304        rts_pin: u8,
305        cts_pin: u8,
306        baud_rate: u32,
307    ) -> UartConfig {
308        UartConfig {
309            rx_pin,
310            tx_pin,
311            baud_rate,
312            flow_control: FlowControl::RtsCts,
313            rts_pin: Some(rts_pin),
314            cts_pin: Some(cts_pin),
315            ..Default::default()
316        }
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use super::*;
323
324    #[test]
325    fn test_uart_config_default() {
326        let config = UartConfig::default();
327
328        assert_eq!(config.rx_pin, 0);
329        assert_eq!(config.tx_pin, 1);
330        assert_eq!(config.baud_rate, 115200);
331        assert_eq!(config.stop_bits, 1.0);
332        assert_eq!(config.data_bits, 8);
333        assert_eq!(config.parity, Parity::Off);
334        assert_eq!(config.flow_control, FlowControl::Off);
335    }
336
337    #[test]
338    fn test_uart_config_custom() {
339        let config = UartConfig {
340            rx_pin: 2,
341            tx_pin: 3,
342            baud_rate: 9600,
343            stop_bits: 2.0,
344            data_bits: 7,
345            parity: Parity::Even,
346            flow_control: FlowControl::RtsCts,
347            rts_pin: Some(4),
348            cts_pin: Some(5),
349        };
350
351        assert_eq!(config.rx_pin, 2);
352        assert_eq!(config.tx_pin, 3);
353        assert_eq!(config.baud_rate, 9600);
354        assert_eq!(config.parity, Parity::Even);
355        assert_eq!(config.flow_control, FlowControl::RtsCts);
356    }
357
358    #[test]
359    fn test_parity_serialization() {
360        use serde_json;
361
362        assert_eq!(serde_json::to_string(&Parity::Off).unwrap(), "\"off\"");
363        assert_eq!(serde_json::to_string(&Parity::Odd).unwrap(), "\"odd\"");
364        assert_eq!(serde_json::to_string(&Parity::Even).unwrap(), "\"even\"");
365    }
366
367    #[test]
368    fn test_flow_control_serialization() {
369        use serde_json;
370
371        assert_eq!(serde_json::to_string(&FlowControl::Off).unwrap(), "\"off\"");
372        assert_eq!(serde_json::to_string(&FlowControl::Rts).unwrap(), "\"rts\"");
373        assert_eq!(serde_json::to_string(&FlowControl::Cts).unwrap(), "\"cts\"");
374        assert_eq!(
375            serde_json::to_string(&FlowControl::RtsCts).unwrap(),
376            "\"rts-cts\""
377        );
378    }
379
380    #[test]
381    fn test_simple_config_creation() {
382        let config = UartManager::simple_config(2, 3, 9600);
383
384        assert_eq!(config.rx_pin, 2);
385        assert_eq!(config.tx_pin, 3);
386        assert_eq!(config.baud_rate, 9600);
387        assert_eq!(config.parity, Parity::Off);
388    }
389
390    #[test]
391    fn test_flow_control_config_creation() {
392        let config = UartManager::flow_control_config(0, 1, 2, 3, 115200);
393
394        assert_eq!(config.rx_pin, 0);
395        assert_eq!(config.tx_pin, 1);
396        assert_eq!(config.rts_pin, Some(2));
397        assert_eq!(config.cts_pin, Some(3));
398        assert_eq!(config.flow_control, FlowControl::RtsCts);
399    }
400
401    #[test]
402    fn test_channel_key_generation() {
403        assert_eq!(format!("uart{}", 0), "uart0");
404        assert_eq!(format!("uart{}", 1), "uart1");
405    }
406}