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