Krolyxon
Commit c7666c2

Branches

Refs →

budctlcratesbudctl-coresrcdevicesmod.rs

125 lines · 5.0 KB · Rust

1//! Device plugins.
2//!
3//! To support a new pair of buds, add one module here and list it in [`REGISTRY`]. Transport,
4//! CLI and GUI code do not change.
5
6use crate::bluez::PairedDevice;
7use crate::bt::Uuid;
8use crate::error::{Error, Result};
9use crate::status::{EqBand, EqPreset, EqPresets, NoiseControl, NoiseMode, Status, Switch, TouchChange, TouchControls};
10use crate::transport::Transport;
11
12pub mod realme_t310;
13
14/// Every model budctl supports.
15pub static REGISTRY: &[&dyn Device] = &[&realme_t310::RealmeT310];
16
17/// One supported model.
18pub trait Device: Sync {
19 /// Model name, e.g. `realme Buds T310`.
20 fn name(&self) -> &'static str;
21
22 /// Whether a paired device is this model, judged from BlueZ data alone.
23 fn matches(&self, device: &PairedDevice) -> bool;
24
25 /// The control service(s), in the order to try. SDP turns each into an RFCOMM channel.
26 fn rfcomm_uuids(&self) -> &'static [Uuid];
27
28 /// Run the model's init sequence on a fresh link and return a ready session.
29 fn open(&self, link: Box<dyn Transport>) -> Result<Box<dyn Session>>;
30}
31
32/// An open control link to one pair of buds. Dropping it closes the link.
33pub trait Session: Send {
34 /// Answer what the buds sent since the last call, without waiting. Some buds drop the link
35 /// when their own requests (the time request, for one) go unanswered, so a front end that
36 /// keeps a session open between commands calls this every so often. An error means the link
37 /// is gone.
38 fn serve(&mut self) -> Result<()> {
39 Ok(())
40 }
41
42 /// Battery, noise control, EQ, switches and whatever else the model can read.
43 fn status(&mut self) -> Result<Status>;
44
45 /// The touch-control (gesture) settings of each bud.
46 fn touch_controls(&mut self) -> Result<TouchControls> {
47 Err(Error::Unsupported(
48 "these buds have no touch-control settings budctl can read".to_owned(),
49 ))
50 }
51
52 /// Set the noise-control mode, then read it back. Returns the mode the buds now report.
53 fn set_noise_control(&mut self, _mode: NoiseMode) -> Result<NoiseControl> {
54 Err(Error::Unsupported(
55 "these buds have no noise-control setting budctl can change".to_owned(),
56 ))
57 }
58
59 /// The EQ presets on the buds, built-in and custom, and the one in use.
60 fn eq_presets(&mut self) -> Result<EqPresets> {
61 Err(Error::Unsupported(
62 "budctl cannot list the EQ presets of these buds".to_owned(),
63 ))
64 }
65
66 /// Select a built-in EQ preset by name, then read it back. Returns the preset now in use.
67 fn set_eq(&mut self, _preset: &str) -> Result<String> {
68 Err(Error::Unsupported(
69 "budctl cannot change the EQ on these buds".to_owned(),
70 ))
71 }
72
73 /// Change the gains of some bands of a custom EQ preset (`custom-<id>`), save it and select
74 /// it, then read it back. With no bands, it only selects the preset.
75 fn set_custom_eq(&mut self, preset: &str, _bands: &[EqBand]) -> Result<EqPreset> {
76 Err(Error::Unsupported(format!(
77 "budctl cannot change {preset} on these buds"
78 )))
79 }
80
81 /// The lowest and the highest level [`Session::set_bass_level`] takes, when the buds have a
82 /// bass level to set.
83 fn bass_range(&self) -> Option<(i8, i8)> {
84 None
85 }
86
87 /// Set the bass level. Only the ack can be checked when the buds cannot report the level.
88 fn set_bass_level(&mut self, _level: i8) -> Result<()> {
89 Err(Error::Unsupported(
90 "budctl cannot change the bass level on these buds".to_owned(),
91 ))
92 }
93
94 /// Start (`true`) or stop ringing the buds so they can be found. Only the ack can be
95 /// checked: there is no state to read back.
96 fn find(&mut self, _ring: bool) -> Result<()> {
97 Err(Error::Unsupported("these buds cannot ring through budctl".to_owned()))
98 }
99
100 /// Turn an on/off setting ([`Switch::key`]) on or off, then read it back.
101 fn set_switch(&mut self, key: &str, _on: bool) -> Result<Switch> {
102 Err(Error::Unsupported(format!("budctl cannot change {key} on these buds")))
103 }
104
105 /// Set the noise-control modes a hold steps through (`off`, `transparency`, `anc`), then
106 /// read it back. Returns the modes the buds now report.
107 fn set_hold_cycle(&mut self, _modes: &[&str]) -> Result<Vec<String>> {
108 Err(Error::Unsupported(
109 "budctl cannot change the hold cycle on these buds".to_owned(),
110 ))
111 }
112
113 /// Give a touch gesture a new action, on `side` (`left`, `right` or `both`), then read the
114 /// table back. With `dry_run`, read the table and work out the write, but send nothing.
115 fn set_touch(&mut self, _side: &str, _gesture: &str, _action: &str, _dry_run: bool) -> Result<TouchChange> {
116 Err(Error::Unsupported(
117 "budctl cannot change the touch controls on these buds".to_owned(),
118 ))
119 }
120}
121
122/// The supported model a paired device is, if any.
123pub fn identify(device: &PairedDevice) -> Option<&'static dyn Device> {
124 REGISTRY.iter().copied().find(|model| model.matches(device))
125}