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::{Args, AtError, AtResult, Bytes};
34
35const SIZE: usize = 64;
36
37/// Echo command module - manages echo state
38pub struct EchoModule {
39    pub echo: bool,
40}
41
42impl AtContext<SIZE> for EchoModule {
43    /// Execute: return current echo state
44    fn exec(&self) -> AtResult<SIZE> {
45        if self.echo {
46            Ok(Bytes::from_str("ECHO: ON"))
47        } else {
48            Ok(Bytes::from_str("ECHO: OFF"))
49        }
50    }
51
52    /// Query: return current echo value
53    fn query(&mut self) -> AtResult<SIZE> {
54        if self.echo {
55            Ok(Bytes::from_str("1"))
56        } else {
57            Ok(Bytes::from_str("0"))
58        }
59    }
60
61    /// Test: show valid values
62    fn test(&mut self) -> AtResult<SIZE> {
63        Ok(Bytes::from_str("Valid values: 0 (OFF), 1 (ON)"))
64    }
65
66    /// Set: enable/disable echo
67    fn set(&mut self, args: Args) -> AtResult<SIZE> {
68        let value = args.get(0).ok_or(AtError::InvalidArgs)?;
69        match value {
70            "0" => {
71                self.echo = false;
72                Ok(Bytes::from_str("ECHO OFF"))
73            }
74            "1" => {
75                self.echo = true;
76                Ok(Bytes::from_str("ECHO ON"))
77            }
78            _ => Err(AtError::InvalidArgs),
79        }
80    }
81}
82
83/// Reset command module - simulates system reset
84pub struct ResetModule;
85
86impl AtContext<SIZE> for ResetModule {
87    /// Execute: perform reset
88    fn exec(&self) -> AtResult<SIZE> {
89        Ok(Bytes::from_str("OK - System reset"))
90    }
91
92    /// Test: show command description
93    fn test(&mut self) -> AtResult<SIZE> {
94        Ok(Bytes::from_str("Reset the system"))
95    }
96}
97
98/// Info command module - provides system information
99pub struct InfoModule {
100    pub version: &'static str,
101}
102
103impl AtContext<SIZE> for InfoModule {
104    /// Execute: return system info
105    fn exec(&self) -> AtResult<SIZE> {
106        Ok(Bytes::from_str(self.version))
107    }
108
109    /// Query: return detailed info
110    fn query(&mut self) -> AtResult<SIZE> {
111        Ok(Bytes::from_str("AT-Parser-RS v1.0.0 - AT Command Parser Library"))
112    }
113}
114
115/// LED command module - controls an LED with multiple parameters
116pub struct LedModule {
117    pub state: bool,
118    pub brightness: u8,
119}
120
121impl AtContext<SIZE> for LedModule {
122    /// Execute: return current LED state
123    fn exec(&self) -> AtResult<SIZE> {
124        if self.state {
125            Ok(Bytes::from_str("LED: ON"))
126        } else {
127            Ok(Bytes::from_str("LED: OFF"))
128        }
129    }
130
131    /// Query: return state and brightness
132    fn query(&mut self) -> AtResult<SIZE> {
133        if self.state {
134            Ok(Bytes::from_str("1,100"))
135        } else {
136            Ok(Bytes::from_str("0,0"))
137        }
138    }
139
140    /// Test: show usage
141    fn test(&mut self) -> AtResult<SIZE> {
142        Ok(Bytes::from_str("AT+LED=<state>,<brightness> where state: 0|1, brightness: 0-100"))
143    }
144
145    /// Set: change LED state and brightness
146    fn set(&mut self, args: Args) -> AtResult<SIZE> {
147        let state_str = args.get(0).ok_or(AtError::InvalidArgs)?;
148        
149        self.state = match state_str {
150            "0" => false,
151            "1" => true,
152            _ => return Err(AtError::InvalidArgs),
153        };
154
155        // Optional brightness parameter
156        if let Some(brightness_str) = args.get(1) {
157            self.brightness = brightness_str
158                .parse::<u8>()
159                .map_err(|_| AtError::InvalidArgs)?;
160            
161            if self.brightness > 100 {
162                return Err(AtError::InvalidArgs);
163            }
164        }
165
166        if self.state {
167            Ok(Bytes::from_str("LED ON"))
168        } else {
169            Ok(Bytes::from_str("LED OFF"))
170        }
171    }
172}
173
174/// Helper function to execute a command and ignore the result
175fn execute_command(cmd: &str, name: &str, module: &mut dyn AtContext<SIZE>) {
176    let result = if let Some(rest) = cmd.strip_prefix(name) {
177        if rest.is_empty() {
178            module.exec()
179        } else if rest == "?" {
180            module.query()
181        } else if rest == "=?" {
182            module.test()
183        } else if let Some(args_str) = rest.strip_prefix('=') {
184            module.set(Args { raw: args_str })
185        } else {
186            Err(AtError::InvalidArgs)
187        }
188    } else {
189        Err(AtError::UnknownCommand)
190    };
191    let _ = result;
192}
193
194#[unsafe(no_mangle)]
195pub extern "C" fn main() -> ! {
196    let mut echo = EchoModule { echo: false };
197    let mut reset = ResetModule;
198    let mut info = InfoModule { version: "v1.0.0" };
199    let mut led = LedModule { state: false, brightness: 0 };
200
201    // INFO
202    execute_command("AT+INFO",   "AT+INFO", &mut info);
203    execute_command("AT+INFO?",  "AT+INFO", &mut info);
204
205    // ECHO
206    execute_command("AT+ECHO",   "AT+ECHO", &mut echo);
207    execute_command("AT+ECHO=?", "AT+ECHO", &mut echo);
208    execute_command("AT+ECHO=1", "AT+ECHO", &mut echo);
209    execute_command("AT+ECHO?",  "AT+ECHO", &mut echo);
210    execute_command("AT+ECHO=0", "AT+ECHO", &mut echo);
211
212    // LED
213    execute_command("AT+LED=?",   "AT+LED", &mut led);
214    execute_command("AT+LED=1",   "AT+LED", &mut led);
215    execute_command("AT+LED?",    "AT+LED", &mut led);
216    execute_command("AT+LED=1,75","AT+LED", &mut led);
217    execute_command("AT+LED=0",   "AT+LED", &mut led);
218
219    // RESET
220    execute_command("AT+RST=?", "AT+RST", &mut reset);
221    execute_command("AT+RST",   "AT+RST", &mut reset);
222
223    // Error cases
224    execute_command("AT+ECHO=2", "AT+ECHO", &mut echo);  // -> Err(InvalidArgs)
225    execute_command("AT+INFO=1", "AT+INFO", &mut info);  // -> Err(NotSupported)
226
227    loop {}
228}