A helper crate to abstract away the state management and string parsing of AT command communication.
It works by creating structs for each AT command, that each implements
AtatCmd. With corresponding response structs that each implements
AtatResp.
This can be simplified alot using the atat_derive crate!
Examples
Command and response example without atat_derive:
use ;
use Write;
use ;
;
;
;
;
;
Same example with atat_derive:
use ;
use String;
;
;
;
Basic usage example (More available in examples folder):
use cortex_m::asm;
use hal::{
gpio::{
gpioa::{PA2, PA3},
Alternate, Floating, Input, AF7,
},
pac::{interrupt, Peripherals, USART2},
prelude::*,
serial::{Config, Event::Rxne, Rx, Serial},
timer::{Event, Timer},
};
use atat::{atat_derive::{AtatResp, AtatCmd}};
use heapless::{spsc::Queue, String};
use crate::rt::entry;
static mut INGRESS: Option<atat::IngressManager> = None;
static mut RX: Option<Rx<USART2>> = None;
#[derive(Clone, AtatResp)]
pub struct NoResponse;
#[derive(Clone, AtatCmd)]
#[at_cmd("", NoResponse, timeout_ms = 1000)]
pub struct AT;
#[entry]
fn main() -> ! {
let p = Peripherals::take().unwrap();
let mut flash = p.FLASH.constrain();
let mut rcc = p.RCC.constrain();
let mut pwr = p.PWR.constrain(&mut rcc.apb1r1);
let mut gpioa = p.GPIOA.split(&mut rcc.ahb2);
let clocks = rcc.cfgr.freeze(&mut flash.acr, &mut pwr);
let tx = gpioa.pa2.into_af7(&mut gpioa.moder, &mut gpioa.afrl);
let rx = gpioa.pa3.into_af7(&mut gpioa.moder, &mut gpioa.afrl);
let mut timer = Timer::tim7(p.TIM7, 1.hz(), clocks, &mut rcc.apb1r1);
let at_timer = Timer::tim6(p.TIM6, 100.hz(), clocks, &mut rcc.apb1r1);
let mut serial = Serial::usart2(
p.USART2,
(tx, rx),
Config::default().baudrate(115_200.bps()),
clocks,
&mut rcc.apb1r1,
);
serial.listen(Rxne);
static mut RES_QUEUE: ResQueue<256> = Queue::new();
static mut URC_QUEUE: UrcQueue<256, 10> = Queue::new();
static mut COM_QUEUE: ComQueue = Queue::new();
let queues = Queues {
res_queue: unsafe { RES_QUEUE.split() },
urc_queue: unsafe { URC_QUEUE.split() },
com_queue: unsafe { COM_QUEUE.split() },
};
let (tx, rx) = serial.split();
let (mut client, ingress) =
ClientBuilder::new(tx, timer, atat::Config::new(atat::Mode::Timeout)).build(queues);
unsafe { INGRESS = Some(ingress) };
unsafe { RX = Some(rx) };
// configure NVIC interrupts
unsafe { cortex_m::peripheral::NVIC::unmask(hal::stm32::Interrupt::TIM7) };
timer.listen(Event::TimeOut);
// if all goes well you should reach this breakpoint
asm::bkpt();
loop {
asm::wfi();
match client.send(&AT) {
Ok(response) => {
// Do something with response here
}
Err(e) => {}
}
}
}
#[interrupt]
fn TIM7() {
let ingress = unsafe { INGRESS.as_mut().unwrap() };
ingress.digest();
}
#[interrupt]
fn USART2() {
let ingress = unsafe { INGRESS.as_mut().unwrap() };
let rx = unsafe { RX.as_mut().unwrap() };
if let Ok(d) = nb::block!(rx.read()) {
ingress.write(&[d]);
}
}
Optional Cargo Features
derive(enabled by default) - Re-exportsatat_deriveto allow derivingAtat__traits.