1use std::time::Duration;
4use std::sync::Arc;
5
6use dbus::{Error, Path};
7use dbus::blocking::{Connection, Proxy};
8use dbus::blocking::stdintf::org_freedesktop_dbus::ObjectManager;
9use dbus::arg::{RefArg, PropMap};
10
11use mmdbus::modem::Modem as ModemAccess;
12use mmdbus::modem_signal::ModemSignal;
13use mmdbus::modem_modem3gpp::ModemModem3gpp;
14use mmdbus::sim::Sim as SimTrait;
15
16const DBUS_NAME: &str = "org.freedesktop.ModemManager1";
17const DBUS_PATH: &str = "/org/freedesktop/ModemManager1";
18const TIMEOUT: Duration = Duration::from_secs(2);
19
20#[derive(Clone)]
21struct Dbus {
22 conn: Arc<Connection>
23}
24
25impl Dbus {
26 fn connect() -> Result<Self, Error> {
27 Connection::new_system()
28 .map(Arc::new)
29 .map(|conn| Self { conn })
30 }
31
32 fn proxy<'a, 'b>(
33 &'b self,
34 path: impl Into<Path<'a>>
35 ) -> Proxy<'a, &'b Connection> {
36 self.conn.with_proxy(DBUS_NAME, path, TIMEOUT)
37 }
38}
39
40#[derive(Clone)]
41pub struct ModemManager {
42 dbus: Dbus
43}
44
45impl ModemManager {
46 pub fn connect() -> Result<Self, Error> {
47 Dbus::connect()
48 .map(|dbus| Self { dbus })
49 }
50
51 pub fn modems(&self) -> Result<Vec<Modem>, Error> {
52 let objects = self.dbus.proxy(DBUS_PATH).get_managed_objects()?;
53 let modems = objects.into_iter()
54 .map(|(path, _)| {
55 Modem {
56 dbus: self.dbus.clone(),
57 path
58 }
59 })
60 .collect();
61
62 Ok(modems)
63 }
64}
65
66pub struct Modem {
67 dbus: Dbus,
68 path: Path<'static>
69}
70
71impl Modem {
72 pub fn manufacturer(&self) -> Result<String, Error> {
74 self.dbus.proxy(&self.path).manufacturer()
75 }
76
77 pub fn model(&self) -> Result<String, Error> {
79 self.dbus.proxy(&self.path).model()
80 }
81
82 pub fn carrier_configuration(&self) -> Result<String, Error> {
85 self.dbus.proxy(&self.path).carrier_configuration()
86 }
87
88 pub fn device(&self) -> Result<String, Error> {
97 self.dbus.proxy(&self.path).device()
98 }
99
100 pub fn state(&self) -> Result<ModemState, Error> {
105 self.dbus.proxy(&self.path).state()
106 .map(Into::into)
107 }
108
109 pub fn access_techs(&self) -> Result<ModemAccessTechs, Error> {
115 self.dbus.proxy(&self.path).access_technologies()
116 .map(Into::into)
117 }
118
119 pub fn signal_quality(&self) -> Result<(u32, bool), Error> {
125 self.dbus.proxy(&self.path).signal_quality()
126 }
127
128 pub fn supported_modes(&self) -> Result<Vec<(ModemMode, ModemMode)>, Error> {
138 self.dbus.proxy(&self.path).supported_modes()
139 .map(|v| v.into_iter().map(|(a, b)| (a.into(), b.into())).collect())
140 }
141
142 pub fn current_modes(&self) -> Result<(ModemMode, ModemMode), Error> {
147 self.dbus.proxy(&self.path).current_modes()
148 .map(|(a, b)| (a.into(), b.into()))
149 }
150
151 pub fn set_current_modes(
160 &self,
161 (allowed, preferred): (ModemMode, ModemMode)
162 ) -> Result<(), Error> {
163 self.dbus.proxy(&self.path).set_current_modes(
164 (allowed.into(), preferred.into())
165 )
166 }
167
168 pub fn supported_bands(&self) -> Result<Vec<ModemBand>, Error> {
173 self.dbus.proxy(&self.path).supported_bands()
174 .map(|v| v.into_iter().map(Into::into).collect())
175 }
176
177 pub fn current_bands(&self) -> Result<Vec<ModemBand>, Error> {
183 self.dbus.proxy(&self.path).current_bands()
184 .map(|v| v.into_iter().map(Into::into).collect())
185 }
186
187 pub fn set_current_bands(
192 &self,
193 bands: &[ModemBand]
194 ) -> Result<(), Error> {
195 self.dbus.proxy(&self.path).set_current_bands(
196 bands.into_iter().map(|b| *b as u32).collect()
197 )
198 }
199
200 pub fn signal_setup(&self, rate: u32) -> Result<(), Error> {
201 self.dbus.proxy(&self.path).setup(rate)
202 }
203
204 pub fn signal_cdma(&self) -> Result<SignalCdma, Error> {
206 let data = self.dbus.proxy(&self.path).cdma()?;
207 SignalCdma::from_prop_map(data)
208 .ok_or_else(|| Error::new_failed("cdma not found"))
209 }
210
211 pub fn signal_evdo(&self) -> Result<SignalEvdo, Error> {
213 let data = self.dbus.proxy(&self.path).evdo()?;
214 SignalEvdo::from_prop_map(data)
215 .ok_or_else(|| Error::new_failed("evdo not found"))
216 }
217
218 pub fn signal_gsm(&self) -> Result<SignalGsm, Error> {
220 let data = self.dbus.proxy(&self.path).gsm()?;
221 SignalGsm::from_prop_map(data)
222 .ok_or_else(|| Error::new_failed("gsm not found"))
223 }
224
225 pub fn signal_umts(&self) -> Result<SignalUmts, Error> {
227 let data = self.dbus.proxy(&self.path).umts()?;
228 SignalUmts::from_prop_map(data)
229 .ok_or_else(|| Error::new_failed("umts not found"))
230 }
231
232 pub fn signal_lte(&self) -> Result<SignalLte, Error> {
234 let data = self.dbus.proxy(&self.path).lte()?;
235 SignalLte::from_prop_map(data)
236 .ok_or_else(|| Error::new_failed("lte not found"))
237 }
238
239 pub fn signal_nr5g(&self) -> Result<SignalNr5g, Error> {
241 let data = self.dbus.proxy(&self.path).nr5g()?;
242 SignalNr5g::from_prop_map(data)
243 .ok_or_else(|| Error::new_failed("nr5g not found"))
244 }
245
246 pub fn own_numbers(&self) -> Result<Vec<String>, Error> {
249 self.dbus.proxy(&self.path).own_numbers()
250 }
251
252 pub fn imei(&self) -> Result<String, Error> {
260 self.dbus.proxy(&self.path).imei()
261 }
262
263 pub fn registration_state(&self) -> Result<RegistrationState, Error> {
272 ModemModem3gpp::registration_state(&self.dbus.proxy(&self.path))
273 .map(Into::into)
274 }
275
276 pub fn operator_code(&self) -> Result<String, Error> {
292 ModemModem3gpp::operator_code(&self.dbus.proxy(&self.path))
293 }
294
295 pub fn operator_name(&self) -> Result<String, Error> {
306 ModemModem3gpp::operator_name(&self.dbus.proxy(&self.path))
307 }
308
309 pub fn sim(&self) -> Result<Sim, Error> {
312 Ok(Sim {
313 path: self.dbus.proxy(&self.path).sim()?,
314 dbus: self.dbus.clone()
315 })
316 }
317}
318
319pub struct Sim {
320 dbus: Dbus,
321 path: Path<'static>
322}
323
324impl Sim {
325 pub fn identifier(&self) -> Result<String, Error> {
330 self.dbus.proxy(&self.path).sim_identifier()
331 }
332
333 pub fn imsi(&self) -> Result<String, Error> {
335 self.dbus.proxy(&self.path).imsi()
336 }
337
338 pub fn eid(&self) -> Result<String, Error> {
340 self.dbus.proxy(&self.path).eid()
341 }
342
343 pub fn operator_name(&self) -> Result<String, Error> {
345 SimTrait::operator_name(&self.dbus.proxy(&self.path))
346 }
347}
348
349
350#[repr(i32)]
351#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
352#[cfg_attr(
353 feature = "serde",
354 derive(serde1::Serialize, serde1::Deserialize),
355 serde(crate = "serde1")
356)]
357#[non_exhaustive]
358pub enum ModemState {
359 Failed = -1,
361 Unknown = 0,
363 Initializing = 1,
365 Locked = 2,
367 Disabled = 3,
369 Disabling = 4,
372 Enabling = 5,
375 Enabled = 6,
378 Searching = 7,
380 Registered = 8,
383 Disconnecting = 9,
387 Connecting = 10,
391 Connected = 11
393}
394
395impl From<i32> for ModemState {
396 fn from(num: i32) -> Self {
397 if num < -1 || num > 11 {
398 Self::Unknown
399 } else {
400 unsafe {
401 *(&num as *const i32 as *const Self)
402 }
403 }
404 }
405}
406
407#[repr(u32)]
408#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
409#[cfg_attr(
410 feature = "serde",
411 derive(serde1::Serialize, serde1::Deserialize),
412 serde(crate = "serde1")
413)]
414#[non_exhaustive]
415pub enum ModemAccessTech {
418 Unknown = 0,
420 Pots = 1 << 0,
422 Gsm = 1 << 1,
424 GsmCompact = 1 << 2,
426 Gprs = 1 << 3,
428 Edge = 1 << 4,
430 Umts = 1 << 5,
432 Hsdpa = 1 << 6,
434 Hsupa = 1 << 7,
436 Hspa = 1 << 8,
438 HspaPlus = 1 << 9,
440 T1xRtt = 1 << 10,
442 Evdo0 = 1 << 11,
444 EvdoA = 1 << 12,
446 EvdoB = 1 << 13,
448 Lte = 1 << 14,
450 T5Gnr = 1 << 15,
452 LteCatM = 1 << 16,
454 LteNbIoT = 1 << 17,
456 Any = u32::MAX
458}
459
460impl ModemAccessTech {
461 const ALL: &'static [ModemAccessTech] = &[
463 ModemAccessTech::Pots,
464 ModemAccessTech::Gsm,
465 ModemAccessTech::GsmCompact,
466 ModemAccessTech::Gprs,
467 ModemAccessTech::Edge,
468 ModemAccessTech::Umts,
469 ModemAccessTech::Hsdpa,
470 ModemAccessTech::Hsupa,
471 ModemAccessTech::Hspa,
472 ModemAccessTech::HspaPlus,
473 ModemAccessTech::T1xRtt,
474 ModemAccessTech::Evdo0,
475 ModemAccessTech::EvdoA,
476 ModemAccessTech::EvdoB,
477 ModemAccessTech::Lte,
478 ModemAccessTech::T5Gnr,
479 ModemAccessTech::LteCatM,
480 ModemAccessTech::LteNbIoT
481 ];
482}
483
484#[derive(Debug, Clone, Copy, PartialEq, Eq)]
486pub struct ModemAccessTechs(u32);
487
488impl ModemAccessTechs {
489 pub fn is_unknown(&self) -> bool {
491 self.0 == ModemAccessTech::Unknown as u32
492 }
493
494 pub fn is_any(&self) -> bool {
496 self.0 == ModemAccessTech::Any as u32
497 }
498
499 pub fn iter<'a>(&'a self) -> impl Iterator<Item=ModemAccessTech> + 'a {
500 let is_unknown = self.is_unknown();
501 let is_any = self.is_any();
502 let allow_others = !is_unknown && !is_any;
503
504 let unknown_iter = is_unknown
510 .then(|| ModemAccessTech::Unknown)
511 .into_iter();
512 let any_iter = is_any.then(|| ModemAccessTech::Any).into_iter();
513
514 let other_iter = ModemAccessTech::ALL.into_iter()
515 .map(|v| *v)
516 .filter(move |t| allow_others && self.0 & *t as u32 > 0);
517
518 unknown_iter.chain(any_iter).chain(other_iter)
519 }
520}
521
522impl From<u32> for ModemAccessTechs {
523 fn from(num: u32) -> Self {
524 Self(num)
525 }
526}
527
528impl From<ModemAccessTechs> for u32 {
529 fn from(a: ModemAccessTechs) -> Self {
530 a.0
531 }
532}
533
534const MODE_NONE: u32 = 0;
535const MODE_CS: u32 = 1 << 0;
537const MODE_2G: u32 = 1 << 1;
539const MODE_3G: u32 = 1 << 2;
541const MODE_4G: u32 = 1 << 3;
543const MODE_5G: u32 = 1 << 4;
545const MODE_ANY: u32 = u32::MAX;
547
548#[derive(Debug, Clone, Copy, PartialEq, Eq)]
550pub struct ModemMode(u32);
551
552impl ModemMode {
553 pub fn new() -> Self {
555 ModemMode(MODE_NONE)
556 }
557
558 pub fn is_any(&self) -> bool {
560 self.0 == MODE_ANY
561 }
562
563 pub fn set_any(&mut self) {
565 self.0 = MODE_ANY;
566 }
567
568 pub fn is_none(&self) -> bool {
570 self.0 == MODE_NONE
571 }
572
573 pub fn has_cs(&self) -> bool {
575 self.0 & MODE_CS > 0
576 }
577
578 pub fn set_cs(&mut self) {
580 self.0 |= MODE_CS;
581 }
582
583 pub fn has_2g(&self) -> bool {
585 self.0 & MODE_2G > 0
586 }
587
588 pub fn set_2g(&mut self) {
590 self.0 |= MODE_2G;
591 }
592
593 pub fn has_3g(&self) -> bool {
595 self.0 & MODE_3G > 0
596 }
597
598 pub fn set_3g(&mut self) {
600 self.0 |= MODE_3G;
601 }
602
603 pub fn has_4g(&self) -> bool {
605 self.0 & MODE_4G > 0
606 }
607
608 pub fn set_4g(&mut self) {
610 self.0 |= MODE_4G;
611 }
612
613 pub fn has_5g(&self) -> bool {
615 self.0 & MODE_5G > 0
616 }
617
618 pub fn set_5g(&mut self) {
620 self.0 |= MODE_5G;
621 }
622}
623
624impl From<u32> for ModemMode {
625 fn from(num: u32) -> Self {
626 Self(num)
627 }
628}
629
630impl From<ModemMode> for u32 {
631 fn from(mode: ModemMode) -> Self {
632 mode.0
633 }
634}
635
636macro_rules! modem_band {
637 ($($var:ident = $expr:expr),*) => (
638 #[repr(u32)]
639 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
640 #[cfg_attr(
641 feature = "serde",
642 derive(serde1::Serialize, serde1::Deserialize),
643 serde(crate = "serde1")
644 )]
645 #[non_exhaustive]
646 pub enum ModemBand {
647 $($var = $expr),*
648 }
649
650 impl From<u32> for ModemBand {
651 fn from(num: u32) -> Self {
652 match num {
653 $($expr => Self::$var),*,
654 _ => Self::Unknown
655 }
656 }
657 }
658
659 impl From<ModemBand> for u32 {
660 fn from(b: ModemBand) -> Self {
661 b as u32
662 }
663 }
664 )
665}
666
667
668modem_band! {
669 Unknown = 0,
670 Egsm = 1,
672 Dcs = 2,
673 Pcs = 3,
674 G850 = 4,
675 Utran1 = 5,
676 Utran3 = 6,
677 Utran4 = 7,
678 Utran6 = 8,
679 Utran5 = 9,
680 Utran8 = 10,
681 Utran9 = 11,
682 Utran2 = 12,
683 Utran7 = 13,
684 G450 = 14,
685 G480 = 15,
686 G750 = 16,
687 G380 = 17,
688 G410 = 18,
689 G710 = 19,
690 G810 = 20,
691 Eutran1 = 31,
693 Eutran2 = 32,
694 Eutran3 = 33,
695 Eutran4 = 34,
696 Eutran5 = 35,
697 Eutran6 = 36,
698 Eutran7 = 37,
699 Eutran8 = 38,
700 Eutran9 = 39,
701 Eutran10 = 40,
702 Eutran11 = 41,
703 Eutran12 = 42,
704 Eutran13 = 43,
705 Eutran14 = 44,
706 Eutran17 = 47,
707 Eutran18 = 48,
708 Eutran19 = 49,
709 Eutran20 = 50,
710 Eutran21 = 51,
711 Eutran22 = 52,
712 Eutran23 = 53,
713 Eutran24 = 54,
714 Eutran25 = 55,
715 Eutran26 = 56,
716 Eutran27 = 57,
717 Eutran28 = 58,
718 Eutran29 = 59,
719 Eutran30 = 60,
720 Eutran31 = 61,
721 Eutran32 = 62,
722 Eutran33 = 63,
723 Eutran34 = 64,
724 Eutran35 = 65,
725 Eutran36 = 66,
726 Eutran37 = 67,
727 Eutran38 = 68,
728 Eutran39 = 69,
729 Eutran40 = 70,
730 Eutran41 = 71,
731 Eutran42 = 72,
732 Eutran43 = 73,
733 Eutran44 = 74,
734 Eutran45 = 75,
735 Eutran46 = 76,
736 Eutran47 = 77,
737 Eutran48 = 78,
738 Eutran49 = 79,
739 Eutran50 = 80,
740 Eutran51 = 81,
741 Eutran52 = 82,
742 Eutran53 = 83,
743 Eutran54 = 84,
744 Eutran55 = 85,
745 Eutran56 = 86,
746 Eutran57 = 87,
747 Eutran58 = 88,
748 Eutran59 = 89,
749 Eutran60 = 90,
750 Eutran61 = 91,
751 Eutran62 = 92,
752 Eutran63 = 93,
753 Eutran64 = 94,
754 Eutran65 = 95,
755 Eutran66 = 96,
756 Eutran67 = 97,
757 Eutran68 = 98,
758 Eutran69 = 99,
759 Eutran70 = 100,
760 Eutran71 = 101,
761 CdmaBc0 = 128,
763 CdmaBc1 = 129,
764 CdmaBc2 = 130,
765 CdmaBc3 = 131,
766 CdmaBc4 = 132,
767 CdmaBc5 = 134,
768 CdmaBc6 = 135,
769 CdmaBc7 = 136,
770 CdmaBc8 = 137,
771 CdmaBc9 = 138,
772 CdmaBc10 = 139,
773 CdmaBc11 = 140,
774 CdmaBc12 = 141,
775 CdmaBc13 = 142,
776 CdmaBc14 = 143,
777 CdmaBc15 = 144,
778 CdmaBc16 = 145,
779 CdmaBc17 = 146,
780 CdmaBc18 = 147,
781 CdmaBc19 = 148,
782 Utran10 = 210,
788 Utran11 = 211,
789 Utran12 = 212,
790 Utran13 = 213,
791 Utran14 = 214,
792 Utran19 = 219,
793 Utran20 = 220,
794 Utran21 = 221,
795 Utran22 = 222,
796 Utran25 = 225,
797 Utran26 = 226,
798 Utran32 = 232,
799 Any = 256
801}
802
803#[derive(Debug, Clone, Copy, PartialEq)]
804#[cfg_attr(
805 feature = "serde",
806 derive(serde1::Serialize, serde1::Deserialize),
807 serde(crate = "serde1", rename = "camelCase")
808)]
809pub struct SignalCdma {
810 pub rssi: f64,
812 pub ecio: f64
814}
815
816impl SignalCdma {
817 fn from_prop_map(prop: PropMap) -> Option<Self> {
818 Some(Self {
819 rssi: prop.get("rssi")?
820 .as_f64()?,
821 ecio: prop.get("ecio")?
822 .as_f64()?
823 })
824 }
825}
826
827#[derive(Debug, Clone, Copy, PartialEq)]
828#[cfg_attr(
829 feature = "serde",
830 derive(serde1::Serialize, serde1::Deserialize),
831 serde(crate = "serde1", rename = "camelCase")
832)]
833pub struct SignalEvdo {
834 pub rssi: f64,
836 pub ecio: f64,
838 pub sinr: f64,
840 pub io: f64
842}
843
844impl SignalEvdo {
845 fn from_prop_map(prop: PropMap) -> Option<Self> {
846 Some(Self {
847 rssi: prop.get("rssi")?
848 .as_f64()?,
849 ecio: prop.get("ecio")?
850 .as_f64()?,
851 sinr: prop.get("sinr")?
852 .as_f64()?,
853 io: prop.get("io")?
854 .as_f64()?
855 })
856 }
857}
858
859#[derive(Debug, Clone, Copy, PartialEq)]
860#[cfg_attr(
861 feature = "serde",
862 derive(serde1::Serialize, serde1::Deserialize),
863 serde(crate = "serde1", rename = "camelCase")
864)]
865pub struct SignalGsm {
866 pub rssi: f64
868}
869
870impl SignalGsm {
871 fn from_prop_map(prop: PropMap) -> Option<Self> {
872 Some(Self {
873 rssi: prop.get("rssi")?
874 .as_f64()?
875 })
876 }
877}
878
879#[derive(Debug, Clone, Copy, PartialEq)]
880#[cfg_attr(
881 feature = "serde",
882 derive(serde1::Serialize, serde1::Deserialize),
883 serde(crate = "serde1", rename = "camelCase")
884)]
885pub struct SignalUmts {
886 pub rssi: f64,
888 pub rscp: f64,
892 pub ecio: f64
894}
895
896impl SignalUmts {
897 fn from_prop_map(prop: PropMap) -> Option<Self> {
898 Some(Self {
899 rssi: prop.get("rssi")?
900 .as_f64()?,
901 rscp: prop.get("rscp")
903 .and_then(|v| v.as_f64())
904 .unwrap_or(0f64),
905 ecio: prop.get("ecio")?
906 .as_f64()?
907 })
908 }
909}
910
911#[derive(Debug, Clone, Copy, PartialEq)]
912#[cfg_attr(
913 feature = "serde",
914 derive(serde1::Serialize, serde1::Deserialize),
915 serde(crate = "serde1", rename = "camelCase")
916)]
917pub struct SignalLte {
918 pub rssi: f64,
920 pub rsrq: f64,
922 pub rsrp: f64,
924 pub snr: f64
926}
927
928impl SignalLte {
929 fn from_prop_map(prop: PropMap) -> Option<Self> {
930 Some(Self {
931 rssi: prop.get("rssi")?
932 .as_f64()?,
933 rsrq: prop.get("rsrq")?
934 .as_f64()?,
935 rsrp: prop.get("rsrp")?
936 .as_f64()?,
937 snr: prop.get("snr")?
938 .as_f64()?
939 })
940 }
941}
942
943#[derive(Debug, Clone, Copy, PartialEq)]
944#[cfg_attr(
945 feature = "serde",
946 derive(serde1::Serialize, serde1::Deserialize),
947 serde(crate = "serde1", rename = "camelCase")
948)]
949pub struct SignalNr5g {
950 pub rsrq: f64,
951 pub rsrp: f64,
952 pub snr: f64
953}
954
955impl SignalNr5g {
956 fn from_prop_map(prop: PropMap) -> Option<Self> {
957 Some(Self {
958 rsrq: prop.get("rsrq")?
959 .as_f64()?,
960 rsrp: prop.get("rsrp")?
961 .as_f64()?,
962 snr: prop.get("snr")?
963 .as_f64()?
964 })
965 }
966}
967
968#[repr(u32)]
969#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
970#[cfg_attr(
971 feature = "serde",
972 derive(serde1::Serialize, serde1::Deserialize),
973 serde(crate = "serde1")
974)]
975#[non_exhaustive]
976pub enum RegistrationState {
977 Idle = 0,
979 Home = 1,
981 Searching = 2,
983 Denied = 3,
985 Unknown = 4,
987 Roaming = 5
989}
990
991impl From<u32> for RegistrationState {
992 fn from(num: u32) -> Self {
993 if num > 5 {
994 Self::Unknown
995 } else {
996 unsafe {
997 *(&num as *const u32 as *const Self)
998 }
999 }
1000 }
1001}