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