Krolyxon
Commit b1f5115

Branches

Refs →

budctlcratesbudctl-coresrcstatus.rs

205 lines · 6.4 KB · Rust

1//! What a session reports, in device-neutral terms. Front ends print these, and `--json`
2//! serializes them as they are.
3
4use serde::{Serialize, Serializer};
5
6/// Bumped whenever the JSON shape changes incompatibly.
7pub const JSON_SCHEMA: u32 = 1;
8
9#[derive(Debug, Default, Clone, Serialize)]
10pub struct Status {
11 pub battery: Battery,
12 pub noise_control: Option<NoiseControl>,
13 /// Name of the current EQ preset.
14 pub eq: Option<String>,
15 pub bass_level: Option<i8>,
16 /// On/off settings, serialized as `{"game": false, …}`.
17 #[serde(serialize_with = "switches_as_map")]
18 pub switches: Vec<Switch>,
19 /// Audio codec of the link the buds report.
20 pub codec: Option<String>,
21 pub firmware: Option<String>,
22 /// Reads that failed. The rest of the status is still valid.
23 pub warnings: Vec<String>,
24}
25
26#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize)]
27pub struct Battery {
28 pub left: Option<Charge>,
29 pub right: Option<Charge>,
30 pub case: Option<Charge>,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
34pub struct Charge {
35 /// Percent.
36 pub level: u8,
37 pub charging: bool,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
41pub struct NoiseControl {
42 /// `off`, `transparency` or `anc`, or `unknown (…)` for a value the device module cannot name.
43 pub mode: String,
44 /// The noise-cancelling level, when the device reports one.
45 pub level: Option<String>,
46}
47
48/// A noise-control mode to set.
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum NoiseMode {
51 Off,
52 Transparency,
53 Anc(AncLevel),
54}
55
56/// How strongly noise cancelling works.
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum AncLevel {
59 Light,
60 Medium,
61 Deep,
62}
63
64impl AncLevel {
65 /// The name [`NoiseControl::level`] uses for it.
66 pub fn name(self) -> &'static str {
67 match self {
68 AncLevel::Light => "light",
69 AncLevel::Medium => "medium",
70 AncLevel::Deep => "deep",
71 }
72 }
73}
74
75impl NoiseMode {
76 /// The name [`NoiseControl::mode`] uses for it.
77 pub fn name(self) -> &'static str {
78 match self {
79 NoiseMode::Off => "off",
80 NoiseMode::Transparency => "transparency",
81 NoiseMode::Anc(_) => "anc",
82 }
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
87pub struct Switch {
88 /// Stable name used on the command line and in JSON (`game`, `dual`…).
89 pub key: &'static str,
90 /// Human name (`Game mode`).
91 pub label: &'static str,
92 pub on: bool,
93}
94
95#[derive(Debug, Default, Clone, Serialize)]
96pub struct TouchControls {
97 pub gestures: Vec<Gesture>,
98 /// Noise-control modes a hold steps through, when the device has that setting.
99 pub hold_cycle: Option<Vec<String>>,
100 /// The actions each gesture can be given, when the device can change them.
101 pub choices: Vec<GestureChoice>,
102 /// The modes the hold cycle can include, when the device can change it.
103 pub cycle_modes: Vec<String>,
104 pub warnings: Vec<String>,
105}
106
107/// The actions one gesture can be given, as the device offers them, in its order.
108#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
109pub struct GestureChoice {
110 /// `double-tap`, `triple-tap`, `hold`…
111 pub gesture: String,
112 /// `none`, `play-pause`…
113 pub actions: Vec<String>,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
117pub struct Gesture {
118 /// `left`, `right` or `both`.
119 pub side: String,
120 /// `double-tap`, `triple-tap`, `hold`…
121 pub gesture: String,
122 /// `play-pause`, `next`, `none`…
123 pub action: String,
124 /// Raw button group, for entries outside the main gestures (calls). `None` for the main group.
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub group: Option<u8>,
127}
128
129/// The EQ presets the buds have, and which one is in use.
130#[derive(Debug, Default, Clone, Serialize)]
131pub struct EqPresets {
132 /// Name of the preset in use, as in [`Status::eq`].
133 pub current: Option<String>,
134 /// Built-in presets first, then custom ones.
135 pub presets: Vec<EqPreset>,
136 /// Reads that failed. The rest is still valid.
137 pub warnings: Vec<String>,
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
141pub struct EqPreset {
142 /// Built-in presets: the name `eq <preset>` takes. Custom ones: the name stored on the buds.
143 pub name: String,
144 /// The buds' id for it.
145 pub id: u8,
146 pub custom: bool,
147 /// Custom presets only: gain per band. Empty for built-in presets.
148 pub bands: Vec<EqBand>,
149 /// Custom presets only: the lowest and the highest gain a band takes, dB.
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub range: Option<(i8, i8)>,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
155pub struct EqBand {
156 pub hz: u16,
157 /// dB.
158 pub gain: i8,
159}
160
161/// A touch-control change: what changes, the write that does it and, once sent, the table the
162/// buds report afterwards.
163#[derive(Debug, Serialize)]
164pub struct TouchChange {
165 /// The entries that change. Empty when every target already has the wanted action.
166 pub changes: Vec<GestureChange>,
167 /// The write that makes the change, or `None` when there is nothing to change.
168 pub write: Option<RawWrite>,
169 /// Whether the write went out. `false` on a dry run and when nothing changes.
170 pub sent: bool,
171 /// The whole table: as read back after the write, or as it would be after a dry run.
172 pub gestures: Vec<Gesture>,
173}
174
175#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
176pub struct GestureChange {
177 pub side: String,
178 pub gesture: String,
179 pub from: String,
180 pub to: String,
181}
182
183/// One command and its payload, as `--dry-run` shows them. The frame around it (sequence byte
184/// and so on) is added when it is sent.
185#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
186pub struct RawWrite {
187 /// `0x0401`.
188 #[serde(serialize_with = "command_as_hex")]
189 pub command: u16,
190 /// `06 01 01 02 01 …`.
191 #[serde(serialize_with = "bytes_as_hex")]
192 pub payload: Vec<u8>,
193}
194
195fn command_as_hex<S: Serializer>(command: &u16, serializer: S) -> Result<S::Ok, S::Error> {
196 serializer.serialize_str(&format!("0x{command:04X}"))
197}
198
199fn bytes_as_hex<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
200 serializer.serialize_str(&crate::debug::hex(bytes))
201}
202
203fn switches_as_map<S: Serializer>(switches: &[Switch], serializer: S) -> Result<S::Ok, S::Error> {
204 serializer.collect_map(switches.iter().map(|s| (s.key, s.on)))
205}