Skip to main content

kobo_core/device/
impls.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Nayeem Bin Ahsan
3//! Production (Sys) implementations of the device traits.
4//!
5//! Each `Sys*` struct wraps the corresponding free functions in the device
6//! modules. Construct once at startup and pass `&dyn Trait` to code that needs
7//! testable device access.
8
9use std::path::PathBuf;
10
11use crate::device::battery;
12use crate::device::bt::{self as bt_mod, set_bt_bus};
13use crate::device::clock;
14use crate::device::config::SocFamily;
15use crate::device::fb::Fb;
16use crate::device::power;
17use crate::device::traits::{FrontlightPaths, *};
18use crate::device::wifi;
19
20// ---------------------------------------------------------------------------
21// SysFrontlight
22// ---------------------------------------------------------------------------
23
24/// Production frontlight: reads/writes real sysfs brightness files.
25pub struct SysFrontlight {
26    brightness_path: PathBuf,
27}
28
29impl SysFrontlight {
30    pub fn new(paths: &FrontlightPaths) -> Self {
31        SysFrontlight {
32            brightness_path: paths.brightness.clone(),
33        }
34    }
35
36    pub fn from_path(path: PathBuf) -> Self {
37        SysFrontlight {
38            brightness_path: path,
39        }
40    }
41}
42
43impl Frontlight for SysFrontlight {
44    fn get(&self) -> u32 {
45        power::frontlight_get(&self.brightness_path).unwrap_or(0)
46    }
47
48    fn set(&self, brightness: u32) {
49        power::frontlight_set(&self.brightness_path, brightness);
50    }
51
52    fn restore(&self, brightness: u32) {
53        power::restore_frontlight(&self.brightness_path, brightness);
54    }
55}
56
57// ---------------------------------------------------------------------------
58// SysBattery
59// ---------------------------------------------------------------------------
60
61/// Production battery: reads `/sys/class/power_supply/*/capacity`.
62pub struct SysBattery;
63
64impl Battery for SysBattery {
65    fn pct(&self) -> i32 {
66        battery::battery_pct()
67    }
68}
69
70// ---------------------------------------------------------------------------
71// SysWifi
72// ---------------------------------------------------------------------------
73
74/// Production wifi: reads `/sys/class/net/wlan0/operstate`.
75pub struct SysWifi;
76
77impl Wifi for SysWifi {
78    fn connected(&self) -> bool {
79        wifi::wifi_status()
80    }
81
82    fn ssid(&self) -> Option<String> {
83        wifi::wifi_name()
84    }
85
86    fn toggle(&self, on: bool) {
87        wifi::wifi_toggle(on);
88    }
89}
90
91// ---------------------------------------------------------------------------
92// SysBluetooth
93// ---------------------------------------------------------------------------
94
95/// Production bluetooth: DBus calls to bluez / mtk.bluedroid.
96pub struct SysBluetooth;
97
98impl SysBluetooth {
99    /// Initialize the DBus bus name for the device's SoC family.
100    /// Call once at startup after device detection.
101    pub fn init(soc: SocFamily) -> Self {
102        set_bt_bus(soc);
103        SysBluetooth
104    }
105}
106
107impl Bluetooth for SysBluetooth {
108    fn connected(&self) -> bool {
109        bt_mod::bt_status()
110    }
111
112    fn name(&self) -> Option<String> {
113        bt_mod::bt_name()
114    }
115
116    fn toggle(&self, on: bool) {
117        bt_mod::bt_toggle(on);
118    }
119}
120
121// ---------------------------------------------------------------------------
122// SysSystemControl
123// ---------------------------------------------------------------------------
124
125/// Production system control: kernel suspend via `/sys/power/state`,
126/// wall-clock via `date` command.
127pub struct SysSystemControl;
128
129impl SystemControl for SysSystemControl {
130    fn suspend(&self, state: &str) {
131        power::kernel_suspend(state);
132    }
133
134    fn clock(&self) -> String {
135        clock::current_clock()
136    }
137}
138
139// ---------------------------------------------------------------------------
140// SysFramebuffer
141// ---------------------------------------------------------------------------
142
143/// Production framebuffer: wraps [`Fb`] (mmap'd `/dev/fb0` + MXCFB refresh).
144pub struct SysFramebuffer<'a> {
145    fb: &'a Fb,
146}
147
148impl<'a> SysFramebuffer<'a> {
149    pub fn new(fb: &'a Fb) -> Self {
150        SysFramebuffer { fb }
151    }
152}
153
154impl<'a> Framebuffer for SysFramebuffer<'a> {
155    fn resolution(&self) -> (usize, usize) {
156        (self.fb.xres, self.fb.yres)
157    }
158
159    fn present(
160        &self,
161        buf: &[u8],
162        w: usize,
163        h: usize,
164        full: bool,
165        top: usize,
166        rh: usize,
167        waveform: u32,
168    ) {
169        self.fb.present(buf, w, h, full, top, rh, waveform);
170    }
171}
172
173/// Resolve frontlight sysfs paths from a [`crate::device::config::FrontlightConfig`].
174pub fn resolve_frontlight_paths(
175    fl_cfg: &crate::device::config::FrontlightConfig,
176) -> FrontlightPaths {
177    FrontlightPaths {
178        brightness: power::known_brightness_path(fl_cfg),
179        mixer: power::frontlight_path(fl_cfg),
180    }
181}