1#![no_std]
10#![no_main]
11#![deny(missing_docs)]
12#![feature(custom_test_frameworks)]
13#![test_runner(test_runner)]
14#![reexport_test_harness_main = "test_main"]
15
16use core::ptr::addr_of;
17use core::ptr::addr_of_mut;
18
19use apollo3::chip::Apollo3DefaultPeripherals;
20use capsules_core::virtualizers::virtual_alarm::MuxAlarm;
21use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
22use components::bme280::Bme280Component;
23use components::ccs811::Ccs811Component;
24use kernel::capabilities;
25use kernel::component::Component;
26use kernel::hil::i2c::I2CMaster;
27use kernel::hil::led::LedHigh;
28use kernel::hil::time::Counter;
29use kernel::platform::{KernelResources, SyscallDriverLookup};
30use kernel::scheduler::round_robin::RoundRobinSched;
31use kernel::{create_capability, debug, static_init};
32
33pub mod io;
35
36#[cfg(test)]
37mod tests;
38
39const NUM_PROCS: usize = 4;
41
42static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = [None; 4];
44
45static mut CHIP: Option<&'static apollo3::chip::Apollo3<Apollo3DefaultPeripherals>> = None;
47static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
49 None;
50
51const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
53 capsules_system::process_policies::PanicFaultPolicy {};
54
55#[cfg(test)]
57static mut PERIPHERALS: Option<&'static Apollo3DefaultPeripherals> = None;
58#[cfg(test)]
60static mut BOARD: Option<&'static kernel::Kernel> = None;
61#[cfg(test)]
63static mut PLATFORM: Option<&'static RedboardArtemisNano> = None;
64#[cfg(test)]
66static mut MAIN_CAP: Option<&dyn kernel::capabilities::MainLoopCapability> = None;
67static mut ALARM: Option<&'static MuxAlarm<'static, apollo3::stimer::STimer<'static>>> = None;
69static mut BME280: Option<
71 &'static capsules_extra::bme280::Bme280<
72 'static,
73 capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, apollo3::iom::Iom<'static>>,
74 >,
75> = None;
76static mut CCS811: Option<&'static capsules_extra::ccs811::Ccs811<'static>> = None;
77
78#[no_mangle]
80#[link_section = ".stack_buffer"]
81pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
82
83type BME280Sensor = components::bme280::Bme280ComponentType<
84 capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, apollo3::iom::Iom<'static>>,
85>;
86type TemperatureDriver = components::temperature::TemperatureComponentType<BME280Sensor>;
87type HumidityDriver = components::humidity::HumidityComponentType<BME280Sensor>;
88
89struct RedboardArtemisNano {
92 alarm: &'static capsules_core::alarm::AlarmDriver<
93 'static,
94 VirtualMuxAlarm<'static, apollo3::stimer::STimer<'static>>,
95 >,
96 led: &'static capsules_core::led::LedDriver<
97 'static,
98 LedHigh<'static, apollo3::gpio::GpioPin<'static>>,
99 1,
100 >,
101 gpio: &'static capsules_core::gpio::GPIO<'static, apollo3::gpio::GpioPin<'static>>,
102 console: &'static capsules_core::console::Console<'static>,
103 i2c_master:
104 &'static capsules_core::i2c_master::I2CMasterDriver<'static, apollo3::iom::Iom<'static>>,
105 spi_controller: &'static capsules_core::spi_controller::Spi<
106 'static,
107 capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
108 'static,
109 apollo3::iom::Iom<'static>,
110 >,
111 >,
112 ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
113 'static,
114 apollo3::ble::Ble<'static>,
115 VirtualMuxAlarm<'static, apollo3::stimer::STimer<'static>>,
116 >,
117 temperature: &'static TemperatureDriver,
118 humidity: &'static HumidityDriver,
119 air_quality: &'static capsules_extra::air_quality::AirQualitySensor<'static>,
120 scheduler: &'static RoundRobinSched<'static>,
121 systick: cortexm4::systick::SysTick,
122}
123
124impl SyscallDriverLookup for RedboardArtemisNano {
126 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
127 where
128 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
129 {
130 match driver_num {
131 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
132 capsules_core::led::DRIVER_NUM => f(Some(self.led)),
133 capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
134 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
135 capsules_core::i2c_master::DRIVER_NUM => f(Some(self.i2c_master)),
136 capsules_core::spi_controller::DRIVER_NUM => f(Some(self.spi_controller)),
137 capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
138 capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
139 capsules_extra::humidity::DRIVER_NUM => f(Some(self.humidity)),
140 capsules_extra::air_quality::DRIVER_NUM => f(Some(self.air_quality)),
141 _ => f(None),
142 }
143 }
144}
145
146impl KernelResources<apollo3::chip::Apollo3<Apollo3DefaultPeripherals>> for RedboardArtemisNano {
147 type SyscallDriverLookup = Self;
148 type SyscallFilter = ();
149 type ProcessFault = ();
150 type Scheduler = RoundRobinSched<'static>;
151 type SchedulerTimer = cortexm4::systick::SysTick;
152 type WatchDog = ();
153 type ContextSwitchCallback = ();
154
155 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
156 self
157 }
158 fn syscall_filter(&self) -> &Self::SyscallFilter {
159 &()
160 }
161 fn process_fault(&self) -> &Self::ProcessFault {
162 &()
163 }
164 fn scheduler(&self) -> &Self::Scheduler {
165 self.scheduler
166 }
167 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
168 &self.systick
169 }
170 fn watchdog(&self) -> &Self::WatchDog {
171 &()
172 }
173 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
174 &()
175 }
176}
177
178#[inline(never)]
181unsafe fn setup() -> (
182 &'static kernel::Kernel,
183 &'static RedboardArtemisNano,
184 &'static apollo3::chip::Apollo3<Apollo3DefaultPeripherals>,
185 &'static Apollo3DefaultPeripherals,
186) {
187 let peripherals = static_init!(Apollo3DefaultPeripherals, Apollo3DefaultPeripherals::new());
188
189 let mcu_ctrl = apollo3::mcuctrl::McuCtrl::new();
191 let pwr_ctrl = apollo3::pwrctrl::PwrCtrl::new();
192 let clkgen = apollo3::clkgen::ClkGen::new();
193
194 clkgen.set_clock_frequency(apollo3::clkgen::ClockFrequency::Freq48MHz);
195
196 let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
198 let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
199
200 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
201
202 pwr_ctrl.enable_uart0();
204 pwr_ctrl.enable_iom0();
205 pwr_ctrl.enable_iom2();
206 pwr_ctrl.enable_ios();
207
208 peripherals.init();
209
210 peripherals
212 .gpio_port
213 .enable_uart(&peripherals.gpio_port[48], &peripherals.gpio_port[49]);
214 peripherals
216 .gpio_port
217 .enable_i2c(&peripherals.gpio_port[25], &peripherals.gpio_port[27]);
218 peripherals.gpio_port.enable_spi(
220 &peripherals.gpio_port[5],
221 &peripherals.gpio_port[7],
222 &peripherals.gpio_port[6],
223 );
224 peripherals
226 .gpio_port
227 .enable_i2c_slave(&peripherals.gpio_port[1], &peripherals.gpio_port[0]);
228
229 kernel::debug::assign_gpios(
231 Some(&peripherals.gpio_port[19]), None,
233 None,
234 );
235
236 let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
238 .finalize(components::uart_mux_component_static!());
239
240 let console = components::console::ConsoleComponent::new(
242 board_kernel,
243 capsules_core::console::DRIVER_NUM,
244 uart_mux,
245 )
246 .finalize(components::console_component_static!());
247 components::debug_writer::DebugWriterComponent::new(
249 uart_mux,
250 create_capability!(capabilities::SetDebugWriterCapability),
251 )
252 .finalize(components::debug_writer_component_static!());
253
254 let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
256 LedHigh<'static, apollo3::gpio::GpioPin>,
257 LedHigh::new(&peripherals.gpio_port[19]),
258 ));
259
260 let gpio = components::gpio::GpioComponent::new(
263 board_kernel,
264 capsules_core::gpio::DRIVER_NUM,
265 components::gpio_component_helper!(
266 apollo3::gpio::GpioPin,
267 0 => &peripherals.gpio_port[13], 1 => &peripherals.gpio_port[33], 2 => &peripherals.gpio_port[11], 3 => &peripherals.gpio_port[29], 5 => &peripherals.gpio_port[31] ),
273 )
274 .finalize(components::gpio_component_static!(apollo3::gpio::GpioPin));
275
276 let _ = peripherals.stimer.start();
279 let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.stimer).finalize(
280 components::alarm_mux_component_static!(apollo3::stimer::STimer),
281 );
282 let alarm = components::alarm::AlarmDriverComponent::new(
283 board_kernel,
284 capsules_core::alarm::DRIVER_NUM,
285 mux_alarm,
286 )
287 .finalize(components::alarm_component_static!(apollo3::stimer::STimer));
288 ALARM = Some(mux_alarm);
289
290 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
292 .finalize(components::process_printer_text_component_static!());
293 PROCESS_PRINTER = Some(process_printer);
294
295 let i2c_master_buffer = static_init!(
297 [u8; capsules_core::i2c_master::BUFFER_LENGTH],
298 [0; capsules_core::i2c_master::BUFFER_LENGTH]
299 );
300 let i2c_master = static_init!(
301 capsules_core::i2c_master::I2CMasterDriver<'static, apollo3::iom::Iom<'static>>,
302 capsules_core::i2c_master::I2CMasterDriver::new(
303 &peripherals.iom2,
304 i2c_master_buffer,
305 board_kernel.create_grant(
306 capsules_core::i2c_master::DRIVER_NUM,
307 &memory_allocation_cap
308 )
309 )
310 );
311
312 peripherals.iom2.set_master_client(i2c_master);
313 peripherals.iom2.enable();
314
315 let mux_i2c = components::i2c::I2CMuxComponent::new(&peripherals.iom2, None)
316 .finalize(components::i2c_mux_component_static!(apollo3::iom::Iom));
317
318 let bme280 = Bme280Component::new(mux_i2c, 0x77)
319 .finalize(components::bme280_component_static!(apollo3::iom::Iom));
320 let temperature = components::temperature::TemperatureComponent::new(
321 board_kernel,
322 capsules_extra::temperature::DRIVER_NUM,
323 bme280,
324 )
325 .finalize(components::temperature_component_static!(BME280Sensor));
326 let humidity = components::humidity::HumidityComponent::new(
327 board_kernel,
328 capsules_extra::humidity::DRIVER_NUM,
329 bme280,
330 )
331 .finalize(components::humidity_component_static!(BME280Sensor));
332 BME280 = Some(bme280);
333
334 let ccs811 = Ccs811Component::new(mux_i2c, 0x5B)
335 .finalize(components::ccs811_component_static!(apollo3::iom::Iom));
336 let air_quality = components::air_quality::AirQualityComponent::new(
337 board_kernel,
338 capsules_extra::temperature::DRIVER_NUM,
339 ccs811,
340 )
341 .finalize(components::air_quality_component_static!());
342 CCS811 = Some(ccs811);
343
344 let mux_spi = components::spi::SpiMuxComponent::new(&peripherals.iom0).finalize(
346 components::spi_mux_component_static!(apollo3::iom::Iom<'static>),
347 );
348
349 let spi_controller = components::spi::SpiSyscallComponent::new(
352 board_kernel,
353 mux_spi,
354 kernel::hil::spi::cs::IntoChipSelect::<_, kernel::hil::spi::cs::ActiveLow>::into_cs(
355 &peripherals.gpio_port[35], ),
357 capsules_core::spi_controller::DRIVER_NUM,
358 )
359 .finalize(components::spi_syscall_component_static!(
360 apollo3::iom::Iom<'static>
361 ));
362
363 mcu_ctrl.enable_ble();
365 clkgen.enable_ble();
366 pwr_ctrl.enable_ble();
367 peripherals.ble.setup_clocks();
368 mcu_ctrl.reset_ble();
369 peripherals.ble.power_up();
370 peripherals.ble.ble_initialise();
371
372 let ble_radio = components::ble::BLEComponent::new(
373 board_kernel,
374 capsules_extra::ble_advertising_driver::DRIVER_NUM,
375 &peripherals.ble,
376 mux_alarm,
377 )
378 .finalize(components::ble_component_static!(
379 apollo3::stimer::STimer,
380 apollo3::ble::Ble,
381 ));
382
383 mcu_ctrl.print_chip_revision();
384
385 debug!("Initialization complete. Entering main loop");
386
387 extern "C" {
389 static _sapps: u8;
391 static _eapps: u8;
393 static mut _sappmem: u8;
395 static _eappmem: u8;
397 }
398
399 let scheduler = components::sched::round_robin::RoundRobinComponent::new(&*addr_of!(PROCESSES))
400 .finalize(components::round_robin_component_static!(NUM_PROCS));
401
402 let systick = cortexm4::systick::SysTick::new_with_calibration(48_000_000);
403
404 let artemis_nano = static_init!(
405 RedboardArtemisNano,
406 RedboardArtemisNano {
407 alarm,
408 led,
409 gpio,
410 console,
411 i2c_master,
412 spi_controller,
413 ble_radio,
414 temperature,
415 humidity,
416 air_quality,
417 scheduler,
418 systick,
419 }
420 );
421
422 let chip = static_init!(
423 apollo3::chip::Apollo3<Apollo3DefaultPeripherals>,
424 apollo3::chip::Apollo3::new(peripherals)
425 );
426 CHIP = Some(chip);
427
428 kernel::process::load_processes(
429 board_kernel,
430 chip,
431 core::slice::from_raw_parts(
432 core::ptr::addr_of!(_sapps),
433 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
434 ),
435 core::slice::from_raw_parts_mut(
436 core::ptr::addr_of_mut!(_sappmem),
437 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
438 ),
439 &mut *addr_of_mut!(PROCESSES),
440 &FAULT_RESPONSE,
441 &process_mgmt_cap,
442 )
443 .unwrap_or_else(|err| {
444 debug!("Error loading processes!");
445 debug!("{:?}", err);
446 });
447
448 (board_kernel, artemis_nano, chip, peripherals)
449}
450
451#[no_mangle]
456pub unsafe fn main() {
457 apollo3::init();
458
459 #[cfg(test)]
460 test_main();
461
462 #[cfg(not(test))]
463 {
464 let (board_kernel, esp32_c3_board, chip, _peripherals) = setup();
465
466 let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
467
468 board_kernel.kernel_loop(
469 esp32_c3_board,
470 chip,
471 None::<&kernel::ipc::IPC<{ NUM_PROCS as u8 }>>,
472 &main_loop_cap,
473 );
474 }
475}
476
477#[cfg(test)]
478use kernel::platform::watchdog::WatchDog;
479
480#[cfg(test)]
481fn test_runner(tests: &[&dyn Fn()]) {
482 unsafe {
483 let (board_kernel, esp32_c3_board, _chip, peripherals) = setup();
484
485 BOARD = Some(board_kernel);
486 PLATFORM = Some(&esp32_c3_board);
487 PERIPHERALS = Some(peripherals);
488 MAIN_CAP = Some(&create_capability!(capabilities::MainLoopCapability));
489
490 PLATFORM.map(|p| {
491 p.watchdog().setup();
492 });
493
494 for test in tests {
495 test();
496 }
497 }
498
499 loop {}
500}