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