Skip to content

Commit

Permalink
Fix parsing CGEV urc and act upon PDP context losses & network loss
Browse files Browse the repository at this point in the history
  • Loading branch information
MathiasKoch committed Jul 26, 2023
1 parent dd4162b commit 6d22c5f
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 67 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ members = [
]

[patch.crates-io]
atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be" }
atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "1222a92" }
# ublox-sockets = { path = "../ublox-sockets" }
2 changes: 1 addition & 1 deletion ublox-cellular/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ doctest = false

[dependencies]
# atat = { version = "0.18", features = ["derive", "bytes"] }
atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = ["derive", "defmt", "bytes"] }
atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "1222a92", features = ["derive", "defmt", "bytes"] }
embedded-hal = "=1.0.0-alpha.11"
embedded-nal = "0.6"
fugit = { version = "0.3" }
Expand Down
30 changes: 13 additions & 17 deletions ublox-cellular/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,22 +543,14 @@ where
}

pub(crate) fn enable_registration_urcs(&mut self) -> Result<(), Error> {
// if packet domain event reporting is not set it's not a stopper. We
// might lack some events when we are dropped from the network.
// TODO: Re-enable this when it works, and is useful!
if self
.network
.send_internal(
&SetPacketSwitchedEventReporting {
mode: PSEventReportingMode::CircularBufferUrcs,
bfr: None,
},
true,
)
.is_err()
{
warn!("Packet domain event reporting set failed");
}
// Report all registration and PDN connectivity status events.
self.network.send_internal(
&SetPacketSwitchedEventReporting {
mode: PSEventReportingMode::BufferUrcs,
bfr: Some(1),
},
true,
)?;

// CREG URC
self.network.send_internal(
Expand Down Expand Up @@ -635,10 +627,14 @@ where
match self.network.process_events() {
// Catch "Resetting the modem due to the network registration timeout"
// as well as consecutive AT timeouts and do a hard reset.
Err(crate::network::Error::Generic(GenericError::Timeout)) => {
Err(crate::network::Error::Generic(GenericError::AtErrors)) => {
self.hard_reset()?;
Err(Error::Generic(GenericError::Timeout))
}
Err(crate::network::Error::Generic(GenericError::Timeout)) => {
self.soft_reset(false)?;
Err(Error::Generic(GenericError::Timeout))
}
result => result.map_err(Error::from),
}
}
Expand Down
14 changes: 2 additions & 12 deletions ublox-cellular/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,8 @@ pub struct AT;

#[derive(Debug, Clone, AtatUrc)]
pub enum Urc {
#[at_urc("+CGEV: NW DETACH")]
NetworkDetach,
#[at_urc("+CGEV: ME DETACH")]
MobileStationDetach,
#[at_urc("+CGEV: NW DEACT")]
NetworkDeactivate,
#[at_urc("+CGEV: ME DEACT")]
MobileStationDeactivate,
#[at_urc("+CGEV: NW PDN DEACT")]
NetworkPDNDeactivate,
#[at_urc("+CGEV: ME PDN DEACT")]
MobileStationPDNDeactivate,
#[at_urc("+CGEV")]
PacketSwitchedEventReporting(psn::urc::PacketSwitchedEventReporting),

#[at_urc("+UUSORD")]
SocketDataAvailable(ip_transport_layer::urc::SocketDataAvailable),
Expand Down
181 changes: 181 additions & 0 deletions ublox-cellular/src/command/psn/impl_.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use super::urc::PacketSwitchedEventReporting;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

impl Serialize for PacketSwitchedEventReporting {
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Self::NetworkDetach => Serializer::serialize_bytes(serializer, b"NW DETACH"),
Self::MobileStationDetach => Serializer::serialize_bytes(serializer, b"ME DETACH"),
Self::NetworkDeactivate => Serializer::serialize_bytes(serializer, b"NW DEACT"),
Self::MobileStationDeactivate => Serializer::serialize_bytes(serializer, b"ME DEACT"),
Self::NetworkPDNDeactivate => Serializer::serialize_bytes(serializer, b"NW PDN DEACT"),
Self::MobileStationPDNDeactivate => {
Serializer::serialize_bytes(serializer, b"ME PDN DEACT")
}
}
}
}

impl<'de> Deserialize<'de> for PacketSwitchedEventReporting {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[allow(non_camel_case_types)]
enum Field {
NetworkDetach,
MobileStationDetach,
NetworkDeactivate,
MobileStationDeactivate,
NetworkPDNDeactivate,
MobileStationPDNDeactivate,
}
struct FieldVisitor;

impl<'de> de::Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Formatter::write_str(formatter, "variant identifier")
}

fn visit_bytes<E>(self, value: &[u8]) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
match value {
b"NW DETACH" => Ok(Field::NetworkDetach),
b"ME DETACH" => Ok(Field::MobileStationDetach),
b"NW DEACT" => Ok(Field::NetworkDeactivate),
b"ME DEACT" => Ok(Field::MobileStationDeactivate),
b"NW PDN DEACT" => Ok(Field::NetworkPDNDeactivate),
b"ME PDN DEACT" => Ok(Field::MobileStationPDNDeactivate),
_ => {
let value =
core::str::from_utf8(value).unwrap_or("\u{fffd}\u{fffd}\u{fffd}");
Err(de::Error::unknown_variant(value, VARIANTS))
}
}
}
}

impl<'de> Deserialize<'de> for Field {
#[inline]
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserializer::deserialize_identifier(deserializer, FieldVisitor)
}
}
struct Visitor<'de> {
marker: core::marker::PhantomData<PacketSwitchedEventReporting>,
lifetime: core::marker::PhantomData<&'de ()>,
}
impl<'de> de::Visitor<'de> for Visitor<'de> {
type Value = PacketSwitchedEventReporting;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Formatter::write_str(formatter, "enum PacketSwitchedEventReporting")
}

fn visit_enum<A>(self, data: A) -> core::result::Result<Self::Value, A::Error>
where
A: de::EnumAccess<'de>,
{
Ok(match de::EnumAccess::variant(data)? {
(Field::NetworkDetach, _) => PacketSwitchedEventReporting::NetworkDetach,
(Field::MobileStationDetach, _) => {
PacketSwitchedEventReporting::MobileStationDetach
}
(Field::NetworkDeactivate, _) => {
PacketSwitchedEventReporting::NetworkDeactivate
}
(Field::MobileStationDeactivate, _) => {
PacketSwitchedEventReporting::MobileStationDeactivate
}
(Field::NetworkPDNDeactivate, _) => {
PacketSwitchedEventReporting::NetworkPDNDeactivate
}
(Field::MobileStationPDNDeactivate, _) => {
PacketSwitchedEventReporting::MobileStationPDNDeactivate
}
})
}
}
const VARIANTS: &[&str] = &[
"NW DETACH",
"ME DETACH",
"NW DEACT",
"ME DEACT",
"NW PDN DEACT",
"ME PDN DEACT",
];
Deserializer::deserialize_enum(
deserializer,
"PacketSwitchedEventReporting",
VARIANTS,
Visitor {
marker: core::marker::PhantomData::<Self>,
lifetime: core::marker::PhantomData,
},
)
}
}

#[cfg(test)]
mod test {
use crate::command::Urc;

use super::*;
use atat::serde_at::de::from_str;
use atat::serde_at::ser::to_string;
use atat::AtatUrc;
use heapless::String;

#[test]
fn serialize_me_detach() {
let options = atat::serde_at::SerializeOptions {
value_sep: false,
..atat::serde_at::SerializeOptions::default()
};
let s = to_string::<_, 32>(
&PacketSwitchedEventReporting::MobileStationDetach,
"",
options,
)
.unwrap();

assert_eq!(s, String::<32>::from("ME DETACH"))
}

#[test]
fn deserialize_packet_switched_event() {
assert_eq!(
from_str("ME DETACH\r\n"),
Ok(PacketSwitchedEventReporting::MobileStationDetach)
);

assert_eq!(
from_str("NW PDN DEACT\r\n"),
Ok(PacketSwitchedEventReporting::NetworkPDNDeactivate)
);

assert_eq!(
from_str("NW DETACH\r\n"),
Ok(PacketSwitchedEventReporting::NetworkDetach)
);
}

#[test]
fn deserialize_packet_switched_event_urc() {
let urc = Urc::parse(b"+CGEV: ME DETACH\r\n").unwrap();
if !matches!(
urc,
Urc::PacketSwitchedEventReporting(PacketSwitchedEventReporting::MobileStationDetach),
) {
panic!()
}
}
}
1 change: 1 addition & 0 deletions ublox-cellular/src/command/psn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//! instruct the GGSN to route down-link packets onto different `QoS` flows
//! towards the TE.

pub mod impl_;
pub mod responses;
pub mod types;
pub mod urc;
Expand Down
11 changes: 11 additions & 0 deletions ublox-cellular/src/command/psn/urc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,14 @@ pub struct EPSNetworkRegistration {
#[at_arg(position = 6)]
pub reject_cause: Option<u8>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PacketSwitchedEventReporting {
NetworkDetach,
MobileStationDetach,
NetworkDeactivate,
MobileStationDeactivate,
NetworkPDNDeactivate,
MobileStationPDNDeactivate,
}
1 change: 1 addition & 0 deletions ublox-cellular/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::services::data::Error as DataServiceError;
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum GenericError {
AtErrors,
Timeout,
Clock,
Unsupported,
Expand Down
Loading

0 comments on commit 6d22c5f

Please sign in to comment.