Skip to main content

embedded_error_handling/
embedded_error_handling.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//! Advanced example: error handling patterns with the at_response! macro
22//!
23//! Demonstrates how to propagate and inspect `AtResult` values whose Ok and
24//! Err variants both carry the AT response prefix alongside the payload.
25
26#![allow(dead_code)]
27#![no_std]
28#![no_main]
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/// A command that may fail in different ways
39struct DiagModule {
40    armed: bool,
41}
42
43impl AtContext<SIZE> for DiagModule {
44    fn exec(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
45        if self.armed {
46            Ok(at_response!(SIZE, at_response; "TRIGGERED"))
47        } else {
48            Err((at_response, AtError::Unhandled("not armed")))
49        }
50    }
51
52    fn query(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
53        Ok(at_response!(SIZE, at_response; if self.armed { 1u8 } else { 0u8 }))
54    }
55
56    fn test(&mut self, at_response: &'static str) -> AtResult<'_, SIZE> {
57        Ok(at_response!(SIZE, at_response; "(0,1)"))
58    }
59
60    fn set(&mut self, at_response: &'static str, args: Args) -> AtResult<'_, SIZE> {
61        let val = args.get(0).ok_or((at_response, AtError::InvalidArgs))?;
62        match val.as_ref() {
63            "0" => { self.armed = false; Ok(at_response!(SIZE, at_response; "OK")) }
64            "1" => { self.armed = true;  Ok(at_response!(SIZE, at_response; "OK")) }
65            _ => Err((at_response, AtError::InvalidArgs)),
66        }
67    }
68}
69
70/// Inspect the result of an execute call and return a status byte
71fn check_result(result: AtResult<SIZE>) -> u8 {
72    match result {
73        Ok((_, _))                           => 0,  // success
74        Err((_, AtError::InvalidArgs))       => 1,
75        Err((_, AtError::NotSupported))      => 2,
76        Err((_, AtError::UnknownCommand))    => 3,
77        Err((_, AtError::Unhandled(_)))      => 4,
78        Err((_, AtError::UnhandledOwned(_))) => 5,
79    }
80}
81
82#[unsafe(no_mangle)]
83pub extern "C" fn main() -> ! {
84    let mut diag = DiagModule { armed: false };
85
86    let mut parser: AtParser<DiagModule, SIZE> = AtParser::new();
87    let commands: &mut [(&str, &str, &mut DiagModule)] = &mut [
88        ("AT+DIAG", "+DIAG: ", &mut diag),
89    ];
90    parser.set_commands(commands);
91
92    // Not armed yet: exec returns Unhandled
93    let _s = check_result(parser.execute("AT+DIAG"));    // -> 4
94
95    // Arm it
96    let _s = check_result(parser.execute("AT+DIAG=1"));  // -> 0
97
98    // Now exec succeeds
99    let _s = check_result(parser.execute("AT+DIAG"));    // -> 0
100
101    // Query state
102    let _s = check_result(parser.execute("AT+DIAG?"));   // -> 0
103
104    // Invalid argument
105    let _s = check_result(parser.execute("AT+DIAG=2"));  // -> 1
106
107    // Unknown command
108    let _s = check_result(parser.execute("AT+UNKNOWN")); // -> 3
109
110    loop {}
111}
112