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