1use crate::{
2 command::{
3 error::UbloxError,
4 mobile_control::{
5 types::{Functionality, ResetMode},
6 SetModuleFunctionality,
7 },
8 network_service::{
9 types::OperatorSelectionMode, GetNetworkRegistrationStatus, SetOperatorSelection,
10 },
11 psn::{
12 self, types::PDPContextStatus, GetEPSNetworkRegistrationStatus,
13 GetGPRSNetworkRegistrationStatus, GetPDPContextState, SetPDPContextState,
14 },
15 Urc,
16 },
17 error::GenericError,
18 registration::{self, ConnectionState, RegistrationParams, RegistrationState},
19 services::data::ContextState,
20};
21use atat::{atat_derive::AtatLen, AtatClient};
22use core::convert::TryInto;
23use embedded_time::{duration::*, Clock, TimeError};
24use hash32_derive::Hash32;
25use serde::{Deserialize, Serialize};
26
27const REGISTRATION_CHECK_INTERVAL: Seconds<u32> = Seconds::<u32>(15);
28const REGISTRATION_TIMEOUT: Minutes<u32> = Minutes::<u32>(5);
29
30#[derive(Debug, PartialEq)]
31pub enum Error {
32 Generic(GenericError),
33 AT(atat::Error<UbloxError>),
34 RegistrationDenied,
35 UnknownProfile,
36 ActivationFailed,
37 _Unknown,
38}
39
40impl From<TimeError> for Error {
41 fn from(e: TimeError) -> Self {
42 Error::Generic(e.into())
43 }
44}
45
46#[derive(
47 Debug, Clone, Copy, Eq, PartialEq, Hash32, Serialize, Deserialize, AtatLen, defmt::Format,
48)]
49pub struct ProfileId(pub u8);
50
51#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, AtatLen, defmt::Format)]
52pub struct ContextId(pub u8);
53
54pub struct AtTx<C> {
55 urc_attempts: u8,
56 max_urc_attempts: u8,
57 consecutive_timeouts: u8,
58 client: C,
59}
60
61impl<C: AtatClient> AtTx<C> {
62 pub fn new(client: C, max_urc_attempts: u8) -> Self {
63 Self {
64 urc_attempts: 0,
65 consecutive_timeouts: 0,
66 max_urc_attempts,
67 client,
68 }
69 }
70
71 pub fn reset(&mut self) -> Result<(), Error> {
72 self.client.reset();
73 Ok(())
74 }
75
76 pub fn send_ignore_timeout<A, const LEN: usize>(
77 &mut self,
78 req: &A,
79 ) -> Result<A::Response, Error>
80 where
81 A: atat::AtatCmd<LEN>,
82 A::Error: Into<UbloxError>,
83 {
84 self.client
85 .send(req)
86 .map_err(|e| match e {
87 nb::Error::Other(ate) => {
88 if !matches!(ate, atat::Error::Timeout) {
91 }
93
94 match ate {
95 atat::Error::Error(ubx) => {
96 let u: UbloxError = ubx.into();
97 Error::AT(atat::Error::Error(u))
98 }
99 atat::Error::Timeout => {
100 self.consecutive_timeouts += 1;
101 Error::AT(atat::Error::Timeout)
102 }
103 atat::Error::Read => Error::AT(atat::Error::Read),
104 atat::Error::Write => Error::AT(atat::Error::Write),
105 atat::Error::InvalidResponse => Error::AT(atat::Error::InvalidResponse),
106 atat::Error::Aborted => Error::AT(atat::Error::Aborted),
107 atat::Error::Overflow => Error::AT(atat::Error::Overflow),
108 atat::Error::Parse => Error::AT(atat::Error::Parse),
109 }
110 }
111 nb::Error::WouldBlock => Error::_Unknown,
112 })
113 .map(|res| {
114 self.consecutive_timeouts = 0;
115 res
116 })
117 }
118
119 pub fn send<A, const LEN: usize>(&mut self, req: &A) -> Result<A::Response, Error>
120 where
121 A: atat::AtatCmd<LEN>,
122 A::Error: Into<UbloxError>,
123 {
124 self.client
125 .send(req)
126 .map_err(|e| match e {
127 nb::Error::Other(ate) => {
128 match ate {
132 atat::Error::Error(ubx) => {
133 let u: UbloxError = ubx.into();
134 Error::AT(atat::Error::Error(u))
135 }
136 atat::Error::Timeout => {
137 self.consecutive_timeouts += 1;
138 Error::AT(atat::Error::Timeout)
139 }
140 atat::Error::Read => Error::AT(atat::Error::Read),
141 atat::Error::Write => Error::AT(atat::Error::Write),
142 atat::Error::InvalidResponse => Error::AT(atat::Error::InvalidResponse),
143 atat::Error::Aborted => Error::AT(atat::Error::Aborted),
144 atat::Error::Overflow => Error::AT(atat::Error::Overflow),
145 atat::Error::Parse => Error::AT(atat::Error::Parse),
146 }
147 }
148 nb::Error::WouldBlock => Error::_Unknown,
149 })
150 .map(|res| {
151 self.consecutive_timeouts = 0;
152 res
153 })
154 }
155
156 pub fn handle_urc<F: FnOnce(Urc) -> bool>(&mut self, f: F) -> Result<(), Error> {
157 let mut a = self.urc_attempts;
158 let max = self.max_urc_attempts;
159
160 self.client.peek_urc_with::<Urc, _>(|urc| {
161 if !f(urc.clone()) {
162 if a < max {
163 a += 1;
164 return false;
165 }
168 }
169 a = 0;
170 true
171 });
172 self.urc_attempts = a;
173 Ok(())
174 }
175}
176
177pub struct Network<C, CLK>
178where
179 CLK: Clock,
180{
181 pub(crate) status: RegistrationState<CLK>,
182 pub(crate) context_state: ContextState,
183 pub(crate) at_tx: AtTx<C>,
184}
185
186impl<C, CLK> Network<C, CLK>
187where
188 C: AtatClient,
189 CLK: Clock,
190{
191 pub(crate) fn new(at_tx: AtTx<C>, timer: CLK) -> Self {
192 Network {
193 status: RegistrationState::new(timer),
194 context_state: ContextState::Setup,
195 at_tx,
196 }
197 }
198
199 pub fn is_connected(&self) -> Result<bool, Error> {
200 Ok(matches!(self.status.conn_state, ConnectionState::Connected))
201 }
202
203 pub fn reset_reg_time(&mut self) -> Result<(), Error> {
204 let now = self.status.timer.try_now().map_err(TimeError::from)?;
205
206 self.status.reg_start_time.replace(now);
207 self.status.reg_check_time = self.status.reg_start_time;
208 Ok(())
209 }
210
211 pub fn process_events(&mut self) -> Result<(), Error>
212 where
213 Generic<CLK::T>: TryInto<Milliseconds>,
214 {
215 if self.at_tx.consecutive_timeouts > 10 {
216 defmt::warn!("Resetting the modem due to consecutive AT timeouts");
217 return Err(Error::Generic(GenericError::Timeout));
218 }
219
220 self.handle_urc()?;
221 self.check_registration_state()?;
222 self.intervene_registration()?;
223 let now = self.status.timer.try_now().map_err(TimeError::from)?;
226 let should_check = self
227 .status
228 .reg_check_time
229 .and_then(|ref reg_check_time| {
230 now.checked_duration_since(reg_check_time)
231 .and_then(|dur| dur.try_into().ok())
232 .map(|dur| dur >= REGISTRATION_CHECK_INTERVAL)
233 })
234 .unwrap_or(true);
235
236 if self.status.conn_state != ConnectionState::Connecting || !should_check {
237 return Ok(());
238 }
239
240 self.status.reg_check_time.replace(now);
241
242 self.update_registration()?;
243
244 let now = self.status.timer.try_now().map_err(TimeError::from)?;
245 let is_timeout = self
246 .status
247 .reg_start_time
248 .and_then(|ref reg_start_time| {
249 now.checked_duration_since(reg_start_time)
250 .and_then(|dur| dur.try_into().ok())
251 .map(|dur| dur >= REGISTRATION_TIMEOUT)
252 })
253 .unwrap_or(false);
254
255 if self.status.conn_state == ConnectionState::Connecting && is_timeout {
256 defmt::warn!("Resetting the modem due to the network registration timeout");
257
258 return Err(Error::Generic(GenericError::Timeout));
259 }
260 Ok(())
261 }
262
263 pub fn check_registration_state(&mut self) -> Result<(), Error> {
264 if self.status.conn_state == ConnectionState::Disconnected {
266 return Ok(());
267 }
268
269 if (self.status.csd.registered() && self.status.psd.registered())
271 || self.status.eps.registered()
272 {
273 self.status.set_connection_state(ConnectionState::Connected);
274 } else if self.status.conn_state == ConnectionState::Connected {
275 self.status.reset();
278 self.status
279 .set_connection_state(ConnectionState::Connecting);
280 }
281
282 Ok(())
283 }
284
285 pub fn intervene_registration(&mut self) -> Result<(), Error>
286 where
287 Generic<CLK::T>: TryInto<Milliseconds>,
288 {
289 if self.status.conn_state != ConnectionState::Connecting {
290 return Ok(());
291 }
292
293 let now = self.status.timer.try_now().map_err(TimeError::from)?;
294
295 let timeout = Seconds(self.status.registration_interventions * 15);
297 if self.status.eps.sticky() && self.status.eps.duration(now) >= timeout {
298 if self.status.eps.get_status() == registration::Status::NotRegistering
300 && self.status.csd.get_status() == registration::Status::NotRegistering
301 {
302 defmt::debug!(
303 "Sticky not registering state for {} s, PLMN reselection",
304 Seconds::<u32>::from(self.status.eps.duration(now)).integer()
305 );
306
307 self.status.csd.reset();
308 self.status.psd.reset();
309 self.status.eps.reset();
310 self.status.registration_interventions += 1;
311 self.send_internal(
312 &SetOperatorSelection {
313 mode: OperatorSelectionMode::Automatic,
314 format: Some(2),
315 },
316 false,
317 )
318 .ok();
319 return Ok(());
320
321 } else if self.status.eps.get_status() == registration::Status::Denied
323 && self.status.csd.get_status() == registration::Status::Denied
324 {
325 defmt::debug!(
326 "Sticky denied state for {} s, RF reset",
327 Seconds::<u32>::from(self.status.eps.duration(now)).integer()
328 );
329 self.status.csd.reset();
330 self.status.psd.reset();
331 self.status.eps.reset();
332 self.status.registration_interventions += 1;
333 self.send_internal(
334 &SetModuleFunctionality {
335 fun: Functionality::Minimum,
336 rst: Some(ResetMode::DontReset),
337 },
338 false,
339 )?;
340 self.send_internal(
341 &SetModuleFunctionality {
342 fun: Functionality::Full,
343 rst: Some(ResetMode::DontReset),
344 },
345 false,
346 )?;
347 return Ok(());
348 }
349 }
350
351 if self.status.csd.sticky()
354 && self.status.csd.duration(now) >= timeout
355 && self.status.csd.get_status() == registration::Status::Denied
356 && self.status.psd.get_status() == registration::Status::Denied
357 {
358 defmt::debug!(
359 "Sticky CSD and PSD denied state for {} s, RF reset",
360 Seconds::<u32>::from(self.status.csd.duration(now)).integer()
361 );
362 self.status.csd.reset();
363 self.status.psd.reset();
364 self.status.eps.reset();
365 self.status.registration_interventions += 1;
366 self.send_internal(
367 &SetModuleFunctionality {
368 fun: Functionality::Minimum,
369 rst: Some(ResetMode::DontReset),
370 },
371 false,
372 )?;
373 self.send_internal(
374 &SetModuleFunctionality {
375 fun: Functionality::Full,
376 rst: Some(ResetMode::DontReset),
377 },
378 false,
379 )?;
380 return Ok(());
381 }
382
383 if self.status.csd.registered()
386 && self.status.psd.sticky()
387 && self.status.psd.duration(now) >= timeout
388 && self.status.psd.get_status() == registration::Status::NotRegistering
389 && self.status.eps.get_status() == registration::Status::NotRegistering
390 {
391 defmt::debug!(
392 "Sticky not registering PSD state for {} s, force GPRS attach",
393 Seconds::<u32>::from(self.status.psd.duration(now)).integer()
394 );
395 self.status.psd.reset();
396 self.status.registration_interventions += 1;
397 self.send_internal(&GetPDPContextState, true)?;
398
399 if self
400 .send_internal(
401 &SetPDPContextState {
402 status: PDPContextStatus::Activated,
403 cid: None,
404 },
405 true,
406 )
407 .is_err()
408 {
409 self.status.csd.reset();
410 self.status.psd.reset();
411 self.status.eps.reset();
412 defmt::warn!("GPRS attach failed, try PLMN reselection");
413 self.send_internal(
414 &SetOperatorSelection {
415 mode: OperatorSelectionMode::Automatic,
416 format: Some(2),
417 },
418 true,
419 )?;
420 }
421 }
422
423 Ok(())
424 }
425
426 pub fn update_registration(&mut self) -> Result<(), Error> {
427 let ts = self.status.timer.try_now().map_err(TimeError::from)?;
428
429 if let Ok(reg) = self.send_internal(&GetNetworkRegistrationStatus, false) {
430 self.status.compare_and_set(reg.into(), ts);
431 }
432
433 if let Ok(reg) = self.send_internal(&GetGPRSNetworkRegistrationStatus, false) {
434 self.status.compare_and_set(reg.into(), ts);
435 }
436
437 if let Ok(reg) = self.send_internal(&GetEPSNetworkRegistrationStatus, false) {
438 self.status.compare_and_set(reg.into(), ts);
439 }
440
441 Ok(())
442 }
443
444 pub(crate) fn handle_urc(&mut self) -> Result<(), Error> {
445 let mut ctx_state = self.context_state;
447 let mut new_reg_params: Option<RegistrationParams> = None;
448
449 self.at_tx.handle_urc(|urc| {
450 match urc {
451 Urc::NetworkDetach => {
452 defmt::warn!("Network Detach URC!");
453 }
454 Urc::MobileStationDetach => {
455 defmt::warn!("ME Detach URC!");
456 }
457 Urc::NetworkDeactivate => {
458 defmt::warn!("Network Deactivate URC!");
459 }
460 Urc::MobileStationDeactivate => {
461 defmt::warn!("ME Deactivate URC!");
462 }
463 Urc::NetworkPDNDeactivate => {
464 defmt::warn!("Network PDN Deactivate URC!");
465 }
466 Urc::MobileStationPDNDeactivate => {
467 defmt::warn!("ME PDN Deactivate URC!");
468 }
469 Urc::ExtendedPSNetworkRegistration(psn::urc::ExtendedPSNetworkRegistration {
470 state,
471 }) => {
472 defmt::info!("[URC] ExtendedPSNetworkRegistration {}", state);
473 }
474 Urc::GPRSNetworkRegistration(reg_params) => {
475 new_reg_params.replace(reg_params.into());
476 }
477 Urc::EPSNetworkRegistration(reg_params) => {
478 new_reg_params.replace(reg_params.into());
479 }
480 Urc::NetworkRegistration(reg_params) => {
481 new_reg_params.replace(reg_params.into());
482 }
483 Urc::DataConnectionActivated(psn::urc::DataConnectionActivated {
484 result,
485 ip_addr: _,
486 }) => {
487 defmt::info!("[URC] DataConnectionActivated {=u8}", result);
488 ctx_state = ContextState::Active;
489 }
490 Urc::DataConnectionDeactivated(psn::urc::DataConnectionDeactivated {
491 profile_id,
492 }) => {
493 defmt::info!("[URC] DataConnectionDeactivated {}", profile_id);
494 ctx_state = ContextState::Activating;
495 }
496 Urc::MessageWaitingIndication(_) => {
497 defmt::info!("[URC] MessageWaitingIndication");
498 }
499 _ => return false,
500 };
501 true
502 })?;
503
504 if let Some(reg_params) = new_reg_params {
505 let ts = self.status.timer.try_now().map_err(TimeError::from)?;
506 self.status.compare_and_set(reg_params, ts)
507 }
508
509 self.context_state = ctx_state;
510 Ok(())
511 }
512
513 pub(crate) fn send_internal<A, const LEN: usize>(
514 &mut self,
515 req: &A,
516 check_urc: bool,
517 ) -> Result<A::Response, Error>
518 where
519 A: atat::AtatCmd<LEN>,
520 A::Error: Into<UbloxError>,
521 {
522 if check_urc {
523 if let Err(e) = self.handle_urc() {
524 defmt::error!("Failed handle URC {}", defmt::Debug2Format(&e));
525 }
526 }
527
528 self.at_tx.send(req)
529 }
530}
531
532#[cfg(test)]
533mod tests {
534 use embedded_time::{duration::*, Instant};
535
536 use crate::{
537 registration::Status,
538 test_helpers::{MockAtClient, MockTimer},
539 };
540
541 use super::*;
542
543 #[test]
544 #[ignore]
545 fn intervene_registration() {
546 let tx = AtTx::new(MockAtClient::new(0), 5);
548 let timer = MockTimer::new(Some(25_234));
549 let mut network = Network::new(tx, timer);
550 network.status.conn_state = ConnectionState::Connecting;
551 network
553 .status
554 .eps
555 .set_status(Status::NotRegistering, Instant::new(1234));
556 network
558 .status
559 .eps
560 .set_status(Status::NotRegistering, Instant::new(1534));
561 network
562 .status
563 .csd
564 .set_status(Status::NotRegistering, Instant::new(1534));
565
566 assert_eq!(network.status.eps.updated(), Some(Instant::new(1534)));
567 assert_eq!(network.status.eps.started(), Some(Instant::new(1234)));
568 assert!(network.status.eps.sticky());
569
570 let ts = network.status.timer.try_now().unwrap();
571 assert_eq!(network.status.eps.duration(ts), Milliseconds(24_000_u32));
572
573 assert!(network.intervene_registration().is_ok());
574
575 assert_eq!(network.status.registration_interventions, 2);
576 }
577
578 #[test]
579 fn reset_reg_time() {
580 let tx = AtTx::new(MockAtClient::new(0), 5);
581 let timer = MockTimer::new(Some(1234));
582 let mut network = Network::new(tx, timer);
583
584 assert!(network.reset_reg_time().is_ok());
585
586 assert_eq!(network.status.reg_start_time, Some(Instant::new(1234)));
587 assert_eq!(network.status.reg_check_time, Some(Instant::new(1234)));
588 }
589
590 #[test]
591 fn check_registration_state() {
592 let tx = AtTx::new(MockAtClient::new(0), 5);
593 let timer = MockTimer::new(Some(1234));
594 let mut network = Network::new(tx, timer);
595
596 network.status.conn_state = ConnectionState::Connected;
599 network.status.registration_interventions = 3;
600 network
601 .status
602 .csd
603 .set_status(Status::Denied, Instant::new(1));
604 network
605 .status
606 .eps
607 .set_status(Status::NotRegistering, Instant::new(5));
608
609 assert!(network.check_registration_state().is_ok());
610
611 assert_eq!(network.status.conn_state, ConnectionState::Connecting);
612 assert_eq!(network.status.reg_start_time, Some(Instant::new(1234)));
613 assert_eq!(network.status.reg_check_time, Some(Instant::new(1234)));
614 assert_eq!(network.status.csd.get_status(), Status::None);
615 assert_eq!(network.status.csd.updated(), None);
616 assert_eq!(network.status.csd.started(), None);
617 assert_eq!(network.status.psd.get_status(), Status::None);
618 assert_eq!(network.status.psd.updated(), None);
619 assert_eq!(network.status.psd.started(), None);
620 assert_eq!(network.status.eps.get_status(), Status::None);
621 assert_eq!(network.status.eps.updated(), None);
622 assert_eq!(network.status.eps.started(), None);
623
624 network
627 .status
628 .eps
629 .set_status(Status::Roaming, Instant::new(5));
630
631 assert!(network.check_registration_state().is_ok());
632
633 assert_eq!(network.status.conn_state, ConnectionState::Connected);
634
635 network.status.conn_state = ConnectionState::Connecting;
638 network.status.reset();
639 network
640 .status
641 .eps
642 .set_status(Status::Denied, Instant::new(5));
643 network
644 .status
645 .csd
646 .set_status(Status::Roaming, Instant::new(5));
647 network.status.psd.set_status(Status::Home, Instant::new(5));
648
649 assert!(network.check_registration_state().is_ok());
650
651 assert_eq!(network.status.conn_state, ConnectionState::Connected);
652 }
653
654 #[test]
655 fn unhandled_urcs() {
656 let mut tx = AtTx::new(MockAtClient::new(0), 5);
657
658 tx.handle_urc(|_| false).unwrap();
659 assert_eq!(tx.client.n_urcs_dequeued, 0);
660 tx.handle_urc(|_| false).unwrap();
661 tx.handle_urc(|_| false).unwrap();
662 tx.handle_urc(|_| false).unwrap();
663 tx.handle_urc(|_| false).unwrap();
664 tx.handle_urc(|_| false).unwrap();
665 assert_eq!(tx.client.n_urcs_dequeued, 1);
666 tx.handle_urc(|_| false).unwrap();
667 tx.handle_urc(|_| true).unwrap();
668 tx.handle_urc(|_| false).unwrap();
669 assert_eq!(tx.client.n_urcs_dequeued, 2);
670 }
671}