#![no_std]
#![cfg_attr(not(doc), no_main)]
#![deny(missing_docs)]
#![feature(custom_test_frameworks)]
#![test_runner(test_runner)]
#![reexport_test_harness_main = "test_main"]
use core::ptr::addr_of;
use core::ptr::addr_of_mut;
use apollo3::chip::Apollo3DefaultPeripherals;
use capsules_core::virtualizers::virtual_alarm::MuxAlarm;
use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
use components::bme280::Bme280Component;
use components::ccs811::Ccs811Component;
use kernel::capabilities;
use kernel::component::Component;
use kernel::hil::i2c::I2CMaster;
use kernel::hil::led::LedHigh;
use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup};
use kernel::scheduler::round_robin::RoundRobinSched;
use kernel::{create_capability, debug, static_init};
pub mod io;
#[cfg(test)]
mod tests;
const NUM_PROCS: usize = 4;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = [None; 4];
static mut CHIP: Option<&'static apollo3::chip::Apollo3<Apollo3DefaultPeripherals>> = None;
static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
None;
const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
capsules_system::process_policies::PanicFaultPolicy {};
#[cfg(test)]
static mut PERIPHERALS: Option<&'static Apollo3DefaultPeripherals> = None;
#[cfg(test)]
static mut BOARD: Option<&'static kernel::Kernel> = None;
#[cfg(test)]
static mut PLATFORM: Option<&'static RedboardArtemisNano> = None;
#[cfg(test)]
static mut MAIN_CAP: Option<&dyn kernel::capabilities::MainLoopCapability> = None;
static mut ALARM: Option<&'static MuxAlarm<'static, apollo3::stimer::STimer<'static>>> = None;
static mut BME280: Option<
&'static capsules_extra::bme280::Bme280<
'static,
capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, apollo3::iom::Iom<'static>>,
>,
> = None;
static mut CCS811: Option<&'static capsules_extra::ccs811::Ccs811<'static>> = None;
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
type BME280Sensor = components::bme280::Bme280ComponentType<
capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, apollo3::iom::Iom<'static>>,
>;
type TemperatureDriver = components::temperature::TemperatureComponentType<BME280Sensor>;
type HumidityDriver = components::humidity::HumidityComponentType<BME280Sensor>;
struct RedboardArtemisNano {
alarm: &'static capsules_core::alarm::AlarmDriver<
'static,
VirtualMuxAlarm<'static, apollo3::stimer::STimer<'static>>,
>,
led: &'static capsules_core::led::LedDriver<
'static,
LedHigh<'static, apollo3::gpio::GpioPin<'static>>,
1,
>,
gpio: &'static capsules_core::gpio::GPIO<'static, apollo3::gpio::GpioPin<'static>>,
console: &'static capsules_core::console::Console<'static>,
i2c_master:
&'static capsules_core::i2c_master::I2CMasterDriver<'static, apollo3::iom::Iom<'static>>,
spi_controller: &'static capsules_core::spi_controller::Spi<
'static,
capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
'static,
apollo3::iom::Iom<'static>,
>,
>,
ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
'static,
apollo3::ble::Ble<'static>,
VirtualMuxAlarm<'static, apollo3::stimer::STimer<'static>>,
>,
temperature: &'static TemperatureDriver,
humidity: &'static HumidityDriver,
air_quality: &'static capsules_extra::air_quality::AirQualitySensor<'static>,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
}
impl SyscallDriverLookup for RedboardArtemisNano {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
{
match driver_num {
capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
capsules_core::led::DRIVER_NUM => f(Some(self.led)),
capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
capsules_core::console::DRIVER_NUM => f(Some(self.console)),
capsules_core::i2c_master::DRIVER_NUM => f(Some(self.i2c_master)),
capsules_core::spi_controller::DRIVER_NUM => f(Some(self.spi_controller)),
capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
capsules_extra::humidity::DRIVER_NUM => f(Some(self.humidity)),
capsules_extra::air_quality::DRIVER_NUM => f(Some(self.air_quality)),
_ => f(None),
}
}
}
impl KernelResources<apollo3::chip::Apollo3<Apollo3DefaultPeripherals>> for RedboardArtemisNano {
type SyscallDriverLookup = Self;
type SyscallFilter = ();
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&()
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
#[inline(never)]
unsafe fn setup() -> (
&'static kernel::Kernel,
&'static RedboardArtemisNano,
&'static apollo3::chip::Apollo3<Apollo3DefaultPeripherals>,
&'static Apollo3DefaultPeripherals,
) {
let peripherals = static_init!(Apollo3DefaultPeripherals, Apollo3DefaultPeripherals::new());
let mcu_ctrl = apollo3::mcuctrl::McuCtrl::new();
let pwr_ctrl = apollo3::pwrctrl::PwrCtrl::new();
let clkgen = apollo3::clkgen::ClkGen::new();
clkgen.set_clock_frequency(apollo3::clkgen::ClockFrequency::Freq48MHz);
let process_mgmt_cap = create_capability!(capabilities::ProcessManagementCapability);
let memory_allocation_cap = create_capability!(capabilities::MemoryAllocationCapability);
let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
pwr_ctrl.enable_uart0();
pwr_ctrl.enable_iom0();
pwr_ctrl.enable_iom2();
pwr_ctrl.enable_ios();
peripherals.init();
peripherals
.gpio_port
.enable_uart(&peripherals.gpio_port[48], &peripherals.gpio_port[49]);
peripherals
.gpio_port
.enable_i2c(&peripherals.gpio_port[25], &peripherals.gpio_port[27]);
peripherals.gpio_port.enable_spi(
&peripherals.gpio_port[5],
&peripherals.gpio_port[7],
&peripherals.gpio_port[6],
);
peripherals
.gpio_port
.enable_i2c_slave(&peripherals.gpio_port[1], &peripherals.gpio_port[0]);
kernel::debug::assign_gpios(
Some(&peripherals.gpio_port[19]), None,
None,
);
let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
.finalize(components::uart_mux_component_static!());
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules_core::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_static!());
components::debug_writer::DebugWriterComponent::new(uart_mux)
.finalize(components::debug_writer_component_static!());
let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
LedHigh<'static, apollo3::gpio::GpioPin>,
LedHigh::new(&peripherals.gpio_port[19]),
));
let gpio = components::gpio::GpioComponent::new(
board_kernel,
capsules_core::gpio::DRIVER_NUM,
components::gpio_component_helper!(
apollo3::gpio::GpioPin,
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] ),
)
.finalize(components::gpio_component_static!(apollo3::gpio::GpioPin));
let _ = peripherals.stimer.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.stimer).finalize(
components::alarm_mux_component_static!(apollo3::stimer::STimer),
);
let alarm = components::alarm::AlarmDriverComponent::new(
board_kernel,
capsules_core::alarm::DRIVER_NUM,
mux_alarm,
)
.finalize(components::alarm_component_static!(apollo3::stimer::STimer));
ALARM = Some(mux_alarm);
let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
.finalize(components::process_printer_text_component_static!());
PROCESS_PRINTER = Some(process_printer);
let i2c_master_buffer = static_init!(
[u8; capsules_core::i2c_master::BUFFER_LENGTH],
[0; capsules_core::i2c_master::BUFFER_LENGTH]
);
let i2c_master = static_init!(
capsules_core::i2c_master::I2CMasterDriver<'static, apollo3::iom::Iom<'static>>,
capsules_core::i2c_master::I2CMasterDriver::new(
&peripherals.iom2,
i2c_master_buffer,
board_kernel.create_grant(
capsules_core::i2c_master::DRIVER_NUM,
&memory_allocation_cap
)
)
);
peripherals.iom2.set_master_client(i2c_master);
peripherals.iom2.enable();
let mux_i2c = components::i2c::I2CMuxComponent::new(&peripherals.iom2, None)
.finalize(components::i2c_mux_component_static!(apollo3::iom::Iom));
let bme280 = Bme280Component::new(mux_i2c, 0x77)
.finalize(components::bme280_component_static!(apollo3::iom::Iom));
let temperature = components::temperature::TemperatureComponent::new(
board_kernel,
capsules_extra::temperature::DRIVER_NUM,
bme280,
)
.finalize(components::temperature_component_static!(BME280Sensor));
let humidity = components::humidity::HumidityComponent::new(
board_kernel,
capsules_extra::humidity::DRIVER_NUM,
bme280,
)
.finalize(components::humidity_component_static!(BME280Sensor));
BME280 = Some(bme280);
let ccs811 = Ccs811Component::new(mux_i2c, 0x5B)
.finalize(components::ccs811_component_static!(apollo3::iom::Iom));
let air_quality = components::air_quality::AirQualityComponent::new(
board_kernel,
capsules_extra::temperature::DRIVER_NUM,
ccs811,
)
.finalize(components::air_quality_component_static!());
CCS811 = Some(ccs811);
let mux_spi = components::spi::SpiMuxComponent::new(&peripherals.iom0).finalize(
components::spi_mux_component_static!(apollo3::iom::Iom<'static>),
);
let spi_controller = components::spi::SpiSyscallComponent::new(
board_kernel,
mux_spi,
kernel::hil::spi::cs::IntoChipSelect::<_, kernel::hil::spi::cs::ActiveLow>::into_cs(
&peripherals.gpio_port[35], ),
capsules_core::spi_controller::DRIVER_NUM,
)
.finalize(components::spi_syscall_component_static!(
apollo3::iom::Iom<'static>
));
mcu_ctrl.enable_ble();
clkgen.enable_ble();
pwr_ctrl.enable_ble();
peripherals.ble.setup_clocks();
mcu_ctrl.reset_ble();
peripherals.ble.power_up();
peripherals.ble.ble_initialise();
let ble_radio = components::ble::BLEComponent::new(
board_kernel,
capsules_extra::ble_advertising_driver::DRIVER_NUM,
&peripherals.ble,
mux_alarm,
)
.finalize(components::ble_component_static!(
apollo3::stimer::STimer,
apollo3::ble::Ble,
));
mcu_ctrl.print_chip_revision();
debug!("Initialization complete. Entering main loop");
extern "C" {
static _sapps: u8;
static _eapps: u8;
static mut _sappmem: u8;
static _eappmem: u8;
}
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&*addr_of!(PROCESSES))
.finalize(components::round_robin_component_static!(NUM_PROCS));
let systick = cortexm4::systick::SysTick::new_with_calibration(48_000_000);
let artemis_nano = static_init!(
RedboardArtemisNano,
RedboardArtemisNano {
alarm,
led,
gpio,
console,
i2c_master,
spi_controller,
ble_radio,
temperature,
humidity,
air_quality,
scheduler,
systick,
}
);
let chip = static_init!(
apollo3::chip::Apollo3<Apollo3DefaultPeripherals>,
apollo3::chip::Apollo3::new(peripherals)
);
CHIP = Some(chip);
kernel::process::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
core::ptr::addr_of!(_sapps),
core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
),
core::slice::from_raw_parts_mut(
core::ptr::addr_of_mut!(_sappmem),
core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
),
&mut *addr_of_mut!(PROCESSES),
&FAULT_RESPONSE,
&process_mgmt_cap,
)
.unwrap_or_else(|err| {
debug!("Error loading processes!");
debug!("{:?}", err);
});
(board_kernel, artemis_nano, chip, peripherals)
}
#[no_mangle]
pub unsafe fn main() {
apollo3::init();
#[cfg(test)]
test_main();
#[cfg(not(test))]
{
let (board_kernel, esp32_c3_board, chip, _peripherals) = setup();
let main_loop_cap = create_capability!(capabilities::MainLoopCapability);
board_kernel.kernel_loop(
esp32_c3_board,
chip,
None::<&kernel::ipc::IPC<{ NUM_PROCS as u8 }>>,
&main_loop_cap,
);
}
}
#[cfg(test)]
use kernel::platform::watchdog::WatchDog;
#[cfg(test)]
fn test_runner(tests: &[&dyn Fn()]) {
unsafe {
let (board_kernel, esp32_c3_board, _chip, peripherals) = setup();
BOARD = Some(board_kernel);
PLATFORM = Some(&esp32_c3_board);
PERIPHERALS = Some(peripherals);
MAIN_CAP = Some(&create_capability!(capabilities::MainLoopCapability));
PLATFORM.map(|p| {
p.watchdog().setup();
});
for test in tests {
test();
}
}
loop {}
}