rktk/task/mod.rs
1//! Program entrypoint.
2
3use crate::{
4 config::Hand,
5 drivers::interface::{
6 debounce::DebounceDriver, display::DisplayDriver, encoder::EncoderDriver,
7 keyscan::KeyscanDriver, mouse::MouseDriver, rgb::RgbDriver, split::SplitDriver,
8 storage::StorageDriver, usb::UsbReporterDriverBuilder,
9 wireless::WirelessReporterDriverBuilder,
10 },
11 hooks::AllHooks,
12};
13use crate::{
14 drivers::{Drivers, interface::system::SystemDriver},
15 hooks::interface::*,
16 utils::sjoin,
17};
18use display::DisplayConfig;
19use embassy_futures::join::{join, join5};
20use embassy_time::Duration;
21use rktk_log::{debug, info};
22
23pub(crate) mod channels;
24// `display` module is public as internally used by macros
25pub mod display;
26mod initializers;
27#[cfg(feature = "rrp-log")]
28mod logger;
29mod master;
30mod rgb;
31mod slave;
32mod split_handler;
33
34/// Runs rktk with the given drivers and key configuration.
35///
36/// # Parameters
37/// - `drivers`: Drivers for the keyboard.
38/// - `hooks`: Hooks for the keyboard. See [`Hooks`] for detail.
39/// - `opts`: Other options such as keymap. See [`crate::config`] for detail.
40#[allow(clippy::type_complexity)]
41pub async fn start<
42 System: SystemDriver,
43 KeyScan: KeyscanDriver,
44 Debounce: DebounceDriver,
45 Encoder: EncoderDriver,
46 Rgb: RgbDriver,
47 Storage: StorageDriver,
48 Split: SplitDriver,
49 Ble: WirelessReporterDriverBuilder,
50 Usb: UsbReporterDriverBuilder,
51 Display: DisplayDriver,
52 Mouse: MouseDriver,
53 H: AllHooks,
54 DC: DisplayConfig<Color = Display::Color> + 'static,
55 RL: blinksy::layout::Layout2d + 'static,
56>(
57 #[allow(unused_variables, reason = "`spawner` is unused when `alloc` is disabled")]
58 spawner: embassy_executor::Spawner,
59 mut drivers: Drivers<
60 System,
61 KeyScan,
62 Debounce,
63 Encoder,
64 Rgb,
65 Storage,
66 Split,
67 Ble,
68 Usb,
69 Display,
70 Mouse,
71 >,
72 hooks: H,
73 mut opts: crate::config::RktkOpts<DC, RL>,
74) {
75 #[cfg(feature = "rrp-log")]
76 {
77 debug!("log init");
78 critical_section::with(|_| unsafe {
79 let _ = log::set_logger_racy(&logger::RRP_LOGGER);
80 log::set_max_level_racy(log::LevelFilter::Info);
81 });
82 }
83
84 info!("Booting rktk");
85
86 drivers
87 .system
88 .double_reset_usb_boot(Duration::from_millis(opts.config.rktk.double_tap_threshold))
89 .await;
90
91 let mut hooks = hooks.destructure();
92
93 sjoin::join!(
94 spawner,
95 async {
96 initializers::init_mouse(&mut drivers.mouse, opts.config).await;
97 let ((wireless, wireless_task), (usb, usb_task)) =
98 initializers::init_reporters(drivers.ble_builder, drivers.usb_builder).await;
99
100 sjoin::join!(
101 spawner,
102 async {
103 let hand = opts.hand.unwrap_or(Hand::Left);
104 crate::utils::display_state!(Hand, Some(hand));
105
106 let role =
107 initializers::init_split(opts.config, drivers.split, &usb, &wireless).await;
108
109 hooks
110 .common
111 .on_init(
112 hand,
113 &mut drivers.keyscan,
114 drivers.mouse.as_mut(),
115 drivers.storage.as_mut(),
116 )
117 .await;
118
119 crate::utils::display_state!(Master, Some(role.is_master()));
120
121 match role {
122 initializers::KeyboardRoleRes::Master { sender, receiver, task } => {
123 info!("Master start");
124 sjoin::join!(
125 spawner,
126 async {
127 let config_store =
128 master::utils::init_storage(drivers.storage).await;
129
130 if KeyScan::CALIBRATION_SIZE > 0
131 && let Some(ref store) = config_store
132 {
133 let mut buf =
134 [0u8; crate::config::CONST_CONFIG.buffer.calibration];
135 if let Ok(()) = store.read_calibration::<{ crate::config::CONST_CONFIG.buffer.calibration }>(&mut buf).await {
136 if drivers.keyscan.load_calibration(&buf[..KeyScan::CALIBRATION_SIZE]).is_err() {
137 rktk_log::error!("Failed to load calibration data into keyscan driver");
138 } else {
139 rktk_log::info!("Calibration data loaded successfully");
140 }
141 }
142 }
143
144 let state = master::utils::load_state(
145 &opts.config.key_manager,
146 &config_store,
147 opts.keymap,
148 )
149 .await;
150
151 hooks
152 .master
153 .on_master_init(
154 &mut drivers.keyscan,
155 drivers.mouse.as_mut(),
156 )
157 .await;
158
159 join(
160 join5(
161 master::report::report_task(
162 opts.config,
163 &drivers.system,
164 &state,
165 &config_store,
166 &wireless,
167 &usb,
168 hooks.master,
169 ),
170 master::handle_slave::start(
171 opts.config,
172 hand,
173 receiver,
174 ),
175 master::handle_keyboard::start(
176 opts.config,
177 hand,
178 drivers.keyscan,
179 &mut drivers.debounce,
180 &config_store,
181 ),
182 master::handle_mouse::start(opts.config, drivers.mouse),
183 master::handle_encoder::start(&mut drivers.encoder),
184 ),
185 async {
186 #[cfg(feature = "rrp")]
187 master::rrp_server::start(
188 opts.config,
189 &usb,
190 &wireless,
191 &state,
192 &config_store,
193 )
194 .await;
195 },
196 )
197 .await;
198 },
199 rgb::start::<RL, _>(
200 opts.config,
201 drivers.rgb,
202 hooks.rgb,
203 Some(sender)
204 ),
205 async move {
206 if let Some(task) = task {
207 task.await;
208 }
209 }
210 );
211 }
212 initializers::KeyboardRoleRes::Slave { sender, receiver, task } => {
213 debug!("Slave start");
214 sjoin::join!(
215 spawner,
216 async move {
217 slave::start(
218 opts.config,
219 sender,
220 receiver,
221 drivers.keyscan,
222 &mut drivers.debounce,
223 drivers.mouse,
224 hooks.slave,
225 )
226 .await
227 },
228 rgb::start::<RL, _>(opts.config, drivers.rgb, hooks.rgb, None),
229 async move {
230 if let Some(task) = task {
231 task.await;
232 }
233 }
234 );
235 }
236 }
237 },
238 async {
239 if let Some(usb_task) = usb_task {
240 usb_task.await
241 }
242 },
243 async {
244 if let Some(wireless_task) = wireless_task {
245 wireless_task.await
246 }
247 }
248 );
249 },
250 async move {
251 if let Some(mut display) = drivers.display {
252 display::start(&mut display, &mut opts.display).await;
253 }
254 }
255 );
256}
RKTK API Docs