Skip to main content

AtContext

Trait AtContext 

Source
pub trait AtContext<const SIZE: usize> {
    // Provided methods
    fn exec(&mut self) -> AtResult<'_, SIZE> { ... }
    fn query(&mut self) -> AtResult<'_, SIZE> { ... }
    fn test(&mut self) -> AtResult<'_, SIZE> { ... }
    fn set(&mut self, _args: Args<'_>) -> AtResult<'_, SIZE> { ... }
}
Expand description

Trait that defines the context for AT command execution.

Implement this trait for each AT command your device exposes. Each method corresponds to one of the four standard AT command forms. All methods have a default implementation that returns AtError::NotSupported, so you only need to override the forms your command actually needs.

The const generic SIZE defines the capacity (in bytes) of the Bytes response buffer returned by each handler. All handlers registered in the same AtParser must use the same SIZE.

§Example — minimal handler

use at_parser_rs::context::AtContext;
use at_parser_rs::{Args, AtResult, AtError};
use osal_rs::utils::Bytes;

const SIZE: usize = 64;

struct ResetModule;

impl AtContext<SIZE> for ResetModule {
    fn exec(&mut self) -> AtResult<'_, SIZE> {
        // AT+RST performs a system reset
        Ok(Bytes::from_str("OK"))
    }
}

§Example — full handler with all forms

use at_parser_rs::context::AtContext;
use at_parser_rs::{Args, AtResult, AtError};
use osal_rs::utils::Bytes;

const SIZE: usize = 64;

struct EchoModule { enabled: bool }

impl AtContext<SIZE> for EchoModule {
    fn exec(&mut self) -> AtResult<'_, SIZE> {
        let s = if self.enabled { "ECHO: ON" } else { "ECHO: OFF" };
        Ok(Bytes::from_str(s))
    }
    fn query(&mut self) -> AtResult<'_, SIZE> {
        Ok(Bytes::from_str(if self.enabled { "1" } else { "0" }))
    }
    fn test(&mut self) -> AtResult<'_, SIZE> {
        Ok(Bytes::from_str("(0,1)"))
    }
    fn set(&mut self, args: Args) -> AtResult<'_, SIZE> {
        let value = args.get(0).ok_or(AtError::InvalidArgs)?;
        match value.as_ref() {
            "0" => { self.enabled = false; Ok(Bytes::from_str("OK")) }
            "1" => { self.enabled = true;  Ok(Bytes::from_str("OK")) }
            _ => Err(AtError::InvalidArgs),
        }
    }
}

Provided Methods§

Source

fn exec(&mut self) -> AtResult<'_, SIZE>

Execute command (AT+CMD)

Called when the command is invoked without any suffix. Use this to implement an action that does not require parameters.

§Returns
  • Ok(Bytes<SIZE>) — response to send back to the caller
  • Err(AtError::NotSupported) — default when not overridden
§Example
struct PingModule;

impl AtContext<SIZE> for PingModule {
    fn exec(&mut self) -> AtResult<'_, SIZE> {
        Ok(Bytes::from_str("PONG"))
    }
}
// AT+PING  →  "PONG"
Examples found in repository?
examples/complete_usage.rs (line 179)
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}
Source

fn query(&mut self) -> AtResult<'_, SIZE>

Query command (AT+CMD?)

Called to retrieve the current value or state of the command.

§Returns
  • Ok(Bytes<SIZE>) — current value/state
  • Err(AtError::NotSupported) — default when not overridden
§Example
struct VolumeModule { level: u8 }

impl AtContext<SIZE> for VolumeModule {
    fn query(&mut self) -> AtResult<'_, SIZE> {
        let mut buf = Bytes::new();
        buf.format(core::format_args!("{}", self.level));
        Ok(buf)
    }
}
// AT+VOL?  →  "75"  (if level == 75)
Examples found in repository?
examples/complete_usage.rs (line 181)
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}
Source

fn test(&mut self) -> AtResult<'_, SIZE>

Test command (AT+CMD=?)

Called to report whether a command is supported or to return the valid parameter ranges accepted by set.

§Returns
  • Ok(Bytes<SIZE>) — human-readable description of valid parameters
  • Err(AtError::NotSupported) — default when not overridden
§Example
struct VolumeModule { level: u8 }

impl AtContext<SIZE> for VolumeModule {
    fn test(&mut self) -> AtResult<'_, SIZE> {
        Ok(Bytes::from_str("(0-100)"))
    }
}
// AT+VOL=?  →  "(0-100)"
Examples found in repository?
examples/complete_usage.rs (line 183)
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}
Source

fn set(&mut self, _args: Args<'_>) -> AtResult<'_, SIZE>

Set command (AT+CMD=<args>)

Called to configure the command with one or more parameters. Arguments are accessible via Args::get using a 0-based comma-separated index. Quoted arguments are unquoted and escape sequences such as \" are decoded automatically.

§Arguments
  • args — parsed argument list; use args.get(n) to retrieve the n-th comma-separated token (0-indexed)
§Returns
  • Ok(Bytes<SIZE>) — confirmation/response
  • Err(AtError::InvalidArgs) — when arguments are missing or invalid
  • Err(AtError::NotSupported) — default when not overridden
§Example
struct VolumeModule { level: u8 }

impl AtContext<SIZE> for VolumeModule {
    fn set(&mut self, args: Args) -> AtResult<'_, SIZE> {
        let val: u8 = args.get(0)
            .ok_or(AtError::InvalidArgs)?
            .parse()
            .map_err(|_| AtError::InvalidArgs)?;
        if val > 100 { return Err(AtError::InvalidArgs); }
        self.level = val;
        Ok(Bytes::from_str("OK"))
    }
}
// AT+VOL=75   →  "OK"      (sets level to 75)
// AT+VOL=200  →  Err(InvalidArgs)
// AT+VOL=     →  Err(InvalidArgs)
Examples found in repository?
examples/complete_usage.rs (line 185)
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}

Implementors§