nrf52840dk_hotp_tutorial/
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 2024.
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 core::ptr::addr_of_mut;
12use kernel::component::Component;
13use kernel::debug;
14use kernel::hil::usb::Client;
15use kernel::platform::{KernelResources, SyscallDriverLookup};
16use kernel::static_init;
17use kernel::{capabilities, create_capability};
18use nrf52840::gpio::Pin;
19use nrf52840dk_lib::{self, PROCESSES};
20
21// State for loading and holding applications.
22// How should the kernel respond when a process faults.
23const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
24    capsules_system::process_policies::PanicFaultPolicy {};
25
26// Screen
27type ScreenDriver = components::screen::ScreenComponentType;
28
29// USB Keyboard HID - for nRF52840dk
30type UsbHw = nrf52840::usbd::Usbd<'static>; // For any nRF52840 board.
31type KeyboardHidDriver = components::keyboard_hid::KeyboardHidComponentType<UsbHw>;
32
33// HMAC
34type HmacSha256Software = components::hmac::HmacSha256SoftwareComponentType<
35    capsules_extra::sha256::Sha256Software<'static>,
36>;
37type HmacDriver = components::hmac::HmacComponentType<HmacSha256Software, 32>;
38
39struct Platform {
40    keyboard_hid_driver: &'static KeyboardHidDriver,
41    hmac: &'static HmacDriver,
42    screen: &'static ScreenDriver,
43    base: nrf52840dk_lib::Platform,
44}
45
46const KEYBOARD_HID_DRIVER_NUM: usize = capsules_core::driver::NUM::KeyboardHid as usize;
47
48impl SyscallDriverLookup for Platform {
49    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
50    where
51        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
52    {
53        match driver_num {
54            capsules_extra::hmac::DRIVER_NUM => f(Some(self.hmac)),
55            KEYBOARD_HID_DRIVER_NUM => f(Some(self.keyboard_hid_driver)),
56            capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)),
57            _ => self.base.with_driver(driver_num, f),
58        }
59    }
60}
61
62type Chip = nrf52840dk_lib::Chip;
63
64impl KernelResources<Chip> for Platform {
65    type SyscallDriverLookup = Self;
66    type SyscallFilter = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SyscallFilter;
67    type ProcessFault = <nrf52840dk_lib::Platform as KernelResources<Chip>>::ProcessFault;
68    type Scheduler = <nrf52840dk_lib::Platform as KernelResources<Chip>>::Scheduler;
69    type SchedulerTimer = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SchedulerTimer;
70    type WatchDog = <nrf52840dk_lib::Platform as KernelResources<Chip>>::WatchDog;
71    type ContextSwitchCallback =
72        <nrf52840dk_lib::Platform as KernelResources<Chip>>::ContextSwitchCallback;
73
74    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
75        self
76    }
77    fn syscall_filter(&self) -> &Self::SyscallFilter {
78        self.base.syscall_filter()
79    }
80    fn process_fault(&self) -> &Self::ProcessFault {
81        self.base.process_fault()
82    }
83    fn scheduler(&self) -> &Self::Scheduler {
84        self.base.scheduler()
85    }
86    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
87        self.base.scheduler_timer()
88    }
89    fn watchdog(&self) -> &Self::WatchDog {
90        self.base.watchdog()
91    }
92    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
93        self.base.context_switch_callback()
94    }
95}
96
97/// Main function called after RAM initialized.
98#[no_mangle]
99pub unsafe fn main() {
100    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
101
102    // Create the base board:
103    let (board_kernel, base_platform, chip, nrf52840_peripherals, _mux_alarm) =
104        nrf52840dk_lib::start();
105
106    //--------------------------------------------------------------------------
107    // HMAC-SHA256
108    //--------------------------------------------------------------------------
109
110    let sha256_sw = components::sha::ShaSoftware256Component::new()
111        .finalize(components::sha_software_256_component_static!());
112
113    let hmac_sha256_sw = components::hmac::HmacSha256SoftwareComponent::new(sha256_sw).finalize(
114        components::hmac_sha256_software_component_static!(capsules_extra::sha256::Sha256Software),
115    );
116
117    let hmac = components::hmac::HmacComponent::new(
118        board_kernel,
119        capsules_extra::hmac::DRIVER_NUM,
120        hmac_sha256_sw,
121    )
122    .finalize(components::hmac_component_static!(HmacSha256Software, 32));
123
124    //--------------------------------------------------------------------------
125    // SCREEN
126    //--------------------------------------------------------------------------
127
128    const SCREEN_I2C_SDA_PIN: Pin = Pin::P1_10;
129    const SCREEN_I2C_SCL_PIN: Pin = Pin::P1_11;
130
131    let i2c_bus = components::i2c::I2CMuxComponent::new(&nrf52840_peripherals.nrf52.twi1, None)
132        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
133    nrf52840_peripherals.nrf52.twi1.configure(
134        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SCL_PIN as u32),
135        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SDA_PIN as u32),
136    );
137    nrf52840_peripherals
138        .nrf52
139        .twi1
140        .set_speed(nrf52840::i2c::Speed::K400);
141
142    // I2C address is b011110X, and on this board D/C̅ is GND.
143    let ssd1306_sh1106_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
144        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
145
146    // Create the ssd1306 object for the actual screen driver.
147    #[cfg(feature = "screen_ssd1306")]
148    let ssd1306_sh1106 = components::ssd1306::Ssd1306Component::new(ssd1306_sh1106_i2c, true)
149        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
150
151    #[cfg(feature = "screen_sh1106")]
152    let ssd1306_sh1106 = components::sh1106::Sh1106Component::new(ssd1306_sh1106_i2c, true)
153        .finalize(components::sh1106_component_static!(nrf52840::i2c::TWI));
154
155    let screen = components::screen::ScreenComponent::new(
156        board_kernel,
157        capsules_extra::screen::DRIVER_NUM,
158        ssd1306_sh1106,
159        None,
160    )
161    .finalize(components::screen_component_static!(1032));
162
163    ssd1306_sh1106.init_screen();
164
165    //--------------------------------------------------------------------------
166    // KEYBOARD
167    //--------------------------------------------------------------------------
168
169    // Create the strings we include in the USB descriptor.
170    let strings = static_init!(
171        [&str; 3],
172        [
173            "Nordic Semiconductor", // Manufacturer
174            "nRF52840dk - TockOS",  // Product
175            "serial0001",           // Serial number
176        ]
177    );
178
179    let usb_device = &nrf52840_peripherals.usbd;
180
181    // Generic HID Keyboard component usage
182    let (keyboard_hid, keyboard_hid_driver) = components::keyboard_hid::KeyboardHidComponent::new(
183        board_kernel,
184        capsules_core::driver::NUM::KeyboardHid as usize,
185        usb_device,
186        0x1915, // Nordic Semiconductor
187        0x503a,
188        strings,
189    )
190    .finalize(components::keyboard_hid_component_static!(UsbHw));
191
192    keyboard_hid.enable();
193    keyboard_hid.attach();
194
195    //--------------------------------------------------------------------------
196    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
197    //--------------------------------------------------------------------------
198
199    let platform = Platform {
200        base: base_platform,
201        keyboard_hid_driver,
202        hmac,
203        screen,
204    };
205
206    // These symbols are defined in the linker script.
207    extern "C" {
208        /// Beginning of the ROM region containing app images.
209        static _sapps: u8;
210        /// End of the ROM region containing app images.
211        static _eapps: u8;
212        /// Beginning of the RAM region for app memory.
213        static mut _sappmem: u8;
214        /// End of the RAM region for app memory.
215        static _eappmem: u8;
216    }
217
218    let process_management_capability =
219        create_capability!(capabilities::ProcessManagementCapability);
220
221    kernel::process::load_processes(
222        board_kernel,
223        chip,
224        core::slice::from_raw_parts(
225            core::ptr::addr_of!(_sapps),
226            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
227        ),
228        core::slice::from_raw_parts_mut(
229            core::ptr::addr_of_mut!(_sappmem),
230            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
231        ),
232        &mut *addr_of_mut!(PROCESSES),
233        &FAULT_RESPONSE,
234        &process_management_capability,
235    )
236    .unwrap_or_else(|err| {
237        debug!("Error loading processes!");
238        debug!("{:?}", err);
239    });
240
241    board_kernel.kernel_loop(
242        &platform,
243        chip,
244        Some(&platform.base.ipc),
245        &main_loop_capability,
246    );
247}