Add context run task
This commit is contained in:
parent
49881f6fd1
commit
372e45dabc
@ -5,6 +5,7 @@ use core::str::FromStr;
|
|||||||
use at_commands::builder::CommandBuilder;
|
use at_commands::builder::CommandBuilder;
|
||||||
use at_commands::parser::CommandParser;
|
use at_commands::parser::CommandParser;
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
use embassy_time::{Timer, Duration};
|
||||||
|
|
||||||
/// Provides a higher level API for controlling a given context.
|
/// Provides a higher level API for controlling a given context.
|
||||||
pub struct Control<'a> {
|
pub struct Control<'a> {
|
||||||
@ -23,6 +24,8 @@ pub struct Config<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Authentication protocol.
|
/// Authentication protocol.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum AuthProt {
|
pub enum AuthProt {
|
||||||
/// No authentication.
|
/// No authentication.
|
||||||
@ -84,7 +87,7 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the modem with the provided config.
|
/// Configures the modem with the provided config.
|
||||||
pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> {
|
pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> {
|
||||||
let mut cmd: [u8; 256] = [0; 256];
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
let mut buf: [u8; 256] = [0; 256];
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
@ -118,9 +121,64 @@ impl<'a> Control<'a> {
|
|||||||
let n = self.control.at_command(op, &mut buf).await;
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("%XPDNCFG")
|
||||||
|
.with_int_parameter(1)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attach to the PDN
|
||||||
|
pub async fn attach(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.with_int_parameter(1)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read current connectivity status for modem.
|
||||||
|
pub async fn detach(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.with_int_parameter(0)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn attached(&self) -> Result<bool, Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_query(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
let (res,) = CommandParser::parse(&buf[..n])
|
||||||
|
.expect_identifier(b"+CGATT: ")
|
||||||
|
.expect_int_parameter()
|
||||||
|
.expect_identifier(b"\r\nOK")
|
||||||
|
.finish()?;
|
||||||
|
Ok(res == 1)
|
||||||
|
}
|
||||||
|
|
||||||
/// Read current connectivity status for modem.
|
/// Read current connectivity status for modem.
|
||||||
pub async fn status(&self) -> Result<Status, Error> {
|
pub async fn status(&self) -> Result<Status, Error> {
|
||||||
let mut cmd: [u8; 256] = [0; 256];
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
@ -162,7 +220,6 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
let ip = if let Some(ip) = ip1 {
|
let ip = if let Some(ip) = ip1 {
|
||||||
let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?;
|
let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?;
|
||||||
self.control.open_raw_socket().await;
|
|
||||||
Some(ip)
|
Some(ip)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -219,4 +276,29 @@ impl<'a> Control<'a> {
|
|||||||
dns,
|
dns,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run a control loop for this context, ensuring that reaattach is handled.
|
||||||
|
pub async fn run<F: Fn(&Status)>(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> {
|
||||||
|
self.configure(config).await?;
|
||||||
|
while !self.attached().await? {
|
||||||
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
let status = self.status().await?;
|
||||||
|
let mut fd = self.control.open_raw_socket().await;
|
||||||
|
reattach(&status);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !self.attached().await? {
|
||||||
|
// TODO: self.control.close_raw_socket(fd).await;
|
||||||
|
self.attach().await?;
|
||||||
|
while !self.attached().await? {
|
||||||
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
let status = self.status().await?;
|
||||||
|
// TODO: let mut fd = self.control.open_raw_socket().await;
|
||||||
|
reattach(&status);
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_secs(10)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -844,7 +844,7 @@ impl<'a> Control<'a> {
|
|||||||
/// Open the raw socket used for sending/receiving IP packets.
|
/// Open the raw socket used for sending/receiving IP packets.
|
||||||
///
|
///
|
||||||
/// This must be done after `AT+CFUN=1` (?)
|
/// This must be done after `AT+CFUN=1` (?)
|
||||||
async fn open_raw_socket(&self) {
|
async fn open_raw_socket(&self) -> u32 {
|
||||||
let mut msg: Message = unsafe { mem::zeroed() };
|
let mut msg: Message = unsafe { mem::zeroed() };
|
||||||
msg.channel = 2; // data
|
msg.channel = 2; // data
|
||||||
msg.id = 0x7001_0004; // open socket
|
msg.id = 0x7001_0004; // open socket
|
||||||
@ -867,7 +867,8 @@ impl<'a> Control<'a> {
|
|||||||
assert_eq!(status, 0);
|
assert_eq!(status, 0);
|
||||||
assert_eq!(msg.param_len, 16);
|
assert_eq!(msg.param_len, 16);
|
||||||
let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap());
|
let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap());
|
||||||
debug!("got FD: {}", fd);
|
trace!("got FD: {}", fd);
|
||||||
|
fd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,43 @@ async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>)
|
|||||||
stack.run().await
|
stack.run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn control_task(
|
||||||
|
control: &'static context::Control<'static>,
|
||||||
|
config: context::Config<'static>,
|
||||||
|
stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>,
|
||||||
|
) {
|
||||||
|
unwrap!(
|
||||||
|
control
|
||||||
|
.run(&config, |status| {
|
||||||
|
let Some(IpAddr::V4(addr)) = status.ip else {
|
||||||
|
panic!("Unexpected IP address");
|
||||||
|
};
|
||||||
|
let addr = Ipv4Address(addr.octets());
|
||||||
|
|
||||||
|
let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
|
||||||
|
Some(Ipv4Address(addr.octets()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dns_servers = Vec::new();
|
||||||
|
for dns in status.dns.iter() {
|
||||||
|
if let IpAddr::V4(ip) = dns {
|
||||||
|
unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
|
||||||
|
address: Ipv4Cidr::new(addr, 32),
|
||||||
|
gateway,
|
||||||
|
dns_servers,
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn blink_task(pin: AnyPin) {
|
async fn blink_task(pin: AnyPin) {
|
||||||
let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
|
let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
|
||||||
@ -117,50 +154,20 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
unwrap!(spawner.spawn(net_task(stack)));
|
unwrap!(spawner.spawn(net_task(stack)));
|
||||||
|
|
||||||
let control = context::Control::new(control, 0).await;
|
static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
|
||||||
|
let control = CONTROL.init(context::Control::new(control, 0).await);
|
||||||
|
|
||||||
unwrap!(
|
unwrap!(spawner.spawn(control_task(
|
||||||
control
|
control,
|
||||||
.configure(context::Config {
|
context::Config {
|
||||||
apn: "iot.nat.es",
|
apn: "iot.nat.es",
|
||||||
auth_prot: context::AuthProt::Pap,
|
auth_prot: context::AuthProt::Pap,
|
||||||
auth: Some(("orange", "orange")),
|
auth: Some(("orange", "orange")),
|
||||||
})
|
},
|
||||||
.await
|
stack
|
||||||
);
|
)));
|
||||||
|
|
||||||
info!("waiting for attach...");
|
stack.wait_config_up().await;
|
||||||
|
|
||||||
let mut status = unwrap!(control.status().await);
|
|
||||||
while !status.attached && status.ip.is_none() {
|
|
||||||
Timer::after_millis(1000).await;
|
|
||||||
status = unwrap!(control.status().await);
|
|
||||||
info!("STATUS: {:?}", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(IpAddr::V4(addr)) = status.ip else {
|
|
||||||
panic!("Unexpected IP address");
|
|
||||||
};
|
|
||||||
let addr = Ipv4Address(addr.octets());
|
|
||||||
|
|
||||||
let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
|
|
||||||
Some(Ipv4Address(addr.octets()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut dns_servers = Vec::new();
|
|
||||||
for dns in status.dns {
|
|
||||||
if let IpAddr::V4(ip) = dns {
|
|
||||||
unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
|
|
||||||
address: Ipv4Cidr::new(addr, 32),
|
|
||||||
gateway,
|
|
||||||
dns_servers,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 4096];
|
||||||
let mut tx_buffer = [0; 4096];
|
let mut tx_buffer = [0; 4096];
|
||||||
@ -172,7 +179,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
|
let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
|
||||||
if let Err(e) = socket.connect((host_addr, 4242)).await {
|
if let Err(e) = socket.connect((host_addr, 4242)).await {
|
||||||
warn!("connect error: {:?}", e);
|
warn!("connect error: {:?}", e);
|
||||||
Timer::after_secs(1).await;
|
Timer::after_secs(10).await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
info!("Connected to {:?}", socket.remote_endpoint());
|
info!("Connected to {:?}", socket.remote_endpoint());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user