Skip to main content

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//! Demonstrates `AtContext` implementations for device-specific commands
24//! in a no_std/embedded environment, using the `at_response!` macro and
25//! the 3-tuple command registration `(at_command, at_response, handler)`.
26
27#![allow(dead_code)]
28#![no_std]
29#![no_main]
30
31extern crate at_parser_rs;
32
33use at_parser_rs::context::AtContext;
34use at_parser_rs::parser::AtParser;
35use at_parser_rs::{Args, AtError, AtResult, at_response};
36
37const SIZE: usize = 64;
38
39/// UART send command — forwards data to the hardware peripheral
40struct UartSendModule {
41    baudrate: u32,
42}
43
44impl UartSendModule {
45    const fn new() -> Self {
46        Self { baudrate: 9600 }
47    }
48
49    fn write(&self, _data: &str) {
50        // In real embedded code: write to the UART peripheral here
51    }
52}
53
54impl AtContext<SIZE> for UartSendModule {
55    /// Query: return current baud-rate
56    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
57        Ok(at_response!(SIZE, at_response; self.baudrate))
58    }
59
60    /// Test: show accepted syntax
61    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
62        Ok(at_response!(SIZE, at_response; "\"<data>\""))
63    }
64
65    /// Set: send the given data string over UART
66    fn set(&mut self, at_response: &'static str, args: Args) -> AtResult<'_, SIZE> {
67        let data = args.get(0).ok_or((at_response, AtError::InvalidArgs))?;
68        self.write(data.as_ref());
69        Ok(at_response!(SIZE, at_response; "SENT"))
70    }
71}
72
73/// Device configuration command — get/set baudrate and mode
74struct ConfigModule {
75    baudrate: u32,
76    mode: u8,
77}
78
79impl ConfigModule {
80    const fn new() -> Self {
81        Self { baudrate: 115200, mode: 0 }
82    }
83}
84
85impl AtContext<SIZE> for ConfigModule {
86    /// Query: return current configuration as `<baudrate>,<mode>`
87    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
88        Ok(at_response!(SIZE, at_response; self.baudrate, self.mode))
89    }
90
91    /// Test: return supported configuration ranges
92    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
93        Ok(at_response!(SIZE, at_response; "<baudrate: 9600-115200>,<mode: 0|1>"))
94    }
95
96    /// Set: apply new baudrate and mode
97    fn set(&mut self, at_response: &'static str, args: Args) -> AtResult<'_, SIZE> {
98        let baudrate = args.get(0)
99            .ok_or((at_response, AtError::InvalidArgs))?
100            .parse::<u32>()
101            .map_err(|_| (at_response, AtError::InvalidArgs))?;
102
103        let mode = args.get(1)
104            .ok_or((at_response, AtError::InvalidArgs))?
105            .parse::<u8>()
106            .map_err(|_| (at_response, AtError::InvalidArgs))?;
107
108        if mode > 1 {
109            return Err((at_response, AtError::InvalidArgs));
110        }
111
112        self.baudrate = baudrate;
113        self.mode = mode;
114        // configure_uart(baudrate, mode);  // apply to hardware here
115
116        Ok(at_response!(SIZE, at_response; "OK"))
117    }
118}
119
120#[unsafe(no_mangle)]
121pub extern "C" fn main() -> ! {
122    let mut uart   = UartSendModule::new();
123    let mut config = ConfigModule::new();
124
125    let mut parser: AtParser<dyn AtContext<SIZE>, SIZE> = AtParser::new();
126    let commands: &mut [(&str, &str, &mut dyn AtContext<SIZE>)] = &mut [
127        ("AT+UARTSEND", "+UARTSEND: ", &mut uart),
128        ("AT+CFG",      "+CFG: ",      &mut config),
129    ];
130    parser.set_commands(commands);
131
132    // Test: show syntax
133    let _ = parser.execute("AT+UARTSEND=?"); // Ok(("+UARTSEND: ", "\"<data>\""))
134    let _ = parser.execute("AT+CFG=?");      // Ok(("+CFG: ", "<baudrate: 9600-115200>,<mode: 0|1>"))
135
136    // Query current config
137    let _ = parser.execute("AT+CFG?");       // Ok(("+CFG: ", "115200,0"))
138
139    // Send data over UART
140    let _ = parser.execute("AT+UARTSEND=\"hello\""); // Ok(("+UARTSEND: ", "SENT"))
141
142    // Set new configuration
143    let _ = parser.execute("AT+CFG=9600,1"); // Ok(("+CFG: ", "OK"))
144    let _ = parser.execute("AT+CFG?");       // Ok(("+CFG: ", "9600,1"))
145
146    // Error cases
147    let _ = parser.execute("AT+CFG=9600,5"); // Err(("+CFG: ", InvalidArgs))  — mode > 1
148    let _ = parser.execute("AT+CFG=abc,0");  // Err(("+CFG: ", InvalidArgs))  — bad baudrate
149
150    loop {}
151}
152