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