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