1#![no_std]
14#![no_main]
15#![deny(missing_docs)]
16
17use core::ptr::addr_of;
18
19use capsules_core::virtualizers::virtual_aes_ccm::MuxAES128CCM;
20use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
21use capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice;
22use kernel::component::Component;
23use kernel::debug::PanicResources;
24use kernel::deferred_call::DeferredCallClient;
25use kernel::hil::i2c::I2CMaster;
26use kernel::hil::led::LedHigh;
27use kernel::hil::screen::Screen;
28use kernel::hil::symmetric_encryption::AES128;
29use kernel::hil::time::Counter;
30use kernel::platform::{KernelResources, SyscallDriverLookup};
31use kernel::scheduler::round_robin::RoundRobinSched;
32use kernel::utilities::single_thread_value::SingleThreadValue;
33#[allow(unused_imports)]
34use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
35use nrf52840::gpio::Pin;
36use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
37
38const LED1_PIN: Pin = Pin::P0_08;
40
41const VIBRA1_PIN: Pin = Pin::P0_19;
43
44const BUTTON_PIN: Pin = Pin::P0_17;
46
47const I2C_TEMP_SDA_PIN: Pin = Pin::P1_15;
49const I2C_TEMP_SCL_PIN: Pin = Pin::P0_02;
50
51const SRC_MAC: u16 = 0xf00f;
54const PAN_ID: u16 = 0xABCD;
55const DEFAULT_EXT_SRC_MAC: [u8; 8] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77];
56
57pub mod io;
59
60const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
63 capsules_system::process_policies::PanicFaultPolicy {};
64
65const NUM_PROCS: usize = 8;
67
68type ChipHw = nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>;
69type ProcessPrinterInUse = capsules_system::process_printer::ProcessPrinterText;
70
71static PANIC_RESOURCES: SingleThreadValue<PanicResources<ChipHw, ProcessPrinterInUse>> =
73 SingleThreadValue::new(PanicResources::new());
74
75kernel::stack_size! {0x1000}
76
77type Bmp280Sensor = components::bmp280::Bmp280ComponentType<
78 VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
79 capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, nrf52840::i2c::TWI<'static>>,
80>;
81type TemperatureDriver = components::temperature::TemperatureComponentType<Bmp280Sensor>;
82type RngDriver = components::rng::RngComponentType<nrf52840::trng::Trng<'static>>;
83
84type Ieee802154Driver = components::ieee802154::Ieee802154ComponentType<
85 nrf52840::ieee802154_radio::Radio<'static>,
86 nrf52840::aes::AesECB<'static>,
87>;
88
89pub struct Platform {
91 temperature: &'static TemperatureDriver,
92 ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
93 'static,
94 nrf52840::ble_radio::Radio<'static>,
95 VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
96 >,
97 ieee802154_radio: &'static Ieee802154Driver,
98 button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
99 pconsole: &'static capsules_core::process_console::ProcessConsole<
100 'static,
101 { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
102 VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
103 components::process_console::Capability,
104 >,
105 console: &'static capsules_core::console::Console<'static>,
106 gpio: &'static capsules_core::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
107 led: &'static capsules_core::led::LedDriver<
108 'static,
109 LedHigh<'static, nrf52840::gpio::GPIOPin<'static>>,
110 2,
111 >,
112 rng: &'static RngDriver,
113 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
114 analog_comparator: &'static capsules_extra::analog_comparator::AnalogComparator<
115 'static,
116 nrf52840::acomp::Comparator<'static>,
117 >,
118 alarm: &'static capsules_core::alarm::AlarmDriver<
119 'static,
120 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
121 'static,
122 nrf52840::rtc::Rtc<'static>,
123 >,
124 >,
125 screen: &'static capsules_extra::screen::screen::Screen<'static>,
126 scheduler: &'static RoundRobinSched<'static>,
127 systick: cortexm4::systick::SysTick,
128}
129
130impl SyscallDriverLookup for Platform {
131 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
132 where
133 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
134 {
135 match driver_num {
136 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
137 capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
138 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
139 capsules_core::led::DRIVER_NUM => f(Some(self.led)),
140 capsules_core::button::DRIVER_NUM => f(Some(self.button)),
141 capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
142 capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
143 capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)),
144 capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
145 capsules_extra::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
146 capsules_extra::screen::screen::DRIVER_NUM => f(Some(self.screen)),
147 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
148 _ => f(None),
149 }
150 }
151}
152
153impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
154 for Platform
155{
156 type SyscallDriverLookup = Self;
157 type SyscallFilter = ();
158 type ProcessFault = ();
159 type Scheduler = RoundRobinSched<'static>;
160 type SchedulerTimer = cortexm4::systick::SysTick;
161 type WatchDog = ();
162 type ContextSwitchCallback = ();
163
164 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
165 self
166 }
167 fn syscall_filter(&self) -> &Self::SyscallFilter {
168 &()
169 }
170 fn process_fault(&self) -> &Self::ProcessFault {
171 &()
172 }
173 fn scheduler(&self) -> &Self::Scheduler {
174 self.scheduler
175 }
176 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
177 &self.systick
178 }
179 fn watchdog(&self) -> &Self::WatchDog {
180 &()
181 }
182 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
183 &()
184 }
185}
186
187#[inline(never)]
191pub unsafe fn start() -> (
192 &'static kernel::Kernel,
193 Platform,
194 &'static nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>,
195) {
196 nrf52840::init();
197
198 kernel::deferred_call::initialize_deferred_call_state::<
200 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
201 >();
202
203 PANIC_RESOURCES.bind_to_thread::<<ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider>();
205
206 let ieee802154_ack_buf = static_init!(
207 [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
208 [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
209 );
210 let nrf52840_peripherals = static_init!(
212 Nrf52840DefaultPeripherals,
213 Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
214 );
215
216 nrf52840_peripherals.init();
218 let base_peripherals = &nrf52840_peripherals.nrf52;
219
220 let processes = components::process_array::ProcessArrayComponent::new()
222 .finalize(components::process_array_component_static!(NUM_PROCS));
223 PANIC_RESOURCES.get().map(|resources| {
224 resources.processes.put(processes.as_slice());
225 });
226
227 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
229
230 let gpio = components::gpio::GpioComponent::new(
232 board_kernel,
233 capsules_core::gpio::DRIVER_NUM,
234 components::gpio_component_helper!(
235 nrf52840::gpio::GPIOPin,
236 0 => &nrf52840_peripherals.gpio_port[Pin::P0_29],
237 ),
238 )
239 .finalize(components::gpio_component_static!(nrf52840::gpio::GPIOPin));
240
241 let button = components::button::ButtonComponent::new(
242 board_kernel,
243 capsules_core::button::DRIVER_NUM,
244 components::button_component_helper!(
245 nrf52840::gpio::GPIOPin,
246 (
247 &nrf52840_peripherals.gpio_port[BUTTON_PIN],
248 kernel::hil::gpio::ActivationMode::ActiveLow,
249 kernel::hil::gpio::FloatingState::PullUp
250 )
251 ),
252 )
253 .finalize(components::button_component_static!(
254 nrf52840::gpio::GPIOPin
255 ));
256
257 let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
258 LedHigh<'static, nrf52840::gpio::GPIOPin>,
259 LedHigh::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
260 LedHigh::new(&nrf52840_peripherals.gpio_port[VIBRA1_PIN]),
261 ));
262
263 let chip = static_init!(
264 nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
265 nrf52840::chip::NRF52::new(nrf52840_peripherals)
266 );
267 PANIC_RESOURCES.get().map(|resources| {
268 resources.chip.put(chip);
269 });
270
271 nrf52_components::startup::NrfStartupComponent::new(
272 false,
273 BUTTON_PIN,
277 nrf52840::uicr::Regulator0Output::V3_0,
278 &base_peripherals.nvmc,
279 )
280 .finalize(());
281
282 let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
286
287 let gpio_port = &nrf52840_peripherals.gpio_port;
288
289 let debug_gpios = static_init!(
291 [&'static dyn kernel::hil::gpio::Pin; 1],
292 [&gpio_port[LED1_PIN]]
293 );
294 kernel::debug::initialize_debug_gpio::<
295 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
296 >();
297 kernel::debug::assign_gpios(debug_gpios);
298
299 let rtc = &base_peripherals.rtc;
300 let _ = rtc.start();
301 let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
302 .finalize(components::alarm_mux_component_static!(nrf52840::rtc::Rtc));
303 let alarm = components::alarm::AlarmDriverComponent::new(
304 board_kernel,
305 capsules_core::alarm::DRIVER_NUM,
306 mux_alarm,
307 )
308 .finalize(components::alarm_component_static!(nrf52840::rtc::Rtc));
309
310 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
311 .finalize(components::process_printer_text_component_static!());
312 PANIC_RESOURCES.get().map(|resources| {
313 resources.printer.put(process_printer);
314 });
315
316 let uart_channel = {
318 let rtt_memory = components::segger_rtt::SeggerRttMemoryComponent::new()
320 .finalize(components::segger_rtt_memory_component_static!());
321
322 self::io::set_rtt_memory(&*core::ptr::from_mut(rtt_memory.rtt_memory));
326
327 components::segger_rtt::SeggerRttComponent::new(mux_alarm, rtt_memory)
328 .finalize(components::segger_rtt_component_static!(nrf52840::rtc::Rtc))
329 };
330
331 let uart_mux = components::console::UartMuxComponent::new(uart_channel, 115200)
333 .finalize(components::uart_mux_component_static!());
334
335 let pconsole = components::process_console::ProcessConsoleComponent::new(
336 board_kernel,
337 uart_mux,
338 mux_alarm,
339 process_printer,
340 Some(cortexm4::support::reset),
341 )
342 .finalize(components::process_console_component_static!(
343 nrf52840::rtc::Rtc<'static>
344 ));
345
346 let console = components::console::ConsoleComponent::new(
348 board_kernel,
349 capsules_core::console::DRIVER_NUM,
350 uart_mux,
351 )
352 .finalize(components::console_component_static!());
353 components::debug_writer::DebugWriterComponent::new::<
355 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
356 >(
357 uart_mux,
358 create_capability!(capabilities::SetDebugWriterCapability),
359 )
360 .finalize(components::debug_writer_component_static!());
361
362 let ble_radio = components::ble::BLEComponent::new(
363 board_kernel,
364 capsules_extra::ble_advertising_driver::DRIVER_NUM,
365 &base_peripherals.ble_radio,
366 mux_alarm,
367 )
368 .finalize(components::ble_component_static!(
369 nrf52840::rtc::Rtc,
370 nrf52840::ble_radio::Radio
371 ));
372
373 let aes_mux = static_init!(
374 MuxAES128CCM<'static, nrf52840::aes::AesECB>,
375 MuxAES128CCM::new(&base_peripherals.ecb,)
376 );
377 base_peripherals.ecb.set_client(aes_mux);
378 aes_mux.register();
379
380 let (ieee802154_radio, _mux_mac) = components::ieee802154::Ieee802154Component::new(
381 board_kernel,
382 capsules_extra::ieee802154::DRIVER_NUM,
383 &nrf52840_peripherals.ieee802154_radio,
384 aes_mux,
385 PAN_ID,
386 SRC_MAC,
387 DEFAULT_EXT_SRC_MAC,
388 )
389 .finalize(components::ieee802154_component_static!(
390 nrf52840::ieee802154_radio::Radio,
391 nrf52840::aes::AesECB<'static>
392 ));
393
394 let _temp = components::temperature::TemperatureComponent::new(
397 board_kernel,
398 capsules_extra::temperature::DRIVER_NUM,
399 &base_peripherals.temp,
400 )
401 .finalize(components::temperature_component_static!(
402 nrf52840::temperature::Temp
403 ));
404
405 let sensors_i2c_bus = static_init!(
406 capsules_core::virtualizers::virtual_i2c::MuxI2C<'static, nrf52840::i2c::TWI>,
407 capsules_core::virtualizers::virtual_i2c::MuxI2C::new(&base_peripherals.twi1, None,)
408 );
409 sensors_i2c_bus.register();
410
411 base_peripherals.twi1.configure(
412 nrf52840::pinmux::Pinmux::new(I2C_TEMP_SCL_PIN as u32),
413 nrf52840::pinmux::Pinmux::new(I2C_TEMP_SDA_PIN as u32),
414 );
415 base_peripherals.twi1.set_master_client(sensors_i2c_bus);
416
417 let bmp280 = components::bmp280::Bmp280Component::new(
418 sensors_i2c_bus,
419 capsules_extra::bmp280::BASE_ADDR,
420 mux_alarm,
421 )
422 .finalize(components::bmp280_component_static!(
423 nrf52840::rtc::Rtc<'static>,
424 nrf52840::i2c::TWI
425 ));
426
427 let temperature = components::temperature::TemperatureComponent::new(
428 board_kernel,
429 capsules_extra::temperature::DRIVER_NUM,
430 bmp280,
431 )
432 .finalize(components::temperature_component_static!(Bmp280Sensor));
433
434 let rng = components::rng::RngComponent::new(
435 board_kernel,
436 capsules_core::rng::DRIVER_NUM,
437 &base_peripherals.trng,
438 )
439 .finalize(components::rng_component_static!(nrf52840::trng::Trng));
440
441 let analog_comparator_channel = static_init!(
444 nrf52840::acomp::Channel,
445 nrf52840::acomp::Channel::new(nrf52840::acomp::ChannelNumber::AC0)
446 );
447 let analog_comparator = components::analog_comparator::AnalogComparatorComponent::new(
448 &base_peripherals.acomp,
449 components::analog_comparator_component_helper!(
450 nrf52840::acomp::Channel,
451 analog_comparator_channel,
452 ),
453 board_kernel,
454 capsules_extra::analog_comparator::DRIVER_NUM,
455 )
456 .finalize(components::analog_comparator_component_static!(
457 nrf52840::acomp::Comparator
458 ));
459
460 nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
461
462 let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
463 .finalize(components::round_robin_component_static!(NUM_PROCS));
464
465 let periodic_virtual_alarm = static_init!(
466 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>,
467 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm::new(mux_alarm)
468 );
469 periodic_virtual_alarm.setup();
470
471 let screen = {
472 let mux_spi = components::spi::SpiMuxComponent::new(&base_peripherals.spim2)
473 .finalize(components::spi_mux_component_static!(nrf52840::spi::SPIM));
474
475 use kernel::hil::spi::SpiMaster;
476 base_peripherals
477 .spim2
478 .set_rate(1_000_000)
479 .expect("SPIM2 set rate");
480
481 base_peripherals.spim2.configure(
482 nrf52840::pinmux::Pinmux::new(Pin::P0_27 as u32),
483 nrf52840::pinmux::Pinmux::new(Pin::P0_28 as u32),
484 nrf52840::pinmux::Pinmux::new(Pin::P0_26 as u32),
485 );
486
487 let disp_pin = &nrf52840_peripherals.gpio_port[Pin::P0_07];
488 let cs_pin = &nrf52840_peripherals.gpio_port[Pin::P0_05];
489
490 let display = components::lpm013m126::Lpm013m126Component::new(
491 mux_spi,
492 cs_pin,
493 disp_pin,
494 &nrf52840_peripherals.gpio_port[Pin::P0_06],
495 mux_alarm,
496 )
497 .finalize(components::lpm013m126_component_static!(
498 nrf52840::rtc::Rtc<'static>,
499 nrf52840::gpio::GPIOPin,
500 nrf52840::spi::SPIM
501 ));
502
503 let screen = components::screen::ScreenComponent::new(
504 board_kernel,
505 capsules_extra::screen::screen::DRIVER_NUM,
506 display,
507 None,
508 )
509 .finalize(components::screen_component_static!(4096));
510 let _ = display.set_power(true);
512 screen
513 };
514
515 let platform = Platform {
516 temperature,
517 button,
518 ble_radio,
519 ieee802154_radio,
520 pconsole,
521 console,
522 led,
523 gpio,
524 rng,
525 alarm,
526 analog_comparator,
527 screen,
528 ipc: kernel::ipc::IPC::new(
529 board_kernel,
530 kernel::ipc::DRIVER_NUM,
531 &memory_allocation_capability,
532 ),
533 scheduler,
534 systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
535 };
536
537 fn load_processes(
548 board_kernel: &'static kernel::Kernel,
549 chip: &'static nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>,
550 ) {
551 let process_management_capability =
552 create_capability!(capabilities::ProcessManagementCapability);
553 unsafe {
554 kernel::process::load_processes(
555 board_kernel,
556 chip,
557 core::slice::from_raw_parts(
558 core::ptr::addr_of!(_sapps),
559 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
560 ),
561 core::slice::from_raw_parts_mut(
562 core::ptr::addr_of_mut!(_sappmem),
563 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
564 ),
565 &FAULT_RESPONSE,
566 &process_management_capability,
567 )
568 .unwrap_or_else(|err| {
569 debug!("Error loading processes!");
570 debug!("{:?}", err);
571 });
572 }
573 }
574
575 let _ = platform.pconsole.start();
576 debug!("Initialization complete. Entering main loop\r");
577 debug!("{}", &*addr_of!(nrf52840::ficr::FICR_INSTANCE));
578
579 load_processes(board_kernel, chip);
580 extern "C" {
582 static _sapps: u8;
584 static _eapps: u8;
586 static mut _sappmem: u8;
588 static _eappmem: u8;
590 }
591
592 (board_kernel, platform, chip)
593}
594
595#[no_mangle]
597pub unsafe fn main() {
598 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
599
600 let (board_kernel, platform, chip) = start();
601 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
602}