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