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, Hooks},
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 + 'static,
55 RL: blinksy::layout::Layout2d + 'static,
56>(
57 #[allow(
58 unused_variables,
59 reason = "`spawner` is unused when `alloc` is disabled"
60 )]
61 spawner: embassy_executor::Spawner,
62 mut drivers: Drivers<
63 System,
64 KeyScan,
65 Debounce,
66 Encoder,
67 Rgb,
68 Storage,
69 Split,
70 Ble,
71 Usb,
72 Display,
73 Mouse,
74 >,
75 hooks: H,
76 mut opts: crate::config::RktkOpts<DC, RL>,
77) {
78 #[cfg(feature = "rrp-log")]
79 {
80 debug!("log init");
81 critical_section::with(|_| unsafe {
82 let _ = log::set_logger_racy(&logger::RRP_LOGGER);
83 log::set_max_level_racy(log::LevelFilter::Info);
84 });
85 }
86
87 info!("Booting rktk",);
88
89 drivers
90 .system
91 .double_reset_usb_boot(Duration::from_millis(opts.config.rktk.split_usb_timeout))
92 .await;
93
94 let mut hooks = hooks.destructure();
95
96 sjoin::join!(
97 spawner,
98 async {
99 initializers::init_mouse(&mut drivers.mouse, opts.config).await;
100 let ((wireless, wireless_task), (usb, usb_task)) =
101 initializers::init_reporters(drivers.ble_builder, drivers.usb_builder).await;
102
103 sjoin::join!(
104 spawner,
105 async {
106 let hand = opts.hand.unwrap_or(Hand::Left);
107 crate::utils::display_state!(Hand, Some(hand));
108
109 let role =
110 initializers::init_split(opts.config, drivers.split, &usb, &wireless).await;
111
112 hooks
113 .common
114 .on_init(
115 hand,
116 &mut drivers.keyscan,
117 drivers.mouse.as_mut(),
118 drivers.storage.as_mut(),
119 )
120 .await;
121
122 crate::utils::display_state!(Master, Some(role.is_master()));
123
124 match role {
125 initializers::KeyboardRoleRes::Master {
126 sender,
127 receiver,
128 task,
129 } => {
130 info!("Master start");
131 sjoin::join!(
132 spawner,
133 async {
134 let config_store =
135 master::utils::init_storage(drivers.storage).await;
136 let state = master::utils::load_state(
137 &opts.config.key_manager,
138 &config_store,
139 opts.keymap,
140 )
141 .await;
142
143 hooks
144 .master
145 .on_master_init(
146 &mut drivers.keyscan,
147 drivers.mouse.as_mut(),
148 )
149 .await;
150
151 join(
152 join5(
153 master::report::report_task(
154 opts.config,
155 &drivers.system,
156 &state,
157 &config_store,
158 &wireless,
159 &usb,
160 hooks.master,
161 ),
162 master::handle_slave::start(
163 opts.config,
164 hand,
165 receiver,
166 ),
167 master::handle_keyboard::start(
168 opts.config,
169 hand,
170 drivers.keyscan,
171 &mut drivers.debounce,
172 ),
173 master::handle_mouse::start(opts.config, drivers.mouse),
174 master::handle_encoder::start(&mut drivers.encoder),
175 ),
176 async {
177 #[cfg(feature = "rrp")]
178 master::rrp_server::start(
179 opts.config,
180 &usb,
181 &wireless,
182 &state,
183 &config_store,
184 )
185 .await;
186 },
187 )
188 .await;
189 },
190 rgb::start::<RL, _>(
191 opts.config,
192 drivers.rgb,
193 hooks.rgb,
194 Some(sender)
195 ),
196 async move {
197 if let Some(task) = task {
198 task.await;
199 }
200 }
201 );
202 }
203 initializers::KeyboardRoleRes::Slave {
204 sender,
205 receiver,
206 task,
207 } => {
208 debug!("Slave start");
209 sjoin::join!(
210 spawner,
211 async move {
212 slave::start(
213 opts.config,
214 sender,
215 receiver,
216 drivers.keyscan,
217 &mut drivers.debounce,
218 drivers.mouse,
219 hooks.slave,
220 )
221 .await
222 },
223 rgb::start::<RL, _>(opts.config, drivers.rgb, hooks.rgb, None),
224 async move {
225 if let Some(task) = task {
226 task.await;
227 }
228 }
229 );
230 }
231 }
232 },
233 async {
234 if let Some(usb_task) = usb_task {
235 usb_task.await
236 }
237 },
238 async {
239 if let Some(wireless_task) = wireless_task {
240 wireless_task.await
241 }
242 }
243 );
244 },
245 async move {
246 if let Some(mut display) = drivers.display {
247 display::start(&mut display, &mut opts.display).await;
248 }
249 }
250 );
251}