aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2024-09-04 18:47:26 +0200
committerUlf Lilleengen <[email protected]>2024-09-04 18:47:26 +0200
commit372e45dabc0cfd3eb495e902665bb752a67aa804 (patch)
tree2d8b5aa066c37b73c857a2aa15f8c47dea06edef
parent49881f6fd1e3d77d63dea2313afb5201eca8ebd9 (diff)
Add context run task
-rw-r--r--embassy-net-nrf91/src/context.rs86
-rw-r--r--embassy-net-nrf91/src/lib.rs5
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs93
3 files changed, 137 insertions, 47 deletions
diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs
index 954830417..f73719224 100644
--- a/embassy-net-nrf91/src/context.rs
+++ b/embassy-net-nrf91/src/context.rs
@@ -5,6 +5,7 @@ use core::str::FromStr;
5use at_commands::builder::CommandBuilder; 5use at_commands::builder::CommandBuilder;
6use at_commands::parser::CommandParser; 6use at_commands::parser::CommandParser;
7use heapless::Vec; 7use heapless::Vec;
8use embassy_time::{Timer, Duration};
8 9
9/// Provides a higher level API for controlling a given context. 10/// Provides a higher level API for controlling a given context.
10pub struct Control<'a> { 11pub struct Control<'a> {
@@ -23,6 +24,8 @@ pub struct Config<'a> {
23} 24}
24 25
25/// Authentication protocol. 26/// Authentication protocol.
27#[derive(Clone, Copy, PartialEq, Debug)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[repr(u8)] 29#[repr(u8)]
27pub enum AuthProt { 30pub enum AuthProt {
28 /// No authentication. 31 /// No authentication.
@@ -84,7 +87,7 @@ impl<'a> Control<'a> {
84 } 87 }
85 88
86 /// Configures the modem with the provided config. 89 /// Configures the modem with the provided config.
87 pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { 90 pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> {
88 let mut cmd: [u8; 256] = [0; 256]; 91 let mut cmd: [u8; 256] = [0; 256];
89 let mut buf: [u8; 256] = [0; 256]; 92 let mut buf: [u8; 256] = [0; 256];
90 93
@@ -118,9 +121,64 @@ impl<'a> Control<'a> {
118 let n = self.control.at_command(op, &mut buf).await; 121 let n = self.control.at_command(op, &mut buf).await;
119 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; 122 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
120 123
124 let op = CommandBuilder::create_set(&mut cmd, true)
125 .named("%XPDNCFG")
126 .with_int_parameter(1)
127 .finish()
128 .map_err(|_| Error::BufferTooSmall)?;
129 let n = self.control.at_command(op, &mut buf).await;
130 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
131
132
133
134 Ok(())
135 }
136
137 /// Attach to the PDN
138 pub async fn attach(&self) -> Result<(), Error> {
139 let mut cmd: [u8; 256] = [0; 256];
140 let mut buf: [u8; 256] = [0; 256];
141 let op = CommandBuilder::create_set(&mut cmd, true)
142 .named("+CGATT")
143 .with_int_parameter(1)
144 .finish()
145 .map_err(|_| Error::BufferTooSmall)?;
146 let n = self.control.at_command(op, &mut buf).await;
147 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
148 Ok(())
149 }
150
151 /// Read current connectivity status for modem.
152 pub async fn detach(&self) -> Result<(), Error> {
153 let mut cmd: [u8; 256] = [0; 256];
154 let mut buf: [u8; 256] = [0; 256];
155 let op = CommandBuilder::create_set(&mut cmd, true)
156 .named("+CGATT")
157 .with_int_parameter(0)
158 .finish()
159 .map_err(|_| Error::BufferTooSmall)?;
160 let n = self.control.at_command(op, &mut buf).await;
161 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
121 Ok(()) 162 Ok(())
122 } 163 }
123 164
165 async fn attached(&self) -> Result<bool, Error> {
166 let mut cmd: [u8; 256] = [0; 256];
167 let mut buf: [u8; 256] = [0; 256];
168
169 let op = CommandBuilder::create_query(&mut cmd, true)
170 .named("+CGATT")
171 .finish()
172 .map_err(|_| Error::BufferTooSmall)?;
173 let n = self.control.at_command(op, &mut buf).await;
174 let (res,) = CommandParser::parse(&buf[..n])
175 .expect_identifier(b"+CGATT: ")
176 .expect_int_parameter()
177 .expect_identifier(b"\r\nOK")
178 .finish()?;
179 Ok(res == 1)
180 }
181
124 /// Read current connectivity status for modem. 182 /// Read current connectivity status for modem.
125 pub async fn status(&self) -> Result<Status, Error> { 183 pub async fn status(&self) -> Result<Status, Error> {
126 let mut cmd: [u8; 256] = [0; 256]; 184 let mut cmd: [u8; 256] = [0; 256];
@@ -162,7 +220,6 @@ impl<'a> Control<'a> {
162 220
163 let ip = if let Some(ip) = ip1 { 221 let ip = if let Some(ip) = ip1 {
164 let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; 222 let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?;
165 self.control.open_raw_socket().await;
166 Some(ip) 223 Some(ip)
167 } else { 224 } else {
168 None 225 None
@@ -219,4 +276,29 @@ impl<'a> Control<'a> {
219 dns, 276 dns,
220 }) 277 })
221 } 278 }
279
280 /// Run a control loop for this context, ensuring that reaattach is handled.
281 pub async fn run<F: Fn(&Status)>(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> {
282 self.configure(config).await?;
283 while !self.attached().await? {
284 Timer::after(Duration::from_secs(1)).await;
285 }
286 let status = self.status().await?;
287 let mut fd = self.control.open_raw_socket().await;
288 reattach(&status);
289
290 loop {
291 if !self.attached().await? {
292 // TODO: self.control.close_raw_socket(fd).await;
293 self.attach().await?;
294 while !self.attached().await? {
295 Timer::after(Duration::from_secs(1)).await;
296 }
297 let status = self.status().await?;
298 // TODO: let mut fd = self.control.open_raw_socket().await;
299 reattach(&status);
300 }
301 Timer::after(Duration::from_secs(10)).await;
302 }
303 }
222} 304}
diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs
index a60e27d97..ab3c6f327 100644
--- a/embassy-net-nrf91/src/lib.rs
+++ b/embassy-net-nrf91/src/lib.rs
@@ -844,7 +844,7 @@ impl<'a> Control<'a> {
844 /// Open the raw socket used for sending/receiving IP packets. 844 /// Open the raw socket used for sending/receiving IP packets.
845 /// 845 ///
846 /// This must be done after `AT+CFUN=1` (?) 846 /// This must be done after `AT+CFUN=1` (?)
847 async fn open_raw_socket(&self) { 847 async fn open_raw_socket(&self) -> u32 {
848 let mut msg: Message = unsafe { mem::zeroed() }; 848 let mut msg: Message = unsafe { mem::zeroed() };
849 msg.channel = 2; // data 849 msg.channel = 2; // data
850 msg.id = 0x7001_0004; // open socket 850 msg.id = 0x7001_0004; // open socket
@@ -867,7 +867,8 @@ impl<'a> Control<'a> {
867 assert_eq!(status, 0); 867 assert_eq!(status, 0);
868 assert_eq!(msg.param_len, 16); 868 assert_eq!(msg.param_len, 16);
869 let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); 869 let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap());
870 debug!("got FD: {}", fd); 870 trace!("got FD: {}", fd);
871 fd
871 } 872 }
872} 873}
873 874
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs
index c65e6e153..a6f42eb3b 100644
--- a/examples/nrf9160/src/bin/modem_tcp_client.rs
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -50,6 +50,43 @@ async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>)
50} 50}
51 51
52#[embassy_executor::task] 52#[embassy_executor::task]
53async fn control_task(
54 control: &'static context::Control<'static>,
55 config: context::Config<'static>,
56 stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>,
57) {
58 unwrap!(
59 control
60 .run(&config, |status| {
61 let Some(IpAddr::V4(addr)) = status.ip else {
62 panic!("Unexpected IP address");
63 };
64 let addr = Ipv4Address(addr.octets());
65
66 let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
67 Some(Ipv4Address(addr.octets()))
68 } else {
69 None
70 };
71
72 let mut dns_servers = Vec::new();
73 for dns in status.dns.iter() {
74 if let IpAddr::V4(ip) = dns {
75 unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
76 }
77 }
78
79 stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
80 address: Ipv4Cidr::new(addr, 32),
81 gateway,
82 dns_servers,
83 }));
84 })
85 .await
86 );
87}
88
89#[embassy_executor::task]
53async fn blink_task(pin: AnyPin) { 90async fn blink_task(pin: AnyPin) {
54 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); 91 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
55 loop { 92 loop {
@@ -117,50 +154,20 @@ async fn main(spawner: Spawner) {
117 154
118 unwrap!(spawner.spawn(net_task(stack))); 155 unwrap!(spawner.spawn(net_task(stack)));
119 156
120 let control = context::Control::new(control, 0).await; 157 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
158 let control = CONTROL.init(context::Control::new(control, 0).await);
121 159
122 unwrap!( 160 unwrap!(spawner.spawn(control_task(
123 control 161 control,
124 .configure(context::Config { 162 context::Config {
125 apn: "iot.nat.es", 163 apn: "iot.nat.es",
126 auth_prot: context::AuthProt::Pap, 164 auth_prot: context::AuthProt::Pap,
127 auth: Some(("orange", "orange")), 165 auth: Some(("orange", "orange")),
128 }) 166 },
129 .await 167 stack
130 ); 168 )));
131 169
132 info!("waiting for attach..."); 170 stack.wait_config_up().await;
133
134 let mut status = unwrap!(control.status().await);
135 while !status.attached && status.ip.is_none() {
136 Timer::after_millis(1000).await;
137 status = unwrap!(control.status().await);
138 info!("STATUS: {:?}", status);
139 }
140
141 let Some(IpAddr::V4(addr)) = status.ip else {
142 panic!("Unexpected IP address");
143 };
144 let addr = Ipv4Address(addr.octets());
145
146 let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
147 Some(Ipv4Address(addr.octets()))
148 } else {
149 None
150 };
151
152 let mut dns_servers = Vec::new();
153 for dns in status.dns {
154 if let IpAddr::V4(ip) = dns {
155 unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
156 }
157 }
158
159 stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
160 address: Ipv4Cidr::new(addr, 32),
161 gateway,
162 dns_servers,
163 }));
164 171
165 let mut rx_buffer = [0; 4096]; 172 let mut rx_buffer = [0; 4096];
166 let mut tx_buffer = [0; 4096]; 173 let mut tx_buffer = [0; 4096];
@@ -172,7 +179,7 @@ async fn main(spawner: Spawner) {
172 let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); 179 let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
173 if let Err(e) = socket.connect((host_addr, 4242)).await { 180 if let Err(e) = socket.connect((host_addr, 4242)).await {
174 warn!("connect error: {:?}", e); 181 warn!("connect error: {:?}", e);
175 Timer::after_secs(1).await; 182 Timer::after_secs(10).await;
176 continue; 183 continue;
177 } 184 }
178 info!("Connected to {:?}", socket.remote_endpoint()); 185 info!("Connected to {:?}", socket.remote_endpoint());