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