nrf52840dk_test_dynamic_app_load/
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 Nordic Semiconductor nRF52840 development kit (DK).
6
7#![no_std]
8#![no_main]
9#![deny(missing_docs)]
10
11use kernel::component::Component;
12use kernel::hil::led::LedLow;
13use kernel::hil::time::Counter;
14use kernel::platform::{KernelResources, SyscallDriverLookup};
15use kernel::process::ProcessArray;
16use kernel::process::ProcessLoadingAsync;
17use kernel::scheduler::round_robin::RoundRobinSched;
18use kernel::{capabilities, create_capability, static_init};
19use nrf52840::gpio::Pin;
20use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
21use nrf52_components::{UartChannel, UartPins};
22
23// The nRF52840DK LEDs (see back of board)
24const LED1_PIN: Pin = Pin::P0_13;
25const LED2_PIN: Pin = Pin::P0_14;
26const LED3_PIN: Pin = Pin::P0_15;
27const LED4_PIN: Pin = Pin::P0_16;
28
29// The nRF52840DK buttons (see back of board)
30const BUTTON1_PIN: Pin = Pin::P0_11;
31const BUTTON2_PIN: Pin = Pin::P0_12;
32const BUTTON3_PIN: Pin = Pin::P0_24;
33const BUTTON4_PIN: Pin = Pin::P0_25;
34const BUTTON_RST_PIN: Pin = Pin::P0_18;
35
36const UART_RTS: Option<Pin> = Some(Pin::P0_05);
37const UART_TXD: Pin = Pin::P0_06;
38const UART_CTS: Option<Pin> = Some(Pin::P0_07);
39const UART_RXD: Pin = Pin::P0_08;
40
41/// Debug Writer
42pub mod io;
43
44// State for loading and holding applications.
45// How should the kernel respond when a process faults.
46const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
47    capsules_system::process_policies::PanicFaultPolicy {};
48
49// Number of concurrent processes this platform supports.
50const NUM_PROCS: usize = 8;
51
52/// Static variables used by io.rs.
53static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
54static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
55// Static reference to process printer for panic dumps.
56static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
57    None;
58
59kernel::stack_size! {0x2000}
60
61//------------------------------------------------------------------------------
62// SYSCALL DRIVER TYPE DEFINITIONS
63//------------------------------------------------------------------------------
64
65type AlarmDriver = components::alarm::AlarmDriverComponentType<nrf52840::rtc::Rtc<'static>>;
66
67type NonVolatilePages = components::dynamic_binary_storage::NVPages<nrf52840::nvmc::Nvmc>;
68type DynamicBinaryStorage<'a> = kernel::dynamic_binary_storage::SequentialDynamicBinaryStorage<
69    'static,
70    'static,
71    nrf52840::chip::NRF52<'a, Nrf52840DefaultPeripherals<'a>>,
72    kernel::process::ProcessStandardDebugFull,
73    NonVolatilePages,
74>;
75
76/// Supported drivers by the platform
77pub struct Platform {
78    console: &'static capsules_core::console::Console<'static>,
79    button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
80    adc: &'static capsules_core::adc::AdcDedicated<'static, nrf52840::adc::Adc<'static>>,
81    led: &'static capsules_core::led::LedDriver<
82        'static,
83        kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
84        4,
85    >,
86    alarm: &'static AlarmDriver,
87    scheduler: &'static RoundRobinSched<'static>,
88    systick: cortexm4::systick::SysTick,
89    processes: &'static ProcessArray<NUM_PROCS>,
90    dynamic_app_loader: &'static capsules_extra::app_loader::AppLoader<
91        DynamicBinaryStorage<'static>,
92        DynamicBinaryStorage<'static>,
93    >,
94}
95
96impl SyscallDriverLookup for Platform {
97    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
98    where
99        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
100    {
101        match driver_num {
102            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
103            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
104            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
105            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
106            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
107            capsules_extra::app_loader::DRIVER_NUM => f(Some(self.dynamic_app_loader)),
108            _ => f(None),
109        }
110    }
111}
112
113/// This is in a separate, inline(never) function so that its stack frame is
114/// removed when this function returns. Otherwise, the stack space used for
115/// these static_inits is wasted.
116#[inline(never)]
117unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
118    let ieee802154_ack_buf = static_init!(
119        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
120        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
121    );
122    // Initialize chip peripheral drivers
123    let nrf52840_peripherals = static_init!(
124        Nrf52840DefaultPeripherals,
125        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
126    );
127
128    nrf52840_peripherals
129}
130
131impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
132    for Platform
133{
134    type SyscallDriverLookup = Self;
135    type SyscallFilter = ();
136    type ProcessFault = ();
137    type Scheduler = RoundRobinSched<'static>;
138    type SchedulerTimer = cortexm4::systick::SysTick;
139    type WatchDog = ();
140    type ContextSwitchCallback = ();
141
142    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
143        self
144    }
145    fn syscall_filter(&self) -> &Self::SyscallFilter {
146        &()
147    }
148    fn process_fault(&self) -> &Self::ProcessFault {
149        &()
150    }
151    fn scheduler(&self) -> &Self::Scheduler {
152        self.scheduler
153    }
154    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
155        &self.systick
156    }
157    fn watchdog(&self) -> &Self::WatchDog {
158        &()
159    }
160    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
161        &()
162    }
163}
164
165impl kernel::process::ProcessLoadingAsyncClient for Platform {
166    fn process_loaded(&self, _result: Result<(), kernel::process::ProcessLoadError>) {}
167
168    fn process_loading_finished(&self) {
169        kernel::debug!("Processes Loaded at Main:");
170
171        for (i, proc) in self.processes.as_slice().iter().enumerate() {
172            proc.get().map(|p| {
173                kernel::debug!("[{}] {}", i, p.get_process_name());
174                kernel::debug!("    ShortId: {}", p.short_app_id());
175            });
176        }
177    }
178}
179
180/// Main function called after RAM initialized.
181#[no_mangle]
182pub unsafe fn main() {
183    //--------------------------------------------------------------------------
184    // INITIAL SETUP
185    //--------------------------------------------------------------------------
186
187    // Apply errata fixes and enable interrupts.
188    nrf52840::init();
189
190    // Set up peripheral drivers. Called in separate function to reduce stack
191    // usage.
192    let nrf52840_peripherals = create_peripherals();
193
194    // Set up circular peripheral dependencies.
195    nrf52840_peripherals.init();
196    let base_peripherals = &nrf52840_peripherals.nrf52;
197
198    // Choose the channel for serial output. This board can be configured to use
199    // either the Segger RTT channel or via UART with traditional TX/RX GPIO
200    // pins.
201    let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
202
203    // Create an array to hold process references.
204    let processes = components::process_array::ProcessArrayComponent::new()
205        .finalize(components::process_array_component_static!(NUM_PROCS));
206    PROCESSES = Some(processes);
207
208    // Setup space to store the core kernel data structure.
209    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
210
211    // Create (and save for panic debugging) a chip object to setup low-level
212    // resources (e.g. MPU, systick).
213    let chip = static_init!(
214        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
215        nrf52840::chip::NRF52::new(nrf52840_peripherals)
216    );
217    CHIP = Some(chip);
218
219    // Do nRF configuration and setup. This is shared code with other nRF-based
220    // platforms.
221    nrf52_components::startup::NrfStartupComponent::new(
222        false,
223        BUTTON_RST_PIN,
224        nrf52840::uicr::Regulator0Output::DEFAULT,
225        &base_peripherals.nvmc,
226    )
227    .finalize(());
228
229    //--------------------------------------------------------------------------
230    // CAPABILITIES
231    //--------------------------------------------------------------------------
232
233    // Create capabilities that the board needs to call certain protected kernel
234    // functions.
235    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
236
237    //--------------------------------------------------------------------------
238    // LEDs
239    //--------------------------------------------------------------------------
240
241    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
242        LedLow<'static, nrf52840::gpio::GPIOPin>,
243        LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
244        LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
245        LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
246        LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
247    ));
248
249    //--------------------------------------------------------------------------
250    // TIMER
251    //--------------------------------------------------------------------------
252
253    let rtc = &base_peripherals.rtc;
254    let _ = rtc.start();
255    let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
256        .finalize(components::alarm_mux_component_static!(nrf52840::rtc::Rtc));
257    let alarm = components::alarm::AlarmDriverComponent::new(
258        board_kernel,
259        capsules_core::alarm::DRIVER_NUM,
260        mux_alarm,
261    )
262    .finalize(components::alarm_component_static!(nrf52840::rtc::Rtc));
263
264    //--------------------------------------------------------------------------
265    // UART & CONSOLE & DEBUG
266    //--------------------------------------------------------------------------
267
268    let uart_channel = nrf52_components::UartChannelComponent::new(
269        uart_channel,
270        mux_alarm,
271        &base_peripherals.uarte0,
272    )
273    .finalize(nrf52_components::uart_channel_component_static!(
274        nrf52840::rtc::Rtc
275    ));
276
277    // Virtualize the UART channel for the console and for kernel debug.
278    let uart_mux = components::console::UartMuxComponent::new(uart_channel, 115200)
279        .finalize(components::uart_mux_component_static!());
280
281    // Setup the serial console for userspace.
282    let console = components::console::ConsoleComponent::new(
283        board_kernel,
284        capsules_core::console::DRIVER_NUM,
285        uart_mux,
286    )
287    .finalize(components::console_component_static!());
288
289    // Tool for displaying information about processes.
290    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
291        .finalize(components::process_printer_text_component_static!());
292    PROCESS_PRINTER = Some(process_printer);
293
294    // Create the process console, an interactive terminal for managing
295    // processes.
296    let pconsole = components::process_console::ProcessConsoleComponent::new(
297        board_kernel,
298        uart_mux,
299        mux_alarm,
300        process_printer,
301        Some(cortexm4::support::reset),
302    )
303    .finalize(components::process_console_component_static!(
304        nrf52840::rtc::Rtc<'static>
305    ));
306
307    // Create the debugger object that handles calls to `debug!()`.
308    components::debug_writer::DebugWriterComponent::new(
309        uart_mux,
310        create_capability!(capabilities::SetDebugWriterCapability),
311    )
312    .finalize(components::debug_writer_component_static!());
313
314    //--------------------------------------------------------------------------
315    // BUTTONS
316    //--------------------------------------------------------------------------
317
318    let button = components::button::ButtonComponent::new(
319        board_kernel,
320        capsules_core::button::DRIVER_NUM,
321        components::button_component_helper!(
322            nrf52840::gpio::GPIOPin,
323            (
324                &nrf52840_peripherals.gpio_port[BUTTON1_PIN],
325                kernel::hil::gpio::ActivationMode::ActiveLow,
326                kernel::hil::gpio::FloatingState::PullUp
327            ),
328            (
329                &nrf52840_peripherals.gpio_port[BUTTON2_PIN],
330                kernel::hil::gpio::ActivationMode::ActiveLow,
331                kernel::hil::gpio::FloatingState::PullUp
332            ),
333            (
334                &nrf52840_peripherals.gpio_port[BUTTON3_PIN],
335                kernel::hil::gpio::ActivationMode::ActiveLow,
336                kernel::hil::gpio::FloatingState::PullUp
337            ),
338            (
339                &nrf52840_peripherals.gpio_port[BUTTON4_PIN],
340                kernel::hil::gpio::ActivationMode::ActiveLow,
341                kernel::hil::gpio::FloatingState::PullUp
342            )
343        ),
344    )
345    .finalize(components::button_component_static!(
346        nrf52840::gpio::GPIOPin
347    ));
348
349    //--------------------------------------------------------------------------
350    // ADC
351    //--------------------------------------------------------------------------
352
353    let adc_channels = static_init!(
354        [nrf52840::adc::AdcChannelSetup; 6],
355        [
356            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput1),
357            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput2),
358            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput4),
359            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput5),
360            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput6),
361            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput7),
362        ]
363    );
364    let adc = components::adc::AdcDedicatedComponent::new(
365        &base_peripherals.adc,
366        adc_channels,
367        board_kernel,
368        capsules_core::adc::DRIVER_NUM,
369    )
370    .finalize(components::adc_dedicated_component_static!(
371        nrf52840::adc::Adc
372    ));
373
374    //--------------------------------------------------------------------------
375    // NRF CLOCK SETUP
376    //--------------------------------------------------------------------------
377
378    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
379
380    //--------------------------------------------------------------------------
381    // Credential Checking
382    //--------------------------------------------------------------------------
383
384    // Create the credential checker.
385    let checking_policy = components::appid::checker_null::AppCheckerNullComponent::new()
386        .finalize(components::app_checker_null_component_static!());
387
388    // Create the AppID assigner.
389    let assigner = components::appid::assigner_tbf::AppIdAssignerTbfHeaderComponent::new()
390        .finalize(components::appid_assigner_tbf_header_component_static!());
391
392    // Create the process checking machine.
393    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
394        .finalize(components::process_checker_machine_component_static!());
395
396    //--------------------------------------------------------------------------
397    // STORAGE PERMISSIONS
398    //--------------------------------------------------------------------------
399
400    let storage_permissions_policy =
401        components::storage_permissions::null::StoragePermissionsNullComponent::new().finalize(
402            components::storage_permissions_null_component_static!(
403                nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
404                kernel::process::ProcessStandardDebugFull,
405            ),
406        );
407
408    // These symbols are defined in the standard Tock linker script.
409    extern "C" {
410        /// Beginning of the ROM region containing app images.
411        static _sapps: u8;
412        /// End of the ROM region containing app images.
413        static _eapps: u8;
414        /// Beginning of the RAM region for app memory.
415        static mut _sappmem: u8;
416        /// End of the RAM region for app memory.
417        static _eappmem: u8;
418    }
419
420    let app_flash = core::slice::from_raw_parts(
421        core::ptr::addr_of!(_sapps),
422        core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
423    );
424    let app_memory = core::slice::from_raw_parts_mut(
425        core::ptr::addr_of_mut!(_sappmem),
426        core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
427    );
428
429    // Create and start the asynchronous process loader.
430    let loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
431        checker,
432        board_kernel,
433        chip,
434        &FAULT_RESPONSE,
435        assigner,
436        storage_permissions_policy,
437        app_flash,
438        app_memory,
439    )
440    .finalize(components::process_loader_sequential_component_static!(
441        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
442        kernel::process::ProcessStandardDebugFull,
443        NUM_PROCS
444    ));
445
446    //--------------------------------------------------------------------------
447    // Dynamic App Loading
448    //--------------------------------------------------------------------------
449
450    // Create the dynamic binary flasher.
451    let dynamic_binary_storage =
452        components::dynamic_binary_storage::SequentialBinaryStorageComponent::new(
453            &base_peripherals.nvmc,
454            loader,
455        )
456        .finalize(components::sequential_binary_storage_component_static!(
457            nrf52840::nvmc::Nvmc,
458            nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
459            kernel::process::ProcessStandardDebugFull,
460        ));
461
462    // Create the dynamic app loader capsule.
463    let dynamic_app_loader = components::app_loader::AppLoaderComponent::new(
464        board_kernel,
465        capsules_extra::app_loader::DRIVER_NUM,
466        dynamic_binary_storage,
467        dynamic_binary_storage,
468    )
469    .finalize(components::app_loader_component_static!(
470        DynamicBinaryStorage<'static>,
471        DynamicBinaryStorage<'static>,
472    ));
473
474    //--------------------------------------------------------------------------
475    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
476    //--------------------------------------------------------------------------
477
478    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
479        .finalize(components::round_robin_component_static!(NUM_PROCS));
480
481    let platform = static_init!(
482        Platform,
483        Platform {
484            console,
485            button,
486            adc,
487            led,
488            alarm,
489            scheduler,
490            systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
491            processes,
492            dynamic_app_loader,
493        }
494    );
495    loader.set_client(platform);
496
497    let _ = pconsole.start();
498
499    board_kernel.kernel_loop(
500        platform,
501        chip,
502        None::<&kernel::ipc::IPC<0>>,
503        &main_loop_capability,
504    );
505}