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#![no_main]
11#![deny(missing_docs)]
12
13use core::ptr::addr_of;
14
15use kernel::capabilities;
16use kernel::component::Component;
17use kernel::hil::led::LedLow;
18use kernel::hil::time::Counter;
19use kernel::hil::usb::Client;
20use kernel::platform::{KernelResources, SyscallDriverLookup};
21use kernel::process::ProcessArray;
22use kernel::scheduler::round_robin::RoundRobinSched;
23#[allow(unused_imports)]
24use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init};
25
26use nrf52840::gpio::Pin;
27use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
28
29// The datasheet and website and everything say this is connected to P1.10, but
30// actually looking at the hardware files (and what actually works) is that the
31// LED is connected to P1.11 (as of a board I received in September 2023).
32//
33// https://github.com/Makerfabs/NRF52840/issues/1
34const LED_PIN: Pin = Pin::P1_11;
35
36const BUTTON_RST_PIN: Pin = Pin::P0_18;
37const BUTTON_PIN: Pin = Pin::P1_15;
38
39const GPIO_D0: Pin = Pin::P0_23;
40const GPIO_D1: Pin = Pin::P0_12;
41const GPIO_D2: Pin = Pin::P0_09;
42const GPIO_D3: Pin = Pin::P0_07;
43
44const _UART_TX_PIN: Pin = Pin::P0_06;
45const _UART_RX_PIN: Pin = Pin::P0_08;
46
47/// I2C pins for all of the sensors.
48const I2C_SDA_PIN: Pin = Pin::P0_26;
49const I2C_SCL_PIN: Pin = Pin::P0_27;
50
51// Constants related to the configuration of the 15.4 network stack
52/// Personal Area Network ID for the IEEE 802.15.4 radio
53const PAN_ID: u16 = 0xABCD;
54/// Gateway (or next hop) MAC Address
55const DST_MAC_ADDR: capsules_extra::net::ieee802154::MacAddress =
56    capsules_extra::net::ieee802154::MacAddress::Short(49138);
57const DEFAULT_CTX_PREFIX_LEN: u8 = 8; //Length of context for 6LoWPAN compression
58const DEFAULT_CTX_PREFIX: [u8; 16] = [0x0_u8; 16]; //Context for 6LoWPAN Compression
59
60/// UART Writer for panic!()s.
61pub mod io;
62
63// How should the kernel respond when a process faults. For this board we choose
64// to stop the app and print a notice, but not immediately panic. This allows
65// users to debug their apps, but avoids issues with using the USB/CDC stack
66// synchronously for panic! too early after the board boots.
67const FAULT_RESPONSE: capsules_system::process_policies::StopWithDebugFaultPolicy =
68    capsules_system::process_policies::StopWithDebugFaultPolicy {};
69
70// Number of concurrent processes this platform supports.
71const NUM_PROCS: usize = 8;
72
73/// Static variables used by io.rs.
74static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
75static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
76static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
77    None;
78static mut CDC_REF_FOR_PANIC: Option<
79    &'static capsules_extra::usb::cdc::CdcAcm<
80        'static,
81        nrf52::usbd::Usbd,
82        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52::rtc::Rtc>,
83    >,
84> = None;
85static mut NRF52_POWER: Option<&'static nrf52840::power::Power> = None;
86
87kernel::stack_size! {0x1000}
88
89// Function for the CDC/USB stack to use to enter the bootloader.
90fn baud_rate_reset_bootloader_enter() {
91    unsafe {
92        // 0x90 is the magic value the bootloader expects
93        NRF52_POWER.unwrap().set_gpregret(0x90);
94        cortexm4::scb::reset();
95    }
96}
97
98fn crc(s: &'static str) -> u32 {
99    kernel::utilities::helpers::crc32_posix(s.as_bytes())
100}
101
102//------------------------------------------------------------------------------
103// SYSCALL DRIVER TYPE DEFINITIONS
104//------------------------------------------------------------------------------
105
106type AlarmDriver = components::alarm::AlarmDriverComponentType<nrf52840::rtc::Rtc<'static>>;
107
108type Screen = components::ssd1306::Ssd1306ComponentType<nrf52840::i2c::TWI<'static>>;
109type ScreenDriver = components::screen::ScreenSharedComponentType<Screen>;
110
111type Ieee802154MacDevice = components::ieee802154::Ieee802154ComponentMacDeviceType<
112    nrf52840::ieee802154_radio::Radio<'static>,
113    nrf52840::aes::AesECB<'static>,
114>;
115type Ieee802154Driver = components::ieee802154::Ieee802154ComponentType<
116    nrf52840::ieee802154_radio::Radio<'static>,
117    nrf52840::aes::AesECB<'static>,
118>;
119type RngDriver = components::rng::RngComponentType<nrf52840::trng::Trng<'static>>;
120
121/// Supported drivers by the platform
122pub struct Platform {
123    ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
124        'static,
125        nrf52::ble_radio::Radio<'static>,
126        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
127            'static,
128            nrf52::rtc::Rtc<'static>,
129        >,
130    >,
131    ieee802154_radio: &'static Ieee802154Driver,
132    console: &'static capsules_core::console::Console<'static>,
133    pconsole: &'static capsules_core::process_console::ProcessConsole<
134        'static,
135        { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
136        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
137            'static,
138            nrf52::rtc::Rtc<'static>,
139        >,
140        components::process_console::Capability,
141    >,
142    gpio: &'static capsules_core::gpio::GPIO<'static, nrf52::gpio::GPIOPin<'static>>,
143    led: &'static capsules_core::led::LedDriver<
144        'static,
145        LedLow<'static, nrf52::gpio::GPIOPin<'static>>,
146        1,
147    >,
148    adc: &'static capsules_core::adc::AdcVirtualized<'static>,
149    rng: &'static RngDriver,
150    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
151    alarm: &'static AlarmDriver,
152    button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
153    screen: &'static ScreenDriver,
154    udp_driver: &'static capsules_extra::net::udp::UDPDriver<'static>,
155    scheduler: &'static RoundRobinSched<'static>,
156    systick: cortexm4::systick::SysTick,
157}
158
159impl SyscallDriverLookup for Platform {
160    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
161    where
162        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
163    {
164        match driver_num {
165            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
166            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
167            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
168            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
169            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
170            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
171            capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
172            capsules_extra::screen::screen::DRIVER_NUM => f(Some(self.screen)),
173            capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
174            capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)),
175            capsules_extra::net::udp::DRIVER_NUM => f(Some(self.udp_driver)),
176            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
177            _ => f(None),
178        }
179    }
180}
181
182impl KernelResources<nrf52::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
183    for Platform
184{
185    type SyscallDriverLookup = Self;
186    type SyscallFilter = ();
187    type ProcessFault = ();
188    type Scheduler = RoundRobinSched<'static>;
189    type SchedulerTimer = cortexm4::systick::SysTick;
190    type WatchDog = ();
191    type ContextSwitchCallback = ();
192
193    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
194        self
195    }
196    fn syscall_filter(&self) -> &Self::SyscallFilter {
197        &()
198    }
199    fn process_fault(&self) -> &Self::ProcessFault {
200        &()
201    }
202    fn scheduler(&self) -> &Self::Scheduler {
203        self.scheduler
204    }
205    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
206        &self.systick
207    }
208    fn watchdog(&self) -> &Self::WatchDog {
209        &()
210    }
211    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
212        &()
213    }
214}
215
216/// This is in a separate, inline(never) function so that its stack frame is
217/// removed when this function returns. Otherwise, the stack space used for
218/// these static_inits is wasted.
219#[inline(never)]
220pub unsafe fn start() -> (
221    &'static kernel::Kernel,
222    Platform,
223    &'static nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>,
224) {
225    nrf52840::init();
226
227    let ieee802154_ack_buf = static_init!(
228        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
229        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
230    );
231
232    // Initialize chip peripheral drivers
233    let nrf52840_peripherals = static_init!(
234        Nrf52840DefaultPeripherals,
235        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
236    );
237
238    // set up circular peripheral dependencies
239    nrf52840_peripherals.init();
240    let base_peripherals = &nrf52840_peripherals.nrf52;
241
242    // Save a reference to the power module for resetting the board into the
243    // bootloader.
244    NRF52_POWER = Some(&base_peripherals.pwr_clk);
245
246    // Create an array to hold process references.
247    let processes = components::process_array::ProcessArrayComponent::new()
248        .finalize(components::process_array_component_static!(NUM_PROCS));
249    PROCESSES = Some(processes);
250
251    // Setup space to store the core kernel data structure.
252    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
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(
414        uart_mux,
415        create_capability!(capabilities::SetDebugWriterCapability),
416    )
417    .finalize(components::debug_writer_component_static!());
418
419    //--------------------------------------------------------------------------
420    // RANDOM NUMBERS
421    //--------------------------------------------------------------------------
422
423    let rng = components::rng::RngComponent::new(
424        board_kernel,
425        capsules_core::rng::DRIVER_NUM,
426        &base_peripherals.trng,
427    )
428    .finalize(components::rng_component_static!(nrf52840::trng::Trng));
429
430    //--------------------------------------------------------------------------
431    // ADC
432    //--------------------------------------------------------------------------
433    base_peripherals.adc.calibrate();
434
435    let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc)
436        .finalize(components::adc_mux_component_static!(nrf52840::adc::Adc));
437
438    let adc_syscall =
439        components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM)
440            .finalize(components::adc_syscall_component_helper!(
441                // A0
442                components::adc::AdcComponent::new(
443                    adc_mux,
444                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput2)
445                )
446                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
447                // A1
448                components::adc::AdcComponent::new(
449                    adc_mux,
450                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput3)
451                )
452                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
453                // A2
454                components::adc::AdcComponent::new(
455                    adc_mux,
456                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput6)
457                )
458                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
459                // A3
460                components::adc::AdcComponent::new(
461                    adc_mux,
462                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput5)
463                )
464                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
465                // A4
466                components::adc::AdcComponent::new(
467                    adc_mux,
468                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput7)
469                )
470                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
471                // A5
472                components::adc::AdcComponent::new(
473                    adc_mux,
474                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput0)
475                )
476                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
477                // A6
478                components::adc::AdcComponent::new(
479                    adc_mux,
480                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput4)
481                )
482                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
483                // A7
484                components::adc::AdcComponent::new(
485                    adc_mux,
486                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput1)
487                )
488                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
489            ));
490
491    //--------------------------------------------------------------------------
492    // SCREEN
493    //--------------------------------------------------------------------------
494
495    let i2c_bus = components::i2c::I2CMuxComponent::new(&base_peripherals.twi1, None)
496        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
497    base_peripherals.twi1.configure(
498        nrf52840::pinmux::Pinmux::new(I2C_SCL_PIN as u32),
499        nrf52840::pinmux::Pinmux::new(I2C_SDA_PIN as u32),
500    );
501
502    // I2C address is b011110X, and on this board D/C̅ is GND.
503    let ssd1306_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
504        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
505
506    // Create the ssd1306 object for the actual screen driver.
507    let ssd1306 = components::ssd1306::Ssd1306Component::new(ssd1306_i2c, true)
508        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
509
510    // Create a Driver for userspace access to the screen.
511    // let screen = components::screen::ScreenComponent::new(
512    //     board_kernel,
513    //     capsules_extra::screen::screen::DRIVER_NUM,
514    //     ssd1306,
515    //     Some(ssd1306),
516    // )
517    // .finalize(components::screen_component_static!(1032));
518
519    let apps_regions = static_init!(
520        [capsules_extra::screen::screen_shared::AppScreenRegion; 3],
521        [
522            capsules_extra::screen::screen_shared::AppScreenRegion::new(
523                kernel::process::ShortId::Fixed(core::num::NonZeroU32::new(crc("circle")).unwrap()),
524                0,     // x
525                0,     // y
526                8 * 8, // width
527                8 * 8  // height
528            ),
529            capsules_extra::screen::screen_shared::AppScreenRegion::new(
530                kernel::process::ShortId::Fixed(core::num::NonZeroU32::new(crc("count")).unwrap()),
531                8 * 8, // x
532                0,     // y
533                8 * 8, // width
534                4 * 8  // height
535            ),
536            capsules_extra::screen::screen_shared::AppScreenRegion::new(
537                kernel::process::ShortId::Fixed(
538                    core::num::NonZeroU32::new(crc("tock-scroll")).unwrap()
539                ),
540                8 * 8, // x
541                4 * 8, // y
542                8 * 8, // width
543                4 * 8  // height
544            )
545        ]
546    );
547
548    let screen = components::screen::ScreenSharedComponent::new(
549        board_kernel,
550        capsules_extra::screen::screen::DRIVER_NUM,
551        ssd1306,
552        apps_regions,
553    )
554    .finalize(components::screen_shared_component_static!(1032, Screen));
555
556    //--------------------------------------------------------------------------
557    // WIRELESS
558    //--------------------------------------------------------------------------
559
560    let ble_radio = components::ble::BLEComponent::new(
561        board_kernel,
562        capsules_extra::ble_advertising_driver::DRIVER_NUM,
563        &base_peripherals.ble_radio,
564        mux_alarm,
565    )
566    .finalize(components::ble_component_static!(
567        nrf52840::rtc::Rtc,
568        nrf52840::ble_radio::Radio
569    ));
570
571    use capsules_extra::net::ieee802154::MacAddress;
572
573    let aes_mux = components::ieee802154::MuxAes128ccmComponent::new(&base_peripherals.ecb)
574        .finalize(components::mux_aes128ccm_component_static!(
575            nrf52840::aes::AesECB
576        ));
577
578    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
579    let device_id_bottom_16 = u16::from_le_bytes([device_id[0], device_id[1]]);
580    let (ieee802154_radio, mux_mac) = components::ieee802154::Ieee802154Component::new(
581        board_kernel,
582        capsules_extra::ieee802154::DRIVER_NUM,
583        &nrf52840_peripherals.ieee802154_radio,
584        aes_mux,
585        PAN_ID,
586        device_id_bottom_16,
587        device_id,
588    )
589    .finalize(components::ieee802154_component_static!(
590        nrf52840::ieee802154_radio::Radio,
591        nrf52840::aes::AesECB<'static>
592    ));
593    use capsules_extra::net::ipv6::ip_utils::IPAddr;
594
595    let local_ip_ifaces = static_init!(
596        [IPAddr; 3],
597        [
598            IPAddr([
599                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
600                0x0e, 0x0f,
601            ]),
602            IPAddr([
603                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
604                0x1e, 0x1f,
605            ]),
606            IPAddr::generate_from_mac(capsules_extra::net::ieee802154::MacAddress::Short(
607                device_id_bottom_16
608            )),
609        ]
610    );
611
612    let (udp_send_mux, udp_recv_mux, udp_port_table) = components::udp_mux::UDPMuxComponent::new(
613        mux_mac,
614        DEFAULT_CTX_PREFIX_LEN,
615        DEFAULT_CTX_PREFIX,
616        DST_MAC_ADDR,
617        MacAddress::Short(device_id_bottom_16),
618        local_ip_ifaces,
619        mux_alarm,
620    )
621    .finalize(components::udp_mux_component_static!(
622        nrf52840::rtc::Rtc,
623        Ieee802154MacDevice
624    ));
625
626    // UDP driver initialization happens here
627    let udp_driver = components::udp_driver::UDPDriverComponent::new(
628        board_kernel,
629        capsules_extra::net::udp::DRIVER_NUM,
630        udp_send_mux,
631        udp_recv_mux,
632        udp_port_table,
633        local_ip_ifaces,
634    )
635    .finalize(components::udp_driver_component_static!(nrf52840::rtc::Rtc));
636
637    //--------------------------------------------------------------------------
638    // APP ID CHECKING
639    //--------------------------------------------------------------------------
640
641    // Create the software-based SHA engine.
642    let sha = components::sha::ShaSoftware256Component::new()
643        .finalize(components::sha_software_256_component_static!());
644
645    // Create the credential checker.
646    let checking_policy = components::appid::checker_sha::AppCheckerSha256Component::new(sha)
647        .finalize(components::app_checker_sha256_component_static!());
648
649    // Create the AppID assigner.
650    let assigner = components::appid::assigner_name::AppIdAssignerNamesComponent::new()
651        .finalize(components::appid_assigner_names_component_static!());
652
653    // Create the process checking machine.
654    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
655        .finalize(components::process_checker_machine_component_static!());
656
657    //--------------------------------------------------------------------------
658    // STORAGE PERMISSIONS
659    //--------------------------------------------------------------------------
660
661    let storage_permissions_policy =
662        components::storage_permissions::individual::StoragePermissionsIndividualComponent::new()
663            .finalize(
664                components::storage_permissions_individual_component_static!(
665                    nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
666                    kernel::process::ProcessStandardDebugFull,
667                ),
668            );
669
670    //--------------------------------------------------------------------------
671    // PROCESS LOADING
672    //--------------------------------------------------------------------------
673
674    // These symbols are defined in the standard Tock linker script.
675    extern "C" {
676        /// Beginning of the ROM region containing app images.
677        static _sapps: u8;
678        /// End of the ROM region containing app images.
679        static _eapps: u8;
680        /// Beginning of the RAM region for app memory.
681        static mut _sappmem: u8;
682        /// End of the RAM region for app memory.
683        static _eappmem: u8;
684    }
685
686    let app_flash = core::slice::from_raw_parts(
687        core::ptr::addr_of!(_sapps),
688        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
689    );
690    let app_memory = core::slice::from_raw_parts_mut(
691        core::ptr::addr_of_mut!(_sappmem),
692        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
693    );
694
695    // Create and start the asynchronous process loader.
696    let _loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
697        checker,
698        board_kernel,
699        chip,
700        &FAULT_RESPONSE,
701        assigner,
702        storage_permissions_policy,
703        app_flash,
704        app_memory,
705    )
706    .finalize(components::process_loader_sequential_component_static!(
707        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
708        kernel::process::ProcessStandardDebugFull,
709        NUM_PROCS
710    ));
711
712    //--------------------------------------------------------------------------
713    // FINAL SETUP AND BOARD BOOT
714    //--------------------------------------------------------------------------
715
716    // Start all of the clocks. Low power operation will require a better
717    // approach than this.
718    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
719
720    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
721        .finalize(components::round_robin_component_static!(NUM_PROCS));
722
723    let platform = Platform {
724        ble_radio,
725        ieee802154_radio,
726        console,
727        pconsole,
728        adc: adc_syscall,
729        led,
730        button,
731        gpio,
732        rng,
733        screen,
734        alarm,
735        udp_driver,
736        ipc: kernel::ipc::IPC::new(
737            board_kernel,
738            kernel::ipc::DRIVER_NUM,
739            &memory_allocation_capability,
740        ),
741        scheduler,
742        systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
743    };
744
745    // Configure the USB stack to enable a serial port over CDC-ACM.
746    cdc.enable();
747    cdc.attach();
748
749    //--------------------------------------------------------------------------
750    // TESTS
751    //--------------------------------------------------------------------------
752    // test::linear_log_test::run(
753    //     mux_alarm,
754    //     &nrf52840_peripherals.nrf52.nvmc,
755    // );
756    // test::log_test::run(
757    //     mux_alarm,
758    //     &nrf52840_peripherals.nrf52.nvmc,
759    // );
760
761    debug!("Initialization complete. Entering main loop.");
762    let _ = platform.pconsole.start();
763
764    ssd1306.init_screen();
765
766    //--------------------------------------------------------------------------
767    // PROCESSES AND MAIN LOOP
768    //--------------------------------------------------------------------------
769
770    (board_kernel, platform, chip)
771}
772
773/// Main function called after RAM initialized.
774#[no_mangle]
775pub unsafe fn main() {
776    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
777
778    let (board_kernel, platform, chip) = start();
779    board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
780}