1use std::sync::Arc;
4use std::time::Duration;
5
6use dbus::arg::{PropMap, RefArg};
7use dbus::blocking::stdintf::org_freedesktop_dbus::ObjectManager;
8use dbus::blocking::{Connection, Proxy};
9use dbus::{Error, Path};
10
11use mmdbus::modem::Modem as ModemAccess;
12use mmdbus::modem_modem3gpp::ModemModem3gpp;
13use mmdbus::modem_signal::ModemSignal;
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().map(|dbus| Self { dbus })
48 }
49
50 pub fn modems(&self) -> Result<Vec<Modem>, Error> {
51 let objects = self.dbus.proxy(DBUS_PATH).get_managed_objects()?;
52 let modems = objects
53 .into_iter()
54 .map(|(path, _)| Modem {
55 dbus: self.dbus.clone(),
56 path,
57 })
58 .collect();
59
60 Ok(modems)
61 }
62}
63
64pub struct Modem {
65 dbus: Dbus,
66 path: Path<'static>,
67}
68
69impl Modem {
70 pub fn manufacturer(&self) -> Result<String, Error> {
72 self.dbus.proxy(&self.path).manufacturer()
73 }
74
75 pub fn model(&self) -> Result<String, Error> {
77 self.dbus.proxy(&self.path).model()
78 }
79
80 pub fn carrier_configuration(&self) -> Result<String, Error> {
83 self.dbus.proxy(&self.path).carrier_configuration()
84 }
85
86 pub fn device(&self) -> Result<String, Error> {
95 self.dbus.proxy(&self.path).device()
96 }
97
98 pub fn state(&self) -> Result<ModemState, Error> {
103 self.dbus.proxy(&self.path).state().map(Into::into)
104 }
105
106 pub fn access_techs(&self) -> Result<ModemAccessTechs, Error> {
112 self.dbus
113 .proxy(&self.path)
114 .access_technologies()
115 .map(Into::into)
116 }
117
118 pub fn signal_quality(&self) -> Result<(u32, bool), Error> {
124 self.dbus.proxy(&self.path).signal_quality()
125 }
126
127 pub fn supported_modes(
137 &self,
138 ) -> Result<Vec<(ModemMode, ModemMode)>, Error> {
139 self.dbus
140 .proxy(&self.path)
141 .supported_modes()
142 .map(|v| v.into_iter().map(|(a, b)| (a.into(), b.into())).collect())
143 }
144
145 pub fn current_modes(&self) -> Result<(ModemMode, ModemMode), Error> {
150 self.dbus
151 .proxy(&self.path)
152 .current_modes()
153 .map(|(a, b)| (a.into(), b.into()))
154 }
155
156 pub fn set_current_modes(
165 &self,
166 (allowed, preferred): (ModemMode, ModemMode),
167 ) -> Result<(), Error> {
168 self.dbus
169 .proxy(&self.path)
170 .set_current_modes((allowed.into(), preferred.into()))
171 }
172
173 pub fn supported_bands(&self) -> Result<Vec<ModemBand>, Error> {
178 self.dbus
179 .proxy(&self.path)
180 .supported_bands()
181 .map(|v| v.into_iter().map(Into::into).collect())
182 }
183
184 pub fn current_bands(&self) -> Result<Vec<ModemBand>, Error> {
190 self.dbus
191 .proxy(&self.path)
192 .current_bands()
193 .map(|v| v.into_iter().map(Into::into).collect())
194 }
195
196 pub fn set_current_bands(&self, bands: &[ModemBand]) -> Result<(), Error> {
201 self.dbus
202 .proxy(&self.path)
203 .set_current_bands(bands.into_iter().map(|b| *b as u32).collect())
204 }
205
206 pub fn signal_rate(&self) -> Result<u32, Error> {
207 self.dbus.proxy(&self.path).rate()
208 }
209
210 pub fn signal_setup(&self, rate: u32) -> Result<(), Error> {
211 self.dbus.proxy(&self.path).setup(rate)
212 }
213
214 pub fn signal_cdma(&self) -> Result<SignalCdma, Error> {
216 let data = self.dbus.proxy(&self.path).cdma()?;
217 SignalCdma::from_prop_map(data)
218 .ok_or_else(|| Error::new_failed("cdma not found"))
219 }
220
221 pub fn signal_evdo(&self) -> Result<SignalEvdo, Error> {
223 let data = self.dbus.proxy(&self.path).evdo()?;
224 SignalEvdo::from_prop_map(data)
225 .ok_or_else(|| Error::new_failed("evdo not found"))
226 }
227
228 pub fn signal_gsm(&self) -> Result<SignalGsm, Error> {
230 let data = self.dbus.proxy(&self.path).gsm()?;
231 SignalGsm::from_prop_map(data)
232 .ok_or_else(|| Error::new_failed("gsm not found"))
233 }
234
235 pub fn signal_umts(&self) -> Result<SignalUmts, Error> {
237 let data = self.dbus.proxy(&self.path).umts()?;
238 SignalUmts::from_prop_map(data)
239 .ok_or_else(|| Error::new_failed("umts not found"))
240 }
241
242 pub fn signal_lte(&self) -> Result<SignalLte, Error> {
244 let data = self.dbus.proxy(&self.path).lte()?;
245 SignalLte::from_prop_map(data)
246 .ok_or_else(|| Error::new_failed("lte not found"))
247 }
248
249 pub fn signal_nr5g(&self) -> Result<SignalNr5g, Error> {
251 let data = self.dbus.proxy(&self.path).nr5g()?;
252 SignalNr5g::from_prop_map(data)
253 .ok_or_else(|| Error::new_failed("nr5g not found"))
254 }
255
256 pub fn own_numbers(&self) -> Result<Vec<String>, Error> {
259 self.dbus.proxy(&self.path).own_numbers()
260 }
261
262 pub fn imei(&self) -> Result<String, Error> {
270 self.dbus.proxy(&self.path).imei()
271 }
272
273 pub fn registration_state(&self) -> Result<RegistrationState, Error> {
282 ModemModem3gpp::registration_state(&self.dbus.proxy(&self.path))
283 .map(Into::into)
284 }
285
286 pub fn operator_code(&self) -> Result<String, Error> {
302 ModemModem3gpp::operator_code(&self.dbus.proxy(&self.path))
303 }
304
305 pub fn operator_name(&self) -> Result<String, Error> {
316 ModemModem3gpp::operator_name(&self.dbus.proxy(&self.path))
317 }
318
319 pub fn sim(&self) -> Result<Sim, Error> {
322 Ok(Sim {
323 path: self.dbus.proxy(&self.path).sim()?,
324 dbus: self.dbus.clone(),
325 })
326 }
327}
328
329pub struct Sim {
330 dbus: Dbus,
331 path: Path<'static>,
332}
333
334impl Sim {
335 pub fn identifier(&self) -> Result<String, Error> {
340 self.dbus.proxy(&self.path).sim_identifier()
341 }
342
343 pub fn imsi(&self) -> Result<String, Error> {
345 self.dbus.proxy(&self.path).imsi()
346 }
347
348 pub fn eid(&self) -> Result<String, Error> {
350 self.dbus.proxy(&self.path).eid()
351 }
352
353 pub fn operator_name(&self) -> Result<String, Error> {
355 SimTrait::operator_name(&self.dbus.proxy(&self.path))
356 }
357}
358
359#[repr(i32)]
360#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
361#[cfg_attr(
362 feature = "serde",
363 derive(serde1::Serialize, serde1::Deserialize),
364 serde(crate = "serde1")
365)]
366#[non_exhaustive]
367pub enum ModemState {
368 Failed = -1,
370 Unknown = 0,
372 Initializing = 1,
374 Locked = 2,
376 Disabled = 3,
378 Disabling = 4,
381 Enabling = 5,
384 Enabled = 6,
387 Searching = 7,
389 Registered = 8,
392 Disconnecting = 9,
396 Connecting = 10,
400 Connected = 11,
402}
403
404impl From<i32> for ModemState {
405 fn from(num: i32) -> Self {
406 if num < -1 || num > 11 {
407 Self::Unknown
408 } else {
409 unsafe { *(&num as *const i32 as *const Self) }
410 }
411 }
412}
413
414#[repr(u32)]
415#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
416#[cfg_attr(
417 feature = "serde",
418 derive(serde1::Serialize, serde1::Deserialize),
419 serde(crate = "serde1")
420)]
421#[non_exhaustive]
422pub enum ModemAccessTech {
425 Unknown = 0,
427 Pots = 1 << 0,
429 Gsm = 1 << 1,
431 GsmCompact = 1 << 2,
433 Gprs = 1 << 3,
435 Edge = 1 << 4,
437 Umts = 1 << 5,
439 Hsdpa = 1 << 6,
441 Hsupa = 1 << 7,
443 Hspa = 1 << 8,
445 HspaPlus = 1 << 9,
447 T1xRtt = 1 << 10,
449 Evdo0 = 1 << 11,
451 EvdoA = 1 << 12,
453 EvdoB = 1 << 13,
455 Lte = 1 << 14,
457 T5Gnr = 1 << 15,
459 LteCatM = 1 << 16,
461 LteNbIoT = 1 << 17,
463 Any = u32::MAX,
465}
466
467impl ModemAccessTech {
468 const ALL: &'static [ModemAccessTech] = &[
470 ModemAccessTech::Pots,
471 ModemAccessTech::Gsm,
472 ModemAccessTech::GsmCompact,
473 ModemAccessTech::Gprs,
474 ModemAccessTech::Edge,
475 ModemAccessTech::Umts,
476 ModemAccessTech::Hsdpa,
477 ModemAccessTech::Hsupa,
478 ModemAccessTech::Hspa,
479 ModemAccessTech::HspaPlus,
480 ModemAccessTech::T1xRtt,
481 ModemAccessTech::Evdo0,
482 ModemAccessTech::EvdoA,
483 ModemAccessTech::EvdoB,
484 ModemAccessTech::Lte,
485 ModemAccessTech::T5Gnr,
486 ModemAccessTech::LteCatM,
487 ModemAccessTech::LteNbIoT,
488 ];
489}
490
491#[derive(Debug, Clone, Copy, PartialEq, Eq)]
493pub struct ModemAccessTechs(u32);
494
495impl ModemAccessTechs {
496 pub fn is_unknown(&self) -> bool {
498 self.0 == ModemAccessTech::Unknown as u32
499 }
500
501 pub fn is_any(&self) -> bool {
503 self.0 == ModemAccessTech::Any as u32
504 }
505
506 pub fn iter<'a>(&'a self) -> impl Iterator<Item = ModemAccessTech> + 'a {
507 let is_unknown = self.is_unknown();
508 let is_any = self.is_any();
509 let allow_others = !is_unknown && !is_any;
510
511 let unknown_iter =
517 is_unknown.then(|| ModemAccessTech::Unknown).into_iter();
518 let any_iter = is_any.then(|| ModemAccessTech::Any).into_iter();
519
520 let other_iter = ModemAccessTech::ALL
521 .into_iter()
522 .map(|v| *v)
523 .filter(move |t| allow_others && self.0 & *t as u32 > 0);
524
525 unknown_iter.chain(any_iter).chain(other_iter)
526 }
527}
528
529impl From<u32> for ModemAccessTechs {
530 fn from(num: u32) -> Self {
531 Self(num)
532 }
533}
534
535impl From<ModemAccessTechs> for u32 {
536 fn from(a: ModemAccessTechs) -> Self {
537 a.0
538 }
539}
540
541const MODE_NONE: u32 = 0;
542const MODE_CS: u32 = 1 << 0;
544const MODE_2G: u32 = 1 << 1;
546const MODE_3G: u32 = 1 << 2;
548const MODE_4G: u32 = 1 << 3;
550const MODE_5G: u32 = 1 << 4;
552const MODE_ANY: u32 = u32::MAX;
554
555#[derive(Debug, Clone, Copy, PartialEq, Eq)]
557pub struct ModemMode(u32);
558
559impl ModemMode {
560 pub fn new() -> Self {
562 ModemMode(MODE_NONE)
563 }
564
565 pub fn is_any(&self) -> bool {
567 self.0 == MODE_ANY
568 }
569
570 pub fn set_any(&mut self) {
572 self.0 = MODE_ANY;
573 }
574
575 pub fn is_none(&self) -> bool {
577 self.0 == MODE_NONE
578 }
579
580 pub fn has_cs(&self) -> bool {
582 self.0 & MODE_CS > 0
583 }
584
585 pub fn set_cs(&mut self) {
587 self.0 |= MODE_CS;
588 }
589
590 pub fn has_2g(&self) -> bool {
592 self.0 & MODE_2G > 0
593 }
594
595 pub fn set_2g(&mut self) {
597 self.0 |= MODE_2G;
598 }
599
600 pub fn has_3g(&self) -> bool {
602 self.0 & MODE_3G > 0
603 }
604
605 pub fn set_3g(&mut self) {
607 self.0 |= MODE_3G;
608 }
609
610 pub fn has_4g(&self) -> bool {
612 self.0 & MODE_4G > 0
613 }
614
615 pub fn set_4g(&mut self) {
617 self.0 |= MODE_4G;
618 }
619
620 pub fn has_5g(&self) -> bool {
622 self.0 & MODE_5G > 0
623 }
624
625 pub fn set_5g(&mut self) {
627 self.0 |= MODE_5G;
628 }
629}
630
631impl From<u32> for ModemMode {
632 fn from(num: u32) -> Self {
633 Self(num)
634 }
635}
636
637impl From<ModemMode> for u32 {
638 fn from(mode: ModemMode) -> Self {
639 mode.0
640 }
641}
642
643macro_rules! modem_band {
644 ($($var:ident = $expr:expr),*) => (
645 #[repr(u32)]
646 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
647 #[cfg_attr(
648 feature = "serde",
649 derive(serde1::Serialize, serde1::Deserialize),
650 serde(crate = "serde1")
651 )]
652 #[non_exhaustive]
653 pub enum ModemBand {
654 $($var = $expr),*
655 }
656
657 impl From<u32> for ModemBand {
658 fn from(num: u32) -> Self {
659 match num {
660 $($expr => Self::$var),*,
661 _ => Self::Unknown
662 }
663 }
664 }
665
666 impl From<ModemBand> for u32 {
667 fn from(b: ModemBand) -> Self {
668 b as u32
669 }
670 }
671 )
672}
673
674modem_band! {
675 Unknown = 0,
676 Egsm = 1,
678 Dcs = 2,
679 Pcs = 3,
680 G850 = 4,
681 Utran1 = 5,
682 Utran3 = 6,
683 Utran4 = 7,
684 Utran6 = 8,
685 Utran5 = 9,
686 Utran8 = 10,
687 Utran9 = 11,
688 Utran2 = 12,
689 Utran7 = 13,
690 G450 = 14,
691 G480 = 15,
692 G750 = 16,
693 G380 = 17,
694 G410 = 18,
695 G710 = 19,
696 G810 = 20,
697 Eutran1 = 31,
699 Eutran2 = 32,
700 Eutran3 = 33,
701 Eutran4 = 34,
702 Eutran5 = 35,
703 Eutran6 = 36,
704 Eutran7 = 37,
705 Eutran8 = 38,
706 Eutran9 = 39,
707 Eutran10 = 40,
708 Eutran11 = 41,
709 Eutran12 = 42,
710 Eutran13 = 43,
711 Eutran14 = 44,
712 Eutran17 = 47,
713 Eutran18 = 48,
714 Eutran19 = 49,
715 Eutran20 = 50,
716 Eutran21 = 51,
717 Eutran22 = 52,
718 Eutran23 = 53,
719 Eutran24 = 54,
720 Eutran25 = 55,
721 Eutran26 = 56,
722 Eutran27 = 57,
723 Eutran28 = 58,
724 Eutran29 = 59,
725 Eutran30 = 60,
726 Eutran31 = 61,
727 Eutran32 = 62,
728 Eutran33 = 63,
729 Eutran34 = 64,
730 Eutran35 = 65,
731 Eutran36 = 66,
732 Eutran37 = 67,
733 Eutran38 = 68,
734 Eutran39 = 69,
735 Eutran40 = 70,
736 Eutran41 = 71,
737 Eutran42 = 72,
738 Eutran43 = 73,
739 Eutran44 = 74,
740 Eutran45 = 75,
741 Eutran46 = 76,
742 Eutran47 = 77,
743 Eutran48 = 78,
744 Eutran49 = 79,
745 Eutran50 = 80,
746 Eutran51 = 81,
747 Eutran52 = 82,
748 Eutran53 = 83,
749 Eutran54 = 84,
750 Eutran55 = 85,
751 Eutran56 = 86,
752 Eutran57 = 87,
753 Eutran58 = 88,
754 Eutran59 = 89,
755 Eutran60 = 90,
756 Eutran61 = 91,
757 Eutran62 = 92,
758 Eutran63 = 93,
759 Eutran64 = 94,
760 Eutran65 = 95,
761 Eutran66 = 96,
762 Eutran67 = 97,
763 Eutran68 = 98,
764 Eutran69 = 99,
765 Eutran70 = 100,
766 Eutran71 = 101,
767 CdmaBc0 = 128,
769 CdmaBc1 = 129,
770 CdmaBc2 = 130,
771 CdmaBc3 = 131,
772 CdmaBc4 = 132,
773 CdmaBc5 = 134,
774 CdmaBc6 = 135,
775 CdmaBc7 = 136,
776 CdmaBc8 = 137,
777 CdmaBc9 = 138,
778 CdmaBc10 = 139,
779 CdmaBc11 = 140,
780 CdmaBc12 = 141,
781 CdmaBc13 = 142,
782 CdmaBc14 = 143,
783 CdmaBc15 = 144,
784 CdmaBc16 = 145,
785 CdmaBc17 = 146,
786 CdmaBc18 = 147,
787 CdmaBc19 = 148,
788 Utran10 = 210,
794 Utran11 = 211,
795 Utran12 = 212,
796 Utran13 = 213,
797 Utran14 = 214,
798 Utran19 = 219,
799 Utran20 = 220,
800 Utran21 = 221,
801 Utran22 = 222,
802 Utran25 = 225,
803 Utran26 = 226,
804 Utran32 = 232,
805 Any = 256
807}
808
809#[derive(Debug, Clone, Copy, PartialEq)]
810#[cfg_attr(
811 feature = "serde",
812 derive(serde1::Serialize, serde1::Deserialize),
813 serde(crate = "serde1", rename = "camelCase")
814)]
815pub struct SignalCdma {
816 pub rssi: f64,
818 pub ecio: f64,
820}
821
822impl SignalCdma {
823 fn from_prop_map(prop: PropMap) -> Option<Self> {
824 Some(Self {
825 rssi: prop.get("rssi")?.as_f64()?,
826 ecio: prop.get("ecio")?.as_f64()?,
827 })
828 }
829}
830
831#[derive(Debug, Clone, Copy, PartialEq)]
832#[cfg_attr(
833 feature = "serde",
834 derive(serde1::Serialize, serde1::Deserialize),
835 serde(crate = "serde1", rename = "camelCase")
836)]
837pub struct SignalEvdo {
838 pub rssi: f64,
840 pub ecio: f64,
842 pub sinr: f64,
844 pub io: f64,
846}
847
848impl SignalEvdo {
849 fn from_prop_map(prop: PropMap) -> Option<Self> {
850 Some(Self {
851 rssi: prop.get("rssi")?.as_f64()?,
852 ecio: prop.get("ecio")?.as_f64()?,
853 sinr: prop.get("sinr")?.as_f64()?,
854 io: prop.get("io")?.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")?.as_f64()?,
874 })
875 }
876}
877
878#[derive(Debug, Clone, Copy, PartialEq)]
879#[cfg_attr(
880 feature = "serde",
881 derive(serde1::Serialize, serde1::Deserialize),
882 serde(crate = "serde1", rename = "camelCase")
883)]
884pub struct SignalUmts {
885 pub rssi: f64,
887 pub rscp: f64,
891 pub ecio: f64,
893}
894
895impl SignalUmts {
896 fn from_prop_map(prop: PropMap) -> Option<Self> {
897 Some(Self {
898 rssi: prop.get("rssi")?.as_f64()?,
899 rscp: prop.get("rscp").and_then(|v| v.as_f64()).unwrap_or(0f64),
901 ecio: prop.get("ecio")?.as_f64()?,
902 })
903 }
904}
905
906#[derive(Debug, Clone, Copy, PartialEq)]
907#[cfg_attr(
908 feature = "serde",
909 derive(serde1::Serialize, serde1::Deserialize),
910 serde(crate = "serde1", rename = "camelCase")
911)]
912pub struct SignalLte {
913 pub rssi: f64,
915 pub rsrq: f64,
917 pub rsrp: f64,
919 pub snr: f64,
921}
922
923impl SignalLte {
924 fn from_prop_map(prop: PropMap) -> Option<Self> {
925 Some(Self {
926 rssi: prop.get("rssi")?.as_f64()?,
927 rsrq: prop.get("rsrq")?.as_f64()?,
928 rsrp: prop.get("rsrp")?.as_f64()?,
929 snr: prop.get("snr")?.as_f64()?,
930 })
931 }
932}
933
934#[derive(Debug, Clone, Copy, PartialEq)]
935#[cfg_attr(
936 feature = "serde",
937 derive(serde1::Serialize, serde1::Deserialize),
938 serde(crate = "serde1", rename = "camelCase")
939)]
940pub struct SignalNr5g {
941 pub rsrq: f64,
942 pub rsrp: f64,
943 pub snr: f64,
944}
945
946impl SignalNr5g {
947 fn from_prop_map(prop: PropMap) -> Option<Self> {
948 Some(Self {
949 rsrq: prop.get("rsrq")?.as_f64()?,
950 rsrp: prop.get("rsrp")?.as_f64()?,
951 snr: prop.get("snr")?.as_f64()?,
952 })
953 }
954}
955
956#[repr(u32)]
957#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
958#[cfg_attr(
959 feature = "serde",
960 derive(serde1::Serialize, serde1::Deserialize),
961 serde(crate = "serde1")
962)]
963#[non_exhaustive]
964pub enum RegistrationState {
965 Idle = 0,
967 Home = 1,
969 Searching = 2,
971 Denied = 3,
973 Unknown = 4,
975 Roaming = 5,
977}
978
979impl From<u32> for RegistrationState {
980 fn from(num: u32) -> Self {
981 if num > 5 {
982 Self::Unknown
983 } else {
984 unsafe { *(&num as *const u32 as *const Self) }
985 }
986 }
987}