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