Skip to main content

complete_usage/
complete_usage.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//! Complete example demonstrating the AT command parser functionality
22//!
23//! **Note**: no_std compatible example - designed to compile and run on embedded
24//! targets. Demonstrates all AT command forms without std dependency.
25
26#![no_std]
27#![no_main]
28#![allow(dead_code, unused_variables)]
29
30extern crate at_parser_rs;
31
32use at_parser_rs::context::AtContext;
33use at_parser_rs::parser::AtParser;
34use at_parser_rs::{Args, AtError, AtResult, at_response};
35
36const SIZE: usize = 64;
37
38/// Echo command module - manages echo state
39pub struct EchoModule {
40    pub echo: bool,
41}
42
43impl AtContext<SIZE> for EchoModule {
44    /// Execute: return current echo state
45    fn exec(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
46        Ok(at_response!(SIZE, at_response; if self.echo { "ON" } else { "OFF" }))
47    }
48
49    /// Query: return current echo value (0 or 1)
50    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
51        Ok(at_response!(SIZE, at_response; if self.echo { 1u8 } else { 0u8 }))
52    }
53
54    /// Test: show valid values
55    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
56        Ok(at_response!(SIZE, at_response; "(0,1)"))
57    }
58
59    /// Set: enable/disable echo
60    fn set(&mut self, at_response: &'static str, args: Args) -> AtResult<'_, SIZE> {
61        let value = args.get(0).ok_or((at_response, AtError::InvalidArgs))?;
62        match value.as_ref() {
63            "0" => {
64                self.echo = false;
65                Ok(at_response!(SIZE, at_response; "OK"))
66            }
67            "1" => {
68                self.echo = true;
69                Ok(at_response!(SIZE, at_response; "OK"))
70            }
71            _ => Err((at_response, AtError::InvalidArgs)),
72        }
73    }
74}
75
76/// Reset command module - simulates system reset
77pub struct ResetModule;
78
79impl AtContext<SIZE> for ResetModule {
80    /// Execute: perform reset
81    fn exec(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
82        Ok(at_response!(SIZE, at_response; "OK"))
83    }
84
85    /// Test: show command description
86    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
87        Ok(at_response!(SIZE, at_response; "Reset the system"))
88    }
89}
90
91/// Info command module - provides system information
92pub struct InfoModule {
93    pub version: &'static str,
94}
95
96impl AtContext<SIZE> for InfoModule {
97    /// Execute: return version string
98    fn exec(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
99        Ok(at_response!(SIZE, at_response; self.version))
100    }
101
102    /// Query: return detailed info
103    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
104        Ok(at_response!(SIZE, at_response; "AT-Parser-RS - AT Command Parser Library"))
105    }
106}
107
108/// LED command module - controls an LED with multiple parameters
109pub struct LedModule {
110    pub state: bool,
111    pub brightness: u8,
112}
113
114impl AtContext<SIZE> for LedModule {
115    /// Execute: return current LED state
116    fn exec(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
117        Ok(at_response!(SIZE, at_response; if self.state { "ON" } else { "OFF" }))
118    }
119
120    /// Query: return state and brightness
121    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
122        Ok(at_response!(SIZE, at_response; self.state as u8, self.brightness))
123    }
124
125    /// Test: show usage
126    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
127        Ok(at_response!(SIZE, at_response; "<state: 0|1>,<brightness: 0-100>"))
128    }
129
130    /// Set: change LED state and brightness
131    fn set(&mut self, at_response: &'static str, args: Args) -> AtResult<'_, SIZE> {
132        let state_str = args.get(0).ok_or((at_response, AtError::InvalidArgs))?;
133
134        self.state = match state_str.as_ref() {
135            "0" => false,
136            "1" => true,
137            _ => return Err((at_response, AtError::InvalidArgs)),
138        };
139
140        // Optional brightness parameter
141        if let Some(brightness_str) = args.get(1) {
142            let bri = brightness_str
143                .parse::<u8>()
144                .map_err(|_| (at_response, AtError::InvalidArgs))?;
145
146            if bri > 100 {
147                return Err((at_response, AtError::InvalidArgs));
148            }
149            self.brightness = bri;
150        }
151
152        Ok(at_response!(SIZE, at_response; "OK"))
153    }
154}
155
156#[unsafe(no_mangle)]
157pub extern "C" fn main() -> ! {
158    let mut echo = EchoModule { echo: false };
159    let mut reset = ResetModule;
160    let mut info = InfoModule { version: "v1.0.0" };
161    let mut led = LedModule { state: false, brightness: 0 };
162
163    let mut parser: AtParser<dyn AtContext<SIZE>, SIZE> = AtParser::new();
164
165    let commands: &mut [(&str, &str, &mut dyn AtContext<SIZE>)] = &mut [
166        ("AT+ECHO", "+ECHO: ", &mut echo),
167        ("AT+RST",  "+RST: ",  &mut reset),
168        ("AT+INFO", "+INFO: ", &mut info),
169        ("AT+LED",  "+LED: ",  &mut led),
170    ];
171    parser.set_commands(commands);
172
173    // INFO
174    let _ = parser.execute("AT+INFO");   // Ok(("+INFO: ", "v1.0.0"))
175    let _ = parser.execute("AT+INFO?");  // Ok(("+INFO: ", "AT-Parser-RS ..."))
176
177    // ECHO
178    let _ = parser.execute("AT+ECHO");   // Ok(("+ECHO: ", "OFF"))
179    let _ = parser.execute("AT+ECHO=?"); // Ok(("+ECHO: ", "(0,1)"))
180    let _ = parser.execute("AT+ECHO=1"); // Ok(("+ECHO: ", "OK"))
181    let _ = parser.execute("AT+ECHO?");  // Ok(("+ECHO: ", "1"))
182    let _ = parser.execute("AT+ECHO=0"); // Ok(("+ECHO: ", "OK"))
183
184    // LED
185    let _ = parser.execute("AT+LED=?");    // Ok(("+LED: ", "<state: 0|1>,<brightness: 0-100>"))
186    let _ = parser.execute("AT+LED=1");    // Ok(("+LED: ", "OK"))
187    let _ = parser.execute("AT+LED?");     // Ok(("+LED: ", "1,0"))
188    let _ = parser.execute("AT+LED=1,75"); // Ok(("+LED: ", "OK"))
189    let _ = parser.execute("AT+LED=0");    // Ok(("+LED: ", "OK"))
190
191    // RESET
192    let _ = parser.execute("AT+RST=?"); // Ok(("+RST: ", "Reset the system"))
193    let _ = parser.execute("AT+RST");   // Ok(("+RST: ", "OK"))
194
195    // Error cases
196    let _ = parser.execute("AT+ECHO=2");   // Err(("+ECHO: ", InvalidArgs))
197    let _ = parser.execute("AT+UNKNOWN");  // Err(("", UnknownCommand))
198
199    loop {}
200}
201