macro_rules! at_modules {
(
$size:expr;
$( $name:expr => $module:ident ),* $(,)?
) => { ... };
}Expand description
Declares a static COMMANDS table mapping AT command strings to their handlers.
This macro expands into a static COMMANDS binding of type
&[(&'static str, &mut dyn AtContext<SIZE>)], which can then be passed to
AtParser::set_commands.
§Syntax
ⓘ
at_modules! {
SIZE;
"AT+CMD1" => HANDLER1,
"AT+CMD2" => HANDLER2,
}SIZE—const usizethat defines the response buffer capacity (must match the capacity used byAtParserand everyAtContextimpl)."AT+CMDn"— the AT command string the parser will match against.HANDLERn— astatic mutvariable that implementsAtContext<SIZE>.
§Safety
The macro uses an unsafe block internally to obtain &mut references to
static mut items. It is the caller’s responsibility to ensure:
- Single-threaded access only — do not call this in a multi-threaded or RTOS context without external synchronisation.
- One call site — the generated
COMMANDSsymbol isstatic; defining it more than once in the same scope will cause a compile error.
§Limitations
- All handlers must implement
AtContextwith the sameSIZEconstant. - The generated symbol is always named
COMMANDS; rename it after expansion if you need multiple tables.
§Example — basic usage
use at_parser_rs::at_modules;
use at_parser_rs::context::AtContext;
use at_parser_rs::{Args, AtResult, AtError};
use osal_rs::utils::Bytes;
const SIZE: usize = 64;
struct EchoModule { echo: bool }
impl AtContext<SIZE> for EchoModule {
fn query(&mut self) -> AtResult<SIZE> {
Ok(Bytes::from_str(if self.echo { "1" } else { "0" }))
}
fn set(&mut self, args: Args) -> AtResult<SIZE> {
let value = args.get(0).ok_or(AtError::InvalidArgs)?;
match value.as_ref() {
"0" => { self.echo = false; Ok(Bytes::from_str("OK")) }
"1" => { self.echo = true; Ok(Bytes::from_str("OK")) }
_ => Err(AtError::InvalidArgs),
}
}
}
struct ResetModule;
impl AtContext<SIZE> for ResetModule {
fn exec(&mut self) -> AtResult<SIZE> { Ok(Bytes::from_str("OK")) }
}
static mut ECHO: EchoModule = EchoModule { echo: false };
static mut RESET: ResetModule = ResetModule;
at_modules! {
SIZE;
"AT+ECHO" => ECHO,
"AT+RST" => RESET,
}
// COMMANDS is now available in scope:
// parser.set_commands(COMMANDS);§Example — single handler
use at_parser_rs::at_modules;
use at_parser_rs::context::AtContext;
use at_parser_rs::{AtResult};
use osal_rs::utils::Bytes;
const SIZE: usize = 32;
struct PingModule;
impl AtContext<SIZE> for PingModule {
fn exec(&mut self) -> AtResult<SIZE> { Ok(Bytes::from_str("PONG")) }
}
static mut PING: PingModule = PingModule;
at_modules! {
SIZE;
"AT+PING" => PING,
}§Recommended alternative
For multi-type handler tables or when static mut is undesirable, prefer the
explicit slice approach — it requires no unsafe at the call site and allows
mixing handler types via trait objects:
use at_parser_rs::context::AtContext;
const SIZE: usize = 64;
let mut echo = EchoModule { echo: false };
let mut reset = ResetModule;
let commands: &mut [(&str, &mut dyn AtContext<SIZE>)] = &mut [
("AT+ECHO", &mut echo),
("AT+RST", &mut reset),
];
parser.set_commands(commands);