embedded_uart_config/embedded_uart_config.rs
1/***************************************************************************
2 *
3 * AT Command Parser
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! Example: AT command table with UART and device configuration handling
22//!
23//! **Note**: This is a pattern demonstration example showing how to implement
24//! configuration commands in no_std/embedded environments. It illustrates
25//! the `AtContext` trait implementation for device-specific commands.
26//!
27//! In a real embedded application, replace the dummy UART implementation
28//! with your platform's actual hardware abstraction layer (HAL).
29
30#![allow(dead_code)]
31#![no_std]
32#![no_main]
33
34extern crate at_parser_rs;
35
36use at_parser_rs::{Args, AtError, AtResult, Bytes};
37use at_parser_rs::context::AtContext;
38
39const SIZE: usize = 64;
40
41// UART struct with AtContext implementation for UARTSEND command
42struct DummyUart {
43 baudrate: u32,
44 mode: u8,
45}
46
47impl DummyUart {
48 const fn new() -> Self {
49 Self { baudrate: 9600, mode: 0 }
50 }
51
52 fn write(&self, data: &str) {
53 // In real embedded, this would send data over UART
54 let _ = data;
55 }
56}
57
58impl AtContext<SIZE> for DummyUart {
59 fn exec(&self) -> AtResult<SIZE> {
60 // Not supported for UARTSEND
61 Err(AtError::NotSupported)
62 }
63 fn set(&mut self, args: Args) -> AtResult<SIZE> {
64 if let Some(data) = args.get(0) {
65 self.write(data);
66 Ok(Bytes::from_str("SENT"))
67 } else {
68 Err(AtError::InvalidArgs)
69 }
70 }
71}
72
73// Device configuration context
74struct ConfigContext;
75
76impl AtContext<SIZE> for ConfigContext {
77 fn exec(&self) -> AtResult<SIZE> {
78 // Not supported for SETCFG
79 Err(AtError::NotSupported)
80 }
81
82 fn query(&mut self) -> AtResult<SIZE> {
83 // Return current configuration as a static string
84 // In real implementation, format the values dynamically
85 Ok(Bytes::from_str("115200,1"))
86 }
87
88 fn test(&mut self) -> AtResult<SIZE> {
89 // Return supported configuration options
90 Ok(Bytes::from_str("+SETCFG: (baudrate),(mode)"))
91 }
92
93 fn set(&mut self, args: Args) -> AtResult<SIZE> {
94 let baud = args.get(0).and_then(|s| s.parse::<u32>().ok());
95 let mode = args.get(1).and_then(|s| s.parse::<u8>().ok());
96 match (baud, mode) {
97 (Some(b), Some(m)) => unsafe {
98 // Configure UART
99 UART.baudrate = b;
100 UART.mode = m;
101 Ok(Bytes::from_str("CONFIGURED"))
102 },
103 _ => Err(AtError::InvalidArgs),
104 }
105 }
106}
107
108static mut UART: DummyUart = DummyUart { baudrate: 9600, mode: 0 };
109static mut CONFIG_CTX: ConfigContext = ConfigContext;
110
111// Example using AtParser
112fn example_with_parser() -> Result<&'static str, AtError> {
113 // Simplified example for no_std
114 // In real embedded code, you would properly initialize the parser
115 Ok("OK")
116}
117
118// Example using the COMMANDS table generated by at_modules macro
119fn example_with_commands_macro() -> Result<&'static str, AtError> {
120 // Simple command parsing without the full parser
121 // In a real embedded system, you would use the parser properly
122 Ok("OK")
123}
124
125// Mock main for compilation (in real embedded code, this would be in your firmware)
126#[unsafe(no_mangle)]
127pub extern "C" fn main() -> ! {
128 // Example usage - in embedded this would be called from your main loop
129 let _result = example_with_commands_macro();
130 loop {}
131}