makepython_nrf52840/
main.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Tock kernel for the MakePython nRF52840.
6//!
7//! It is based on nRF52840 SoC.
8
9#![no_std]
10// Disable this attribute when documenting, as a workaround for
11// https://github.com/rust-lang/rust/issues/62184.
12#![cfg_attr(not(doc), no_main)]
13#![deny(missing_docs)]
14
15use core::ptr::{addr_of, addr_of_mut};
16
17use kernel::capabilities;
18use kernel::component::Component;
19use kernel::hil::led::LedLow;
20use kernel::hil::time::Counter;
21use kernel::hil::usb::Client;
22use kernel::platform::{KernelResources, SyscallDriverLookup};
23use kernel::scheduler::round_robin::RoundRobinSched;
24#[allow(unused_imports)]
25use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init};
26
27use nrf52840::gpio::Pin;
28use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
29
30// The datasheet and website and everything say this is connected to P1.10, but
31// actually looking at the hardware files (and what actually works) is that the
32// LED is connected to P1.11 (as of a board I received in September 2023).
33//
34// https://github.com/Makerfabs/NRF52840/issues/1
35const LED_PIN: Pin = Pin::P1_11;
36
37const BUTTON_RST_PIN: Pin = Pin::P0_18;
38const BUTTON_PIN: Pin = Pin::P1_15;
39
40const GPIO_D0: Pin = Pin::P0_23;
41const GPIO_D1: Pin = Pin::P0_12;
42const GPIO_D2: Pin = Pin::P0_09;
43const GPIO_D3: Pin = Pin::P0_07;
44
45const _UART_TX_PIN: Pin = Pin::P0_06;
46const _UART_RX_PIN: Pin = Pin::P0_08;
47
48/// I2C pins for all of the sensors.
49const I2C_SDA_PIN: Pin = Pin::P0_26;
50const I2C_SCL_PIN: Pin = Pin::P0_27;
51
52// Constants related to the configuration of the 15.4 network stack
53/// Personal Area Network ID for the IEEE 802.15.4 radio
54const PAN_ID: u16 = 0xABCD;
55/// Gateway (or next hop) MAC Address
56const DST_MAC_ADDR: capsules_extra::net::ieee802154::MacAddress =
57    capsules_extra::net::ieee802154::MacAddress::Short(49138);
58const DEFAULT_CTX_PREFIX_LEN: u8 = 8; //Length of context for 6LoWPAN compression
59const DEFAULT_CTX_PREFIX: [u8; 16] = [0x0_u8; 16]; //Context for 6LoWPAN Compression
60
61/// UART Writer for panic!()s.
62pub mod io;
63
64// How should the kernel respond when a process faults. For this board we choose
65// to stop the app and print a notice, but not immediately panic. This allows
66// users to debug their apps, but avoids issues with using the USB/CDC stack
67// synchronously for panic! too early after the board boots.
68const FAULT_RESPONSE: capsules_system::process_policies::StopWithDebugFaultPolicy =
69    capsules_system::process_policies::StopWithDebugFaultPolicy {};
70
71// Number of concurrent processes this platform supports.
72const NUM_PROCS: usize = 8;
73
74// State for loading and holding applications.
75static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
76    [None; NUM_PROCS];
77
78static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
79static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
80    None;
81static mut CDC_REF_FOR_PANIC: Option<
82    &'static capsules_extra::usb::cdc::CdcAcm<
83        'static,
84        nrf52::usbd::Usbd,
85        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52::rtc::Rtc>,
86    >,
87> = None;
88static mut NRF52_POWER: Option<&'static nrf52840::power::Power> = None;
89
90/// Dummy buffer that causes the linker to reserve enough space for the stack.
91#[no_mangle]
92#[link_section = ".stack_buffer"]
93pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
94
95// Function for the CDC/USB stack to use to enter the bootloader.
96fn baud_rate_reset_bootloader_enter() {
97    unsafe {
98        // 0x90 is the magic value the bootloader expects
99        NRF52_POWER.unwrap().set_gpregret(0x90);
100        cortexm4::scb::reset();
101    }
102}
103
104fn crc(s: &'static str) -> u32 {
105    kernel::utilities::helpers::crc32_posix(s.as_bytes())
106}
107
108//------------------------------------------------------------------------------
109// SYSCALL DRIVER TYPE DEFINITIONS
110//------------------------------------------------------------------------------
111
112type AlarmDriver = components::alarm::AlarmDriverComponentType<nrf52840::rtc::Rtc<'static>>;
113
114type Screen = components::ssd1306::Ssd1306ComponentType<nrf52840::i2c::TWI<'static>>;
115type ScreenDriver = components::screen::ScreenSharedComponentType<Screen>;
116
117type Ieee802154MacDevice = components::ieee802154::Ieee802154ComponentMacDeviceType<
118    nrf52840::ieee802154_radio::Radio<'static>,
119    nrf52840::aes::AesECB<'static>,
120>;
121type Ieee802154Driver = components::ieee802154::Ieee802154ComponentType<
122    nrf52840::ieee802154_radio::Radio<'static>,
123    nrf52840::aes::AesECB<'static>,
124>;
125type RngDriver = components::rng::RngComponentType<nrf52840::trng::Trng<'static>>;
126
127/// Supported drivers by the platform
128pub struct Platform {
129    ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
130        'static,
131        nrf52::ble_radio::Radio<'static>,
132        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
133            'static,
134            nrf52::rtc::Rtc<'static>,
135        >,
136    >,
137    ieee802154_radio: &'static Ieee802154Driver,
138    console: &'static capsules_core::console::Console<'static>,
139    pconsole: &'static capsules_core::process_console::ProcessConsole<
140        'static,
141        { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
142        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
143            'static,
144            nrf52::rtc::Rtc<'static>,
145        >,
146        components::process_console::Capability,
147    >,
148    gpio: &'static capsules_core::gpio::GPIO<'static, nrf52::gpio::GPIOPin<'static>>,
149    led: &'static capsules_core::led::LedDriver<
150        'static,
151        LedLow<'static, nrf52::gpio::GPIOPin<'static>>,
152        1,
153    >,
154    adc: &'static capsules_core::adc::AdcVirtualized<'static>,
155    rng: &'static RngDriver,
156    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
157    alarm: &'static AlarmDriver,
158    button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
159    screen: &'static ScreenDriver,
160    udp_driver: &'static capsules_extra::net::udp::UDPDriver<'static>,
161    scheduler: &'static RoundRobinSched<'static>,
162    systick: cortexm4::systick::SysTick,
163}
164
165impl SyscallDriverLookup for Platform {
166    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
167    where
168        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
169    {
170        match driver_num {
171            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
172            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
173            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
174            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
175            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
176            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
177            capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
178            capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)),
179            capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
180            capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)),
181            capsules_extra::net::udp::DRIVER_NUM => f(Some(self.udp_driver)),
182            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
183            _ => f(None),
184        }
185    }
186}
187
188impl KernelResources<nrf52::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
189    for Platform
190{
191    type SyscallDriverLookup = Self;
192    type SyscallFilter = ();
193    type ProcessFault = ();
194    type Scheduler = RoundRobinSched<'static>;
195    type SchedulerTimer = cortexm4::systick::SysTick;
196    type WatchDog = ();
197    type ContextSwitchCallback = ();
198
199    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
200        self
201    }
202    fn syscall_filter(&self) -> &Self::SyscallFilter {
203        &()
204    }
205    fn process_fault(&self) -> &Self::ProcessFault {
206        &()
207    }
208    fn scheduler(&self) -> &Self::Scheduler {
209        self.scheduler
210    }
211    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
212        &self.systick
213    }
214    fn watchdog(&self) -> &Self::WatchDog {
215        &()
216    }
217    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
218        &()
219    }
220}
221
222/// This is in a separate, inline(never) function so that its stack frame is
223/// removed when this function returns. Otherwise, the stack space used for
224/// these static_inits is wasted.
225#[inline(never)]
226pub unsafe fn start() -> (
227    &'static kernel::Kernel,
228    Platform,
229    &'static nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>,
230) {
231    nrf52840::init();
232
233    let ieee802154_ack_buf = static_init!(
234        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
235        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
236    );
237
238    // Initialize chip peripheral drivers
239    let nrf52840_peripherals = static_init!(
240        Nrf52840DefaultPeripherals,
241        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
242    );
243
244    // set up circular peripheral dependencies
245    nrf52840_peripherals.init();
246    let base_peripherals = &nrf52840_peripherals.nrf52;
247
248    // Save a reference to the power module for resetting the board into the
249    // bootloader.
250    NRF52_POWER = Some(&base_peripherals.pwr_clk);
251
252    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
253
254    // Do nRF configuration and setup. This is shared code with other nRF-based
255    // platforms.
256    nrf52_components::startup::NrfStartupComponent::new(
257        false,
258        BUTTON_RST_PIN,
259        nrf52840::uicr::Regulator0Output::DEFAULT,
260        &base_peripherals.nvmc,
261    )
262    .finalize(());
263
264    let chip = static_init!(
265        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
266        nrf52840::chip::NRF52::new(nrf52840_peripherals)
267    );
268    CHIP = Some(chip);
269
270    //--------------------------------------------------------------------------
271    // CAPABILITIES
272    //--------------------------------------------------------------------------
273
274    // Create capabilities that the board needs to call certain protected kernel
275    // functions.
276    let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
277
278    //--------------------------------------------------------------------------
279    // DEBUG GPIO
280    //--------------------------------------------------------------------------
281
282    // Configure kernel debug GPIOs as early as possible. These are used by the
283    // `debug_gpio!(0, toggle)` macro. We configure these early so that the
284    // macro is available during most of the setup code and kernel execution.
285    kernel::debug::assign_gpios(Some(&nrf52840_peripherals.gpio_port[LED_PIN]), None, None);
286
287    //--------------------------------------------------------------------------
288    // GPIO
289    //--------------------------------------------------------------------------
290
291    let gpio = components::gpio::GpioComponent::new(
292        board_kernel,
293        capsules_core::gpio::DRIVER_NUM,
294        components::gpio_component_helper!(
295            nrf52840::gpio::GPIOPin,
296            0 => &nrf52840_peripherals.gpio_port[GPIO_D0],
297            1 => &nrf52840_peripherals.gpio_port[GPIO_D1],
298            2 => &nrf52840_peripherals.gpio_port[GPIO_D2],
299            3 => &nrf52840_peripherals.gpio_port[GPIO_D3],
300        ),
301    )
302    .finalize(components::gpio_component_static!(nrf52840::gpio::GPIOPin));
303
304    //--------------------------------------------------------------------------
305    // LEDs
306    //--------------------------------------------------------------------------
307
308    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
309        LedLow<'static, nrf52840::gpio::GPIOPin>,
310        LedLow::new(&nrf52840_peripherals.gpio_port[LED_PIN]),
311    ));
312
313    //--------------------------------------------------------------------------
314    // BUTTONS
315    //--------------------------------------------------------------------------
316
317    let button = components::button::ButtonComponent::new(
318        board_kernel,
319        capsules_core::button::DRIVER_NUM,
320        components::button_component_helper!(
321            nrf52840::gpio::GPIOPin,
322            (
323                &nrf52840_peripherals.gpio_port[BUTTON_PIN],
324                kernel::hil::gpio::ActivationMode::ActiveLow,
325                kernel::hil::gpio::FloatingState::PullUp
326            )
327        ),
328    )
329    .finalize(components::button_component_static!(
330        nrf52840::gpio::GPIOPin
331    ));
332
333    //--------------------------------------------------------------------------
334    // ALARM & TIMER
335    //--------------------------------------------------------------------------
336
337    let rtc = &base_peripherals.rtc;
338    let _ = rtc.start();
339
340    let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
341        .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc));
342    let alarm = components::alarm::AlarmDriverComponent::new(
343        board_kernel,
344        capsules_core::alarm::DRIVER_NUM,
345        mux_alarm,
346    )
347    .finalize(components::alarm_component_static!(nrf52::rtc::Rtc));
348
349    //--------------------------------------------------------------------------
350    // UART & CONSOLE & DEBUG
351    //--------------------------------------------------------------------------
352
353    // Setup the CDC-ACM over USB driver that we will use for UART.
354    // We use the Arduino Vendor ID and Product ID since the device is the same.
355
356    // Create the strings we include in the USB descriptor. We use the hardcoded
357    // DEVICEADDR register on the nRF52 to set the serial number.
358    let serial_number_buf = static_init!([u8; 17], [0; 17]);
359    let serial_number_string: &'static str =
360        (*addr_of!(nrf52::ficr::FICR_INSTANCE)).address_str(serial_number_buf);
361    let strings = static_init!(
362        [&str; 3],
363        [
364            "MakePython",         // Manufacturer
365            "NRF52840 - TockOS",  // Product
366            serial_number_string, // Serial number
367        ]
368    );
369
370    let cdc = components::cdc::CdcAcmComponent::new(
371        &nrf52840_peripherals.usbd,
372        capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840,
373        0x2341,
374        0x005a,
375        strings,
376        mux_alarm,
377        Some(&baud_rate_reset_bootloader_enter),
378    )
379    .finalize(components::cdc_acm_component_static!(
380        nrf52::usbd::Usbd,
381        nrf52::rtc::Rtc
382    ));
383    CDC_REF_FOR_PANIC = Some(cdc); //for use by panic handler
384
385    // Process Printer for displaying process information.
386    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
387        .finalize(components::process_printer_text_component_static!());
388    PROCESS_PRINTER = Some(process_printer);
389
390    // Create a shared UART channel for the console and for kernel debug.
391    let uart_mux = components::console::UartMuxComponent::new(cdc, 115200)
392        .finalize(components::uart_mux_component_static!());
393
394    let pconsole = components::process_console::ProcessConsoleComponent::new(
395        board_kernel,
396        uart_mux,
397        mux_alarm,
398        process_printer,
399        Some(cortexm4::support::reset),
400    )
401    .finalize(components::process_console_component_static!(
402        nrf52::rtc::Rtc<'static>
403    ));
404
405    // Setup the console.
406    let console = components::console::ConsoleComponent::new(
407        board_kernel,
408        capsules_core::console::DRIVER_NUM,
409        uart_mux,
410    )
411    .finalize(components::console_component_static!());
412    // Create the debugger object that handles calls to `debug!()`.
413    components::debug_writer::DebugWriterComponent::new(uart_mux)
414        .finalize(components::debug_writer_component_static!());
415
416    //--------------------------------------------------------------------------
417    // RANDOM NUMBERS
418    //--------------------------------------------------------------------------
419
420    let rng = components::rng::RngComponent::new(
421        board_kernel,
422        capsules_core::rng::DRIVER_NUM,
423        &base_peripherals.trng,
424    )
425    .finalize(components::rng_component_static!(nrf52840::trng::Trng));
426
427    //--------------------------------------------------------------------------
428    // ADC
429    //--------------------------------------------------------------------------
430    base_peripherals.adc.calibrate();
431
432    let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc)
433        .finalize(components::adc_mux_component_static!(nrf52840::adc::Adc));
434
435    let adc_syscall =
436        components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM)
437            .finalize(components::adc_syscall_component_helper!(
438                // A0
439                components::adc::AdcComponent::new(
440                    adc_mux,
441                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput2)
442                )
443                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
444                // A1
445                components::adc::AdcComponent::new(
446                    adc_mux,
447                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput3)
448                )
449                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
450                // A2
451                components::adc::AdcComponent::new(
452                    adc_mux,
453                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput6)
454                )
455                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
456                // A3
457                components::adc::AdcComponent::new(
458                    adc_mux,
459                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput5)
460                )
461                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
462                // A4
463                components::adc::AdcComponent::new(
464                    adc_mux,
465                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput7)
466                )
467                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
468                // A5
469                components::adc::AdcComponent::new(
470                    adc_mux,
471                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput0)
472                )
473                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
474                // A6
475                components::adc::AdcComponent::new(
476                    adc_mux,
477                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput4)
478                )
479                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
480                // A7
481                components::adc::AdcComponent::new(
482                    adc_mux,
483                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput1)
484                )
485                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
486            ));
487
488    //--------------------------------------------------------------------------
489    // SCREEN
490    //--------------------------------------------------------------------------
491
492    let i2c_bus = components::i2c::I2CMuxComponent::new(&base_peripherals.twi1, None)
493        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
494    base_peripherals.twi1.configure(
495        nrf52840::pinmux::Pinmux::new(I2C_SCL_PIN as u32),
496        nrf52840::pinmux::Pinmux::new(I2C_SDA_PIN as u32),
497    );
498
499    // I2C address is b011110X, and on this board D/C̅ is GND.
500    let ssd1306_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
501        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
502
503    // Create the ssd1306 object for the actual screen driver.
504    let ssd1306 = components::ssd1306::Ssd1306Component::new(ssd1306_i2c, true)
505        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
506
507    // Create a Driver for userspace access to the screen.
508    // let screen = components::screen::ScreenComponent::new(
509    //     board_kernel,
510    //     capsules_extra::screen::DRIVER_NUM,
511    //     ssd1306,
512    //     Some(ssd1306),
513    // )
514    // .finalize(components::screen_component_static!(1032));
515
516    let apps_regions = static_init!(
517        [capsules_extra::screen_shared::AppScreenRegion; 3],
518        [
519            capsules_extra::screen_shared::AppScreenRegion::new(
520                kernel::process::ShortId::Fixed(core::num::NonZeroU32::new(crc("circle")).unwrap()),
521                0,     // x
522                0,     // y
523                8 * 8, // width
524                8 * 8  // height
525            ),
526            capsules_extra::screen_shared::AppScreenRegion::new(
527                kernel::process::ShortId::Fixed(core::num::NonZeroU32::new(crc("count")).unwrap()),
528                8 * 8, // x
529                0,     // y
530                8 * 8, // width
531                4 * 8  // height
532            ),
533            capsules_extra::screen_shared::AppScreenRegion::new(
534                kernel::process::ShortId::Fixed(
535                    core::num::NonZeroU32::new(crc("tock-scroll")).unwrap()
536                ),
537                8 * 8, // x
538                4 * 8, // y
539                8 * 8, // width
540                4 * 8  // height
541            )
542        ]
543    );
544
545    let screen = components::screen::ScreenSharedComponent::new(
546        board_kernel,
547        capsules_extra::screen::DRIVER_NUM,
548        ssd1306,
549        apps_regions,
550    )
551    .finalize(components::screen_shared_component_static!(1032, Screen));
552
553    //--------------------------------------------------------------------------
554    // WIRELESS
555    //--------------------------------------------------------------------------
556
557    let ble_radio = components::ble::BLEComponent::new(
558        board_kernel,
559        capsules_extra::ble_advertising_driver::DRIVER_NUM,
560        &base_peripherals.ble_radio,
561        mux_alarm,
562    )
563    .finalize(components::ble_component_static!(
564        nrf52840::rtc::Rtc,
565        nrf52840::ble_radio::Radio
566    ));
567
568    use capsules_extra::net::ieee802154::MacAddress;
569
570    let aes_mux = components::ieee802154::MuxAes128ccmComponent::new(&base_peripherals.ecb)
571        .finalize(components::mux_aes128ccm_component_static!(
572            nrf52840::aes::AesECB
573        ));
574
575    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
576    let device_id_bottom_16 = u16::from_le_bytes([device_id[0], device_id[1]]);
577    let (ieee802154_radio, mux_mac) = components::ieee802154::Ieee802154Component::new(
578        board_kernel,
579        capsules_extra::ieee802154::DRIVER_NUM,
580        &nrf52840_peripherals.ieee802154_radio,
581        aes_mux,
582        PAN_ID,
583        device_id_bottom_16,
584        device_id,
585    )
586    .finalize(components::ieee802154_component_static!(
587        nrf52840::ieee802154_radio::Radio,
588        nrf52840::aes::AesECB<'static>
589    ));
590    use capsules_extra::net::ipv6::ip_utils::IPAddr;
591
592    let local_ip_ifaces = static_init!(
593        [IPAddr; 3],
594        [
595            IPAddr([
596                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
597                0x0e, 0x0f,
598            ]),
599            IPAddr([
600                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
601                0x1e, 0x1f,
602            ]),
603            IPAddr::generate_from_mac(capsules_extra::net::ieee802154::MacAddress::Short(
604                device_id_bottom_16
605            )),
606        ]
607    );
608
609    let (udp_send_mux, udp_recv_mux, udp_port_table) = components::udp_mux::UDPMuxComponent::new(
610        mux_mac,
611        DEFAULT_CTX_PREFIX_LEN,
612        DEFAULT_CTX_PREFIX,
613        DST_MAC_ADDR,
614        MacAddress::Short(device_id_bottom_16),
615        local_ip_ifaces,
616        mux_alarm,
617    )
618    .finalize(components::udp_mux_component_static!(
619        nrf52840::rtc::Rtc,
620        Ieee802154MacDevice
621    ));
622
623    // UDP driver initialization happens here
624    let udp_driver = components::udp_driver::UDPDriverComponent::new(
625        board_kernel,
626        capsules_extra::net::udp::DRIVER_NUM,
627        udp_send_mux,
628        udp_recv_mux,
629        udp_port_table,
630        local_ip_ifaces,
631    )
632    .finalize(components::udp_driver_component_static!(nrf52840::rtc::Rtc));
633
634    //--------------------------------------------------------------------------
635    // APP ID CHECKING
636    //--------------------------------------------------------------------------
637
638    // Create the software-based SHA engine.
639    let sha = components::sha::ShaSoftware256Component::new()
640        .finalize(components::sha_software_256_component_static!());
641
642    // Create the credential checker.
643    let checking_policy = components::appid::checker_sha::AppCheckerSha256Component::new(sha)
644        .finalize(components::app_checker_sha256_component_static!());
645
646    // Create the AppID assigner.
647    let assigner = components::appid::assigner_name::AppIdAssignerNamesComponent::new()
648        .finalize(components::appid_assigner_names_component_static!());
649
650    // Create the process checking machine.
651    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
652        .finalize(components::process_checker_machine_component_static!());
653
654    //--------------------------------------------------------------------------
655    // STORAGE PERMISSIONS
656    //--------------------------------------------------------------------------
657
658    let storage_permissions_policy =
659        components::storage_permissions::individual::StoragePermissionsIndividualComponent::new()
660            .finalize(
661                components::storage_permissions_individual_component_static!(
662                    nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
663                    kernel::process::ProcessStandardDebugFull,
664                ),
665            );
666
667    //--------------------------------------------------------------------------
668    // PROCESS LOADING
669    //--------------------------------------------------------------------------
670
671    // Create and start the asynchronous process loader.
672    let _loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
673        checker,
674        &mut *addr_of_mut!(PROCESSES),
675        board_kernel,
676        chip,
677        &FAULT_RESPONSE,
678        assigner,
679        storage_permissions_policy,
680    )
681    .finalize(components::process_loader_sequential_component_static!(
682        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
683        kernel::process::ProcessStandardDebugFull,
684        NUM_PROCS
685    ));
686
687    //--------------------------------------------------------------------------
688    // FINAL SETUP AND BOARD BOOT
689    //--------------------------------------------------------------------------
690
691    // Start all of the clocks. Low power operation will require a better
692    // approach than this.
693    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
694
695    let scheduler = components::sched::round_robin::RoundRobinComponent::new(&*addr_of!(PROCESSES))
696        .finalize(components::round_robin_component_static!(NUM_PROCS));
697
698    let platform = Platform {
699        ble_radio,
700        ieee802154_radio,
701        console,
702        pconsole,
703        adc: adc_syscall,
704        led,
705        button,
706        gpio,
707        rng,
708        screen,
709        alarm,
710        udp_driver,
711        ipc: kernel::ipc::IPC::new(
712            board_kernel,
713            kernel::ipc::DRIVER_NUM,
714            &memory_allocation_capability,
715        ),
716        scheduler,
717        systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
718    };
719
720    // Configure the USB stack to enable a serial port over CDC-ACM.
721    cdc.enable();
722    cdc.attach();
723
724    //--------------------------------------------------------------------------
725    // TESTS
726    //--------------------------------------------------------------------------
727    // test::linear_log_test::run(
728    //     mux_alarm,
729    //     &nrf52840_peripherals.nrf52.nvmc,
730    // );
731    // test::log_test::run(
732    //     mux_alarm,
733    //     &nrf52840_peripherals.nrf52.nvmc,
734    // );
735
736    debug!("Initialization complete. Entering main loop.");
737    let _ = platform.pconsole.start();
738
739    ssd1306.init_screen();
740
741    //--------------------------------------------------------------------------
742    // PROCESSES AND MAIN LOOP
743    //--------------------------------------------------------------------------
744
745    (board_kernel, platform, chip)
746}
747
748/// Main function called after RAM initialized.
749#[no_mangle]
750pub unsafe fn main() {
751    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
752
753    let (board_kernel, platform, chip) = start();
754    board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
755}