use std::time::Duration;
use std::sync::Arc;
use dbus::{Error, Path};
use dbus::blocking::{Connection, Proxy};
use dbus::blocking::stdintf::org_freedesktop_dbus::ObjectManager;
use dbus::arg::{RefArg, PropMap};
use mmdbus::modem::Modem as ModemAccess;
use mmdbus::modem_signal::ModemSignal;
use mmdbus::modem_modem3gpp::ModemModem3gpp;
use mmdbus::sim::Sim as SimTrait;
const DBUS_NAME: &str = "org.freedesktop.ModemManager1";
const DBUS_PATH: &str = "/org/freedesktop/ModemManager1";
const TIMEOUT: Duration = Duration::from_secs(2);
#[derive(Clone)]
struct Dbus {
conn: Arc<Connection>
}
impl Dbus {
fn connect() -> Result<Self, Error> {
Connection::new_system()
.map(Arc::new)
.map(|conn| Self { conn })
}
fn proxy<'a, 'b>(
&'b self,
path: impl Into<Path<'a>>
) -> Proxy<'a, &'b Connection> {
self.conn.with_proxy(DBUS_NAME, path, TIMEOUT)
}
}
#[derive(Clone)]
pub struct ModemManager {
dbus: Dbus
}
impl ModemManager {
pub fn connect() -> Result<Self, Error> {
Dbus::connect()
.map(|dbus| Self { dbus })
}
pub fn modems(&self) -> Result<Vec<Modem>, Error> {
let objects = self.dbus.proxy(DBUS_PATH).get_managed_objects()?;
let modems = objects.into_iter()
.map(|(path, _)| {
Modem {
dbus: self.dbus.clone(),
path
}
})
.collect();
Ok(modems)
}
}
pub struct Modem {
dbus: Dbus,
path: Path<'static>
}
impl Modem {
pub fn manufacturer(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).manufacturer()
}
pub fn model(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).model()
}
pub fn carrier_configuration(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).carrier_configuration()
}
pub fn device(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).device()
}
pub fn state(&self) -> Result<ModemState, Error> {
self.dbus.proxy(&self.path).state()
.map(Into::into)
}
pub fn access_techs(&self) -> Result<ModemAccessTechs, Error> {
self.dbus.proxy(&self.path).access_technologies()
.map(Into::into)
}
pub fn signal_quality(&self) -> Result<(u32, bool), Error> {
self.dbus.proxy(&self.path).signal_quality()
}
pub fn supported_modes(&self) -> Result<Vec<(ModemMode, ModemMode)>, Error> {
self.dbus.proxy(&self.path).supported_modes()
.map(|v| v.into_iter().map(|(a, b)| (a.into(), b.into())).collect())
}
pub fn current_modes(&self) -> Result<(ModemMode, ModemMode), Error> {
self.dbus.proxy(&self.path).current_modes()
.map(|(a, b)| (a.into(), b.into()))
}
pub fn set_current_modes(
&self,
(allowed, preferred): (ModemMode, ModemMode)
) -> Result<(), Error> {
self.dbus.proxy(&self.path).set_current_modes(
(allowed.into(), preferred.into())
)
}
pub fn supported_bands(&self) -> Result<Vec<ModemBand>, Error> {
self.dbus.proxy(&self.path).supported_bands()
.map(|v| v.into_iter().map(Into::into).collect())
}
pub fn current_bands(&self) -> Result<Vec<ModemBand>, Error> {
self.dbus.proxy(&self.path).current_bands()
.map(|v| v.into_iter().map(Into::into).collect())
}
pub fn set_current_bands(
&self,
bands: &[ModemBand]
) -> Result<(), Error> {
self.dbus.proxy(&self.path).set_current_bands(
bands.into_iter().map(|b| *b as u32).collect()
)
}
pub fn signal_setup(&self, rate: u32) -> Result<(), Error> {
self.dbus.proxy(&self.path).setup(rate)
}
pub fn signal_cdma(&self) -> Result<SignalCdma, Error> {
let data = self.dbus.proxy(&self.path).cdma()?;
SignalCdma::from_prop_map(data)
.ok_or_else(|| Error::new_failed("cdma not found"))
}
pub fn signal_evdo(&self) -> Result<SignalEvdo, Error> {
let data = self.dbus.proxy(&self.path).evdo()?;
SignalEvdo::from_prop_map(data)
.ok_or_else(|| Error::new_failed("evdo not found"))
}
pub fn signal_gsm(&self) -> Result<SignalGsm, Error> {
let data = self.dbus.proxy(&self.path).gsm()?;
SignalGsm::from_prop_map(data)
.ok_or_else(|| Error::new_failed("gsm not found"))
}
pub fn signal_umts(&self) -> Result<SignalUmts, Error> {
let data = self.dbus.proxy(&self.path).umts()?;
SignalUmts::from_prop_map(data)
.ok_or_else(|| Error::new_failed("umts not found"))
}
pub fn signal_lte(&self) -> Result<SignalLte, Error> {
let data = self.dbus.proxy(&self.path).lte()?;
SignalLte::from_prop_map(data)
.ok_or_else(|| Error::new_failed("lte not found"))
}
pub fn signal_nr5g(&self) -> Result<SignalNr5g, Error> {
let data = self.dbus.proxy(&self.path).nr5g()?;
SignalNr5g::from_prop_map(data)
.ok_or_else(|| Error::new_failed("nr5g not found"))
}
pub fn own_numbers(&self) -> Result<Vec<String>, Error> {
self.dbus.proxy(&self.path).own_numbers()
}
pub fn imei(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).imei()
}
pub fn operator_name(&self) -> Result<String, Error> {
ModemModem3gpp::operator_name(&self.dbus.proxy(&self.path))
}
pub fn sim(&self) -> Result<Sim, Error> {
Ok(Sim {
path: self.dbus.proxy(&self.path).sim()?,
dbus: self.dbus.clone()
})
}
}
pub struct Sim {
dbus: Dbus,
path: Path<'static>
}
impl Sim {
pub fn identifier(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).sim_identifier()
}
pub fn imsi(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).imsi()
}
pub fn eid(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).eid()
}
pub fn operator_name(&self) -> Result<String, Error> {
SimTrait::operator_name(&self.dbus.proxy(&self.path))
}
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1")
)]
#[non_exhaustive]
pub enum ModemState {
Failed = -1,
Unknown = 0,
Initializing = 1,
Locked = 2,
Disabled = 3,
Disabling = 4,
Enabling = 5,
Enabled = 6,
Searching = 7,
Registered = 8,
Disconnecting = 9,
Connecting = 10,
Connected = 11
}
impl From<i32> for ModemState {
fn from(num: i32) -> Self {
if num < -1 || num > 11 {
Self::Unknown
} else {
unsafe {
*(&num as *const i32 as *const Self)
}
}
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1")
)]
#[non_exhaustive]
pub enum ModemAccessTech {
Unknown = 0,
Pots = 1 << 0,
Gsm = 1 << 1,
GsmCompact = 1 << 2,
Gprs = 1 << 3,
Edge = 1 << 4,
Umts = 1 << 5,
Hsdpa = 1 << 6,
Hsupa = 1 << 7,
Hspa = 1 << 8,
HspaPlus = 1 << 9,
T1xRtt = 1 << 10,
Evdo0 = 1 << 11,
EvdoA = 1 << 12,
EvdoB = 1 << 13,
Lte = 1 << 14,
T5Gnr = 1 << 15,
LteCatM = 1 << 16,
LteNbIoT = 1 << 17,
Any = u32::MAX
}
impl ModemAccessTech {
const ALL: &'static [ModemAccessTech] = &[
ModemAccessTech::Pots,
ModemAccessTech::Gsm,
ModemAccessTech::GsmCompact,
ModemAccessTech::Gprs,
ModemAccessTech::Edge,
ModemAccessTech::Umts,
ModemAccessTech::Hsdpa,
ModemAccessTech::Hsupa,
ModemAccessTech::Hspa,
ModemAccessTech::HspaPlus,
ModemAccessTech::T1xRtt,
ModemAccessTech::Evdo0,
ModemAccessTech::EvdoA,
ModemAccessTech::EvdoB,
ModemAccessTech::Lte,
ModemAccessTech::T5Gnr,
ModemAccessTech::LteCatM,
ModemAccessTech::LteNbIoT
];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ModemAccessTechs(u32);
impl ModemAccessTechs {
pub fn is_unknown(&self) -> bool {
self.0 == ModemAccessTech::Unknown as u32
}
pub fn is_any(&self) -> bool {
self.0 == ModemAccessTech::Any as u32
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item=ModemAccessTech> + 'a {
let is_unknown = self.is_unknown();
let is_any = self.is_any();
let allow_others = !is_unknown && !is_any;
let unknown_iter = is_unknown
.then(|| ModemAccessTech::Unknown)
.into_iter();
let any_iter = is_any.then(|| ModemAccessTech::Any).into_iter();
let other_iter = ModemAccessTech::ALL.into_iter()
.map(|v| *v)
.filter(move |t| allow_others && self.0 & *t as u32 > 0);
unknown_iter.chain(any_iter).chain(other_iter)
}
}
impl From<u32> for ModemAccessTechs {
fn from(num: u32) -> Self {
Self(num)
}
}
impl From<ModemAccessTechs> for u32 {
fn from(a: ModemAccessTechs) -> Self {
a.0
}
}
const MODE_NONE: u32 = 0;
const MODE_CS: u32 = 1 << 0;
const MODE_2G: u32 = 1 << 1;
const MODE_3G: u32 = 1 << 2;
const MODE_4G: u32 = 1 << 3;
const MODE_5G: u32 = 1 << 4;
const MODE_ANY: u32 = u32::MAX;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ModemMode(u32);
impl ModemMode {
pub fn new() -> Self {
ModemMode(MODE_NONE)
}
pub fn is_any(&self) -> bool {
self.0 == MODE_ANY
}
pub fn set_any(&mut self) {
self.0 = MODE_ANY;
}
pub fn is_none(&self) -> bool {
self.0 == MODE_NONE
}
pub fn has_cs(&self) -> bool {
self.0 & MODE_CS > 0
}
pub fn set_cs(&mut self) {
self.0 |= MODE_CS;
}
pub fn has_2g(&self) -> bool {
self.0 & MODE_2G > 0
}
pub fn set_2g(&mut self) {
self.0 |= MODE_2G;
}
pub fn has_3g(&self) -> bool {
self.0 & MODE_3G > 0
}
pub fn set_3g(&mut self) {
self.0 |= MODE_3G;
}
pub fn has_4g(&self) -> bool {
self.0 & MODE_4G > 0
}
pub fn set_4g(&mut self) {
self.0 |= MODE_4G;
}
pub fn has_5g(&self) -> bool {
self.0 & MODE_5G > 0
}
pub fn set_5g(&mut self) {
self.0 |= MODE_5G;
}
}
impl From<u32> for ModemMode {
fn from(num: u32) -> Self {
Self(num)
}
}
impl From<ModemMode> for u32 {
fn from(mode: ModemMode) -> Self {
mode.0
}
}
macro_rules! modem_band {
($($var:ident = $expr:expr),*) => (
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1")
)]
#[non_exhaustive]
pub enum ModemBand {
$($var = $expr),*
}
impl From<u32> for ModemBand {
fn from(num: u32) -> Self {
match num {
$($expr => Self::$var),*,
_ => Self::Unknown
}
}
}
impl From<ModemBand> for u32 {
fn from(b: ModemBand) -> Self {
b as u32
}
}
)
}
modem_band! {
Unknown = 0,
Egsm = 1,
Dcs = 2,
Pcs = 3,
G850 = 4,
Utran1 = 5,
Utran3 = 6,
Utran4 = 7,
Utran6 = 8,
Utran5 = 9,
Utran8 = 10,
Utran9 = 11,
Utran2 = 12,
Utran7 = 13,
G450 = 14,
G480 = 15,
G750 = 16,
G380 = 17,
G410 = 18,
G710 = 19,
G810 = 20,
Eutran1 = 31,
Eutran2 = 32,
Eutran3 = 33,
Eutran4 = 34,
Eutran5 = 35,
Eutran6 = 36,
Eutran7 = 37,
Eutran8 = 38,
Eutran9 = 39,
Eutran10 = 40,
Eutran11 = 41,
Eutran12 = 42,
Eutran13 = 43,
Eutran14 = 44,
Eutran17 = 47,
Eutran18 = 48,
Eutran19 = 49,
Eutran20 = 50,
Eutran21 = 51,
Eutran22 = 52,
Eutran23 = 53,
Eutran24 = 54,
Eutran25 = 55,
Eutran26 = 56,
Eutran27 = 57,
Eutran28 = 58,
Eutran29 = 59,
Eutran30 = 60,
Eutran31 = 61,
Eutran32 = 62,
Eutran33 = 63,
Eutran34 = 64,
Eutran35 = 65,
Eutran36 = 66,
Eutran37 = 67,
Eutran38 = 68,
Eutran39 = 69,
Eutran40 = 70,
Eutran41 = 71,
Eutran42 = 72,
Eutran43 = 73,
Eutran44 = 74,
Eutran45 = 75,
Eutran46 = 76,
Eutran47 = 77,
Eutran48 = 78,
Eutran49 = 79,
Eutran50 = 80,
Eutran51 = 81,
Eutran52 = 82,
Eutran53 = 83,
Eutran54 = 84,
Eutran55 = 85,
Eutran56 = 86,
Eutran57 = 87,
Eutran58 = 88,
Eutran59 = 89,
Eutran60 = 90,
Eutran61 = 91,
Eutran62 = 92,
Eutran63 = 93,
Eutran64 = 94,
Eutran65 = 95,
Eutran66 = 96,
Eutran67 = 97,
Eutran68 = 98,
Eutran69 = 99,
Eutran70 = 100,
Eutran71 = 101,
CdmaBc0 = 128,
CdmaBc1 = 129,
CdmaBc2 = 130,
CdmaBc3 = 131,
CdmaBc4 = 132,
CdmaBc5 = 134,
CdmaBc6 = 135,
CdmaBc7 = 136,
CdmaBc8 = 137,
CdmaBc9 = 138,
CdmaBc10 = 139,
CdmaBc11 = 140,
CdmaBc12 = 141,
CdmaBc13 = 142,
CdmaBc14 = 143,
CdmaBc15 = 144,
CdmaBc16 = 145,
CdmaBc17 = 146,
CdmaBc18 = 147,
CdmaBc19 = 148,
Utran10 = 210,
Utran11 = 211,
Utran12 = 212,
Utran13 = 213,
Utran14 = 214,
Utran19 = 219,
Utran20 = 220,
Utran21 = 221,
Utran22 = 222,
Utran25 = 225,
Utran26 = 226,
Utran32 = 232,
Any = 256
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalCdma {
pub rssi: f64,
pub ecio: f64
}
impl SignalCdma {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rssi: prop.get("rssi")?
.as_f64()?,
ecio: prop.get("ecio")?
.as_f64()?
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalEvdo {
pub rssi: f64,
pub ecio: f64,
pub sinr: f64,
pub io: f64
}
impl SignalEvdo {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rssi: prop.get("rssi")?
.as_f64()?,
ecio: prop.get("ecio")?
.as_f64()?,
sinr: prop.get("sinr")?
.as_f64()?,
io: prop.get("io")?
.as_f64()?
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalGsm {
pub rssi: f64
}
impl SignalGsm {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rssi: prop.get("rssi")?
.as_f64()?
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalUmts {
pub rssi: f64,
pub rscp: f64,
pub ecio: f64
}
impl SignalUmts {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rssi: prop.get("rssi")?
.as_f64()?,
rscp: prop.get("rscp")
.and_then(|v| v.as_f64())
.unwrap_or(0f64),
ecio: prop.get("ecio")?
.as_f64()?
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalLte {
pub rssi: f64,
pub rsrq: f64,
pub rsrp: f64,
pub snr: f64
}
impl SignalLte {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rssi: prop.get("rssi")?
.as_f64()?,
rsrq: prop.get("rsrq")?
.as_f64()?,
rsrp: prop.get("rsrp")?
.as_f64()?,
snr: prop.get("snr")?
.as_f64()?
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1", rename = "camelCase")
)]
pub struct SignalNr5g {
pub rsrq: f64,
pub rsrp: f64,
pub snr: f64
}
impl SignalNr5g {
fn from_prop_map(prop: PropMap) -> Option<Self> {
Some(Self {
rsrq: prop.get("rsrq")?
.as_f64()?,
rsrp: prop.get("rsrp")?
.as_f64()?,
snr: prop.get("snr")?
.as_f64()?
})
}
}