-
-
Notifications
You must be signed in to change notification settings - Fork 186
Expand file tree
/
Copy pathcentral.rs
More file actions
287 lines (258 loc) · 10.4 KB
/
Copy pathcentral.rs
File metadata and controls
287 lines (258 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#![no_std]
#![no_main]
mod vial;
#[macro_use]
mod macros;
mod keymap;
use defmt::{info, unwrap};
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_nrf::gpio::{Input, Output};
use embassy_nrf::interrupt::{self, InterruptExt};
use embassy_nrf::mode::Async;
use embassy_nrf::peripherals::{RNG, SAADC, USBD};
use embassy_nrf::saadc::{self, AnyInput, Input as _, Saadc};
use embassy_nrf::usb::Driver;
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
use embassy_nrf::{Peri, bind_interrupts, rng, usb};
use nrf_mpsl::Flash;
use nrf_sdc::mpsl::MultiprotocolServiceLayer;
use nrf_sdc::{self as sdc, mpsl};
use panic_probe as _;
use rand_chacha::ChaCha12Rng;
use rand_core::SeedableRng;
use rmk::ble::{BleTransport, build_ble_stack};
use rmk::config::{
BehaviorConfig, BleBatteryConfig, DeviceConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig,
};
use rmk::debounce::default_debouncer::DefaultDebouncer;
use rmk::event::*;
use rmk::futures::future::join;
use rmk::host::HostService;
use rmk::input_device::adc::{AnalogEventType, NrfAdc};
use rmk::input_device::battery::BatteryProcessor;
use rmk::input_device::rotary_encoder::RotaryEncoder;
use rmk::keyboard::Keyboard;
use rmk::matrix::Matrix;
use rmk::processor::builtin::led_indicator::KeyboardIndicatorProcessor;
use rmk::processor::builtin::wpm::WpmProcessor;
use rmk::split::ble::central::scan_peripherals;
use rmk::split::central::run_peripheral_manager;
use rmk::usb::UsbTransport;
use rmk::{HostResources, KeymapData, initialize_keymap_and_storage, run_all};
use static_cell::StaticCell;
use vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
bind_interrupts!(struct Irqs {
USBD => usb::InterruptHandler<USBD>;
SAADC => saadc::InterruptHandler;
RNG => rng::InterruptHandler<RNG>;
EGU0_SWI0 => nrf_sdc::mpsl::LowPrioInterruptHandler;
CLOCK_POWER => nrf_sdc::mpsl::ClockInterruptHandler, usb::vbus_detect::InterruptHandler;
RADIO => nrf_sdc::mpsl::HighPrioInterruptHandler;
TIMER0 => nrf_sdc::mpsl::HighPrioInterruptHandler;
RTC0 => nrf_sdc::mpsl::HighPrioInterruptHandler;
});
#[embassy_executor::task]
async fn mpsl_task(mpsl: &'static MultiprotocolServiceLayer<'static>) -> ! {
mpsl.run().await
}
/// How many outgoing L2CAP buffers per link
const L2CAP_TXQ: u8 = 3;
/// How many incoming L2CAP buffers per link
const L2CAP_RXQ: u8 = 3;
/// Size of L2CAP packets
const L2CAP_MTU: usize = 251;
fn build_sdc<'d, const N: usize>(
p: nrf_sdc::Peripherals<'d>,
rng: &'d mut rng::Rng<Async>,
mpsl: &'d MultiprotocolServiceLayer,
mem: &'d mut sdc::Mem<N>,
) -> Result<nrf_sdc::SoftdeviceController<'d>, nrf_sdc::Error> {
sdc::Builder::new()?
.support_scan()
.support_central()
.support_adv()
.support_peripheral()
.support_dle_peripheral()
.support_dle_central()
.support_phy_update_central()
.support_phy_update_peripheral()
.support_le_2m_phy()
.central_count(1)?
.peripheral_count(1)?
.buffer_cfg(L2CAP_MTU as u16, L2CAP_MTU as u16, L2CAP_TXQ, L2CAP_RXQ)?
.build(p, rng, mpsl, mem)
}
/// Initializes the SAADC peripheral in single-ended mode on the given pin.
fn init_adc(adc_pin: AnyInput, adc: Peri<'static, SAADC>) -> Saadc<'static, 1> {
// Then we initialize the ADC. We are only using one channel in this example.
let config = saadc::Config::default();
let channel_cfg = saadc::ChannelConfig::single_ended(adc_pin.degrade_saadc());
interrupt::SAADC.set_priority(interrupt::Priority::P3);
saadc::Saadc::new(adc, Irqs, config, [channel_cfg])
}
fn ble_addr() -> [u8; 6] {
let ficr = embassy_nrf::pac::FICR;
let high = u64::from(ficr.deviceid(1).read());
let addr = high << 32 | u64::from(ficr.deviceid(0).read());
let addr = addr | 0x0000_c000_0000_0000;
unwrap!(addr.to_le_bytes()[..6].try_into())
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("Hello RMK BLE!");
// Initialize the peripherals and nrf-sdc controller
let mut nrf_config = embassy_nrf::config::Config::default();
nrf_config.dcdc.reg0_voltage = Some(embassy_nrf::config::Reg0Voltage::_3V3);
nrf_config.dcdc.reg0 = true;
nrf_config.dcdc.reg1 = true;
let p = embassy_nrf::init(nrf_config);
let mpsl_p = mpsl::Peripherals::new(p.RTC0, p.TIMER0, p.TEMP, p.PPI_CH19, p.PPI_CH30, p.PPI_CH31);
let lfclk_cfg = mpsl::raw::mpsl_clock_lfclk_cfg_t {
source: mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8,
rc_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8,
rc_temp_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8,
accuracy_ppm: mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16,
skip_wait_lfclk_started: mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0,
};
static MPSL: StaticCell<MultiprotocolServiceLayer> = StaticCell::new();
static SESSION_MEM: StaticCell<mpsl::SessionMem<1>> = StaticCell::new();
let mpsl = MPSL.init(unwrap!(mpsl::MultiprotocolServiceLayer::with_timeslots(
mpsl_p,
Irqs,
lfclk_cfg,
SESSION_MEM.init(mpsl::SessionMem::new())
)));
spawner.spawn(mpsl_task(&*mpsl).unwrap());
let sdc_p = sdc::Peripherals::new(
p.PPI_CH17, p.PPI_CH18, p.PPI_CH20, p.PPI_CH21, p.PPI_CH22, p.PPI_CH23, p.PPI_CH24, p.PPI_CH25, p.PPI_CH26,
p.PPI_CH27, p.PPI_CH28, p.PPI_CH29,
);
let mut rng = rng::Rng::new(p.RNG, Irqs);
let mut rng_gen = ChaCha12Rng::from_rng(&mut rng).unwrap();
let mut sdc_mem = sdc::Mem::<8192>::new();
let sdc = unwrap!(build_sdc(sdc_p, &mut rng, mpsl, &mut sdc_mem));
let mut host_resources = HostResources::new();
let stack = build_ble_stack(sdc, ble_addr(), &mut rng_gen, &mut host_resources).await;
// Initialize usb driver
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
// Initialize flash
let flash = Flash::take(mpsl, p.NVMC);
// Initialize IO Pins
let (row_pins, col_pins) = config_matrix_pins_nrf!(peripherals: p, input: [P0_30, P0_31, P0_29, P0_02], output: [P0_28, P0_03, P1_10, P1_11, P1_13, P0_09, P0_10]);
// Initialize the ADC.
// We are only using one channel for detecting battery level
let adc_pin = p.P0_05.degrade_saadc();
let is_charging_pin = Input::new(p.P0_07, embassy_nrf::gpio::Pull::Up);
let saadc = init_adc(adc_pin, p.SAADC);
// Wait for ADC calibration.
saadc.calibrate().await;
// Keyboard config
let keyboard_device_config = DeviceConfig {
vid: 0x4c4b,
pid: 0x4643,
manufacturer: "Haobo",
product_name: "RMK Keyboard",
serial_number: "vial:f64c2b3c:000001",
};
let vial_config = VialConfig::new(VIAL_KEYBOARD_ID, VIAL_KEYBOARD_DEF, &[(0, 0), (1, 1)]);
let ble_battery_config = BleBatteryConfig::new(Some(is_charging_pin), true, None, false);
let storage_config = StorageConfig {
start_addr: 0xA0000,
num_sectors: 6,
..Default::default()
};
let rmk_config = RmkConfig {
device_config: keyboard_device_config,
vial_config,
ble_battery_config,
storage_config,
};
// Initialze keyboard stuffs
// Initialize the storage and keymap
let mut keymap_data = KeymapData::new_with_encoder(keymap::get_default_keymap(), keymap::get_default_encoder_map());
let mut behavior_config = BehaviorConfig::default();
behavior_config.morse.enable_flow_tap = true;
let key_config = PositionalConfig::default();
let (keymap, mut storage) = initialize_keymap_and_storage(
&mut keymap_data,
flash,
&storage_config,
&mut behavior_config,
&key_config,
)
.await;
let pin_a = Input::new(p.P1_06, embassy_nrf::gpio::Pull::None);
let pin_b = Input::new(p.P1_04, embassy_nrf::gpio::Pull::None);
let mut encoder = RotaryEncoder::with_resolution(pin_a, pin_b, 4, true, 0);
// Initialize the matrix and keyboard
let debouncer = DefaultDebouncer::new();
let mut matrix = Matrix::<_, _, _, 4, 7, true>::new(row_pins, col_pins, debouncer);
// let mut matrix = TestMatrix::<ROW, COL>::new();
let mut keyboard = Keyboard::new(&keymap);
let mut host_service = HostService::new(&keymap, &rmk_config);
// Read peripheral address from storage
let peripheral_addrs = storage.read_peripheral_addresses::<1>().await;
// Initialize the encoder processor
let mut adc_device = NrfAdc::new(
saadc,
[AnalogEventType::Battery],
embassy_time::Duration::from_secs(12),
None,
);
let mut batt_proc = BatteryProcessor::new(2000, 2806);
// Initialize the controllers
let mut capslock_led = KeyboardIndicatorProcessor::new(
Output::new(
p.P0_00,
embassy_nrf::gpio::Level::Low,
embassy_nrf::gpio::OutputDrive::Standard,
),
false,
rmk::types::led_indicator::LedIndicatorType::CapsLock,
);
// Peripheral battery monitor controller
// This controller subscribes to PeripheralBatteryEvent events
// and logs the battery level of each peripheral
use rmk::event::PeripheralBatteryEvent;
use rmk::macros::processor;
#[processor(subscribe = [PeripheralBatteryEvent, BatteryStatusEvent, LayerChangeEvent])]
struct PeripheralBatteryMonitor {}
impl PeripheralBatteryMonitor {
async fn on_peripheral_battery_event(&mut self, event: PeripheralBatteryEvent) {
info!("Peripheral {} battery status: {:?}", event.id, event);
}
async fn on_battery_status_event(&mut self, event: BatteryStatusEvent) {
info!("Central battery status: {:?}", event);
}
async fn on_layer_change_event(&mut self, event: LayerChangeEvent) {
info!("Layer changed to: {}", event.0);
}
}
let mut peripheral_battery_monitor = PeripheralBatteryMonitor {};
let mut usb_transport = UsbTransport::new(driver, rmk_config.device_config);
let mut ble_transport = BleTransport::new(&stack, rmk_config).await;
let mut wpm_processor = WpmProcessor::new();
// Start
join(
run_all!(
matrix,
encoder,
adc_device,
storage,
usb_transport,
ble_transport,
wpm_processor,
batt_proc,
keyboard,
host_service,
capslock_led,
peripheral_battery_monitor
),
join(
run_peripheral_manager::<4, 7, 4, 0, _>(0, &peripheral_addrs, &stack),
scan_peripherals(&stack, &peripheral_addrs),
),
)
.await;
}