simulation: rewrite the storage and simulation stack
This commit is contained in:
155
src/bin/main.rs
155
src/bin/main.rs
@@ -51,6 +51,10 @@ fn gpio_interrupt_handler() {
|
||||
INTERRUPTS.try_get().unwrap().process_interrupts();
|
||||
}
|
||||
|
||||
static MOTION_BUS: ConstStaticCell<Channel<CriticalSectionRawMutex,Measurement,5> > = ConstStaticCell::new(Channel::new());
|
||||
static RECORDING_BUS: ConstStaticCell<PubSubChannel<CriticalSectionRawMutex,Measurement,10, 4, 1> > = ConstStaticCell::new(PubSubChannel::new());
|
||||
static PREDICTIONS: ConstStaticCell<PubSubChannel<NoopRawMutex, Prediction, 30, 7, 1>> = ConstStaticCell::new(PubSubChannel::new());
|
||||
|
||||
#[esp_rtos::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
// If we aren't using the second CPU, we can use the bootloader space for the heap instead
|
||||
@@ -72,11 +76,8 @@ async fn main(spawner: Spawner) {
|
||||
esp_rtos::start(sys_timer.alarm0);
|
||||
info!("Embassy initialized!");
|
||||
|
||||
static MOTION_BUS: StaticCell<Channel<CriticalSectionRawMutex,Measurement,5> > = StaticCell::new();
|
||||
let motion_bus = MOTION_BUS.init_with(|| { Channel::new() });
|
||||
|
||||
static RECORDING_BUS: StaticCell<PubSubChannel<CriticalSectionRawMutex,Measurement,1, 2, 1> > = StaticCell::new();
|
||||
let recording_bus = RECORDING_BUS.init_with(|| { PubSubChannel::new() });
|
||||
let motion_bus = MOTION_BUS.take();
|
||||
let recording_bus = RECORDING_BUS.take();
|
||||
|
||||
info!("Setting up rendering pipeline");
|
||||
let mut surfaces = UiSurfacePool::default();
|
||||
@@ -160,32 +161,6 @@ async fn main(spawner: Spawner) {
|
||||
spawner.must_spawn(renderbug_bike::tasks::oled_render::oled_render(output, oled_surfaces, oled_uniforms));
|
||||
}
|
||||
|
||||
let mut storage = renderbug_bike::storage::SharedFlash::new(esp_storage::FlashStorage::new());
|
||||
let mut partition_buf = [8; 1024];
|
||||
let partitions = esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut partition_buf).unwrap();
|
||||
|
||||
#[cfg(feature="simulation")]
|
||||
{
|
||||
use renderbug_bike::tasks::simulation::SimDataTable;
|
||||
for sim_data in SimDataTable::open(storage, partitions).expect("Could not find sim data!") {
|
||||
let srcid = sim_data.srcid();
|
||||
info!("Found simulation data for {srcid:?}");
|
||||
if spawner.spawn(renderbug_bike::tasks::simulation::simulation_task(sim_data, motion_bus.dyn_sender())).is_err() {
|
||||
error!("Unable to spawn simulation task for {srcid:?}! Increase the task pool size.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature="simulation"))]
|
||||
{
|
||||
use renderbug_bike::storage::SimDataRecorder;
|
||||
|
||||
let recorder = SimDataRecorder::open(storage, partitions).expect("Unable to open sim data partition for writing");
|
||||
//spawner.spawn(record_telemetry(recording_bus.dyn_receiver(), recorder)).unwrap();
|
||||
}
|
||||
|
||||
spawner.spawn(print_sensor_readings(recording_bus.dyn_subscriber().unwrap())).unwrap();
|
||||
|
||||
#[cfg(feature="radio")]
|
||||
let (wifi, network_device, ble) = {
|
||||
info!("Configuring wifi");
|
||||
@@ -211,9 +186,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
let core2_main = |spawner: Spawner| {
|
||||
info!("Starting application tasks");
|
||||
|
||||
static PREDICTIONS: StaticCell<PubSubChannel<NoopRawMutex, Prediction, 15, 6, 1>> = StaticCell::new();
|
||||
let predictions = PREDICTIONS.init(PubSubChannel::new());
|
||||
let predictions = PREDICTIONS.take();
|
||||
|
||||
#[cfg(not(feature="demo"))]
|
||||
{
|
||||
@@ -251,24 +224,72 @@ async fn main(spawner: Spawner) {
|
||||
info!("Starting connectivity task");
|
||||
spawner.must_spawn(renderbug_bike::tasks::wifi::wifi_connect_task(wifi, motion_bus.dyn_sender()));
|
||||
|
||||
info!("Starting location sampler");
|
||||
static SAMPLER: ConstStaticCell<Watch<NoopRawMutex, Prediction, 1>> = ConstStaticCell::new(Watch::new());
|
||||
let sampler = SAMPLER.take();
|
||||
spawner.must_spawn(renderbug_bike::tasks::wifi::location_sampler(predictions.dyn_subscriber().unwrap(), sampler.dyn_sender()));
|
||||
|
||||
info!("Launching HTTP telemetry");
|
||||
spawner.must_spawn(renderbug_bike::tasks::wifi::http_telemetry_task(predictions.dyn_subscriber().unwrap(), stack, motion_bus.dyn_sender()));
|
||||
spawner.must_spawn(renderbug_bike::tasks::wifi::http_telemetry_task(sampler.dyn_receiver().unwrap(), stack, motion_bus.dyn_sender()));
|
||||
|
||||
info!("Starting BLE services");
|
||||
spawner.must_spawn(renderbug_bike::tasks::ble::ble_task(ble, predictions.dyn_subscriber().unwrap(), spawner));
|
||||
}
|
||||
|
||||
#[cfg(feature="dual-core")]
|
||||
spawner.must_spawn(print_sensor_status(predictions.dyn_subscriber().unwrap()));
|
||||
|
||||
let mut storage = SharedFlash::new(esp_storage::FlashStorage::new(peripherals.FLASH).multicore_auto_park());
|
||||
let mut partition_buf = [8; 1024];
|
||||
let partitions = esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut partition_buf).unwrap();
|
||||
|
||||
#[cfg(any(feature="flash-recording", feature="simulation"))]
|
||||
{
|
||||
info!("Launching core 2 watchdog");
|
||||
let timer1 = TimerGroup::new(peripherals.TIMG1);
|
||||
let mut ui_wdt = timer1.wdt;
|
||||
ui_wdt.set_timeout(esp_hal::timer::timg::MwdtStage::Stage0, esp_hal::time::Duration::from_secs(60));
|
||||
ui_wdt.enable();
|
||||
spawner.must_spawn(wdt_task(ui_wdt));
|
||||
use renderbug_bike::tasks::simulation::{SimDataStream, SimDataTable};
|
||||
let sim_partition = SimDataTable::find_partition(storage, partitions).expect("Could not find sim data partition!");
|
||||
info!("Got partition: {sim_partition:?}");
|
||||
let mut sim_table = match SimDataTable::open(sim_partition.clone()) {
|
||||
Ok(table) => table,
|
||||
Err(SimDataError::StreamIndexMissing) => {
|
||||
info!("Sim data partition not formatted, creating new stream table with {sim_partition:?}");
|
||||
SimDataTable::create(sim_partition).expect("Unable to create sim data stream table in partition!")
|
||||
},
|
||||
Err(e) => panic!("Error opening sim data stream table: {e:?}")
|
||||
};
|
||||
|
||||
loop {
|
||||
match sim_table.next() {
|
||||
Some((header, reader)) => {
|
||||
let srcid = header.id;
|
||||
info!("Found simulation data for {srcid:?} at {:#x}", reader.abs_start());
|
||||
|
||||
let stream = SimDataStream::open(reader, srcid);
|
||||
|
||||
if cfg!(feature="simulation") {
|
||||
if spawner.spawn(renderbug_bike::tasks::simulation::simulation_task(stream, motion_bus.dyn_sender())).is_err() {
|
||||
error!("Unable to spawn simulation task for {srcid:?}! Increase the task pool size.");
|
||||
}
|
||||
} else if cfg!(feature="flash-recording") && srcid == StreamType::Bundle {
|
||||
info!("Continuing recording stream");
|
||||
spawner.spawn(record_telemetry(recording_bus.dyn_subscriber().unwrap(), stream, motion_bus.dyn_sender())).unwrap();
|
||||
break;
|
||||
}
|
||||
},
|
||||
None if cfg!(feature="flash-recording") => {
|
||||
// If we already found a recording stream, we break; out of the loop above
|
||||
let reader = sim_table.append_new_stream(StreamType::Bundle).expect("Unable to create a new recording stream in the sim data partition! Is there enough free space?");
|
||||
warn!("Starting new recording stream at {:#x}", reader.abs_start());
|
||||
let recorder = SimDataStream::create(reader, StreamType::Bundle);
|
||||
spawner.spawn(record_telemetry(recording_bus.dyn_subscriber().unwrap(), recorder, motion_bus.dyn_sender())).unwrap();
|
||||
break;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spawner.must_spawn(print_sensor_status(predictions.dyn_subscriber().unwrap()));
|
||||
spawner.must_spawn(wdt_task(rtc, predictions.dyn_subscriber().unwrap(), oled_controls, display_controls));
|
||||
|
||||
//info!("Final memory stats: {}", esp_alloc::HEAP.stats());
|
||||
|
||||
info!("Ready to rock and roll in {}ms", Instant::now().as_millis());
|
||||
};
|
||||
@@ -316,9 +337,17 @@ async fn wdt_task(mut wdt: Wdt<esp_hal::peripherals::TIMG1<'static>>) {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn record_telemetry(firehose: DynamicReceiver<'static, Measurement>, mut storage: SimDataRecorder<StorageRange<SharedFlash<FlashStorage>>>) {
|
||||
async fn record_telemetry(mut firehose: DynSubscriber<'static, Measurement>, mut storage: SimDataStream<StorageRange<SharedFlash<FlashStorage<'static>>>>, motion: DynamicSender<'static, Measurement>) {
|
||||
let mut skipped_events = 0;
|
||||
while let Ok(Some((_, evt))) = storage.read_next() {
|
||||
trace!("Skipping event {evt:?}");
|
||||
skipped_events += 1;
|
||||
}
|
||||
info!("Skipped {} events to catch up to the end of the recording stream", skipped_events);
|
||||
motion.send(Measurement::SensorHardwareStatus(SensorSource::FlashRecording, SensorState::Online)).await;
|
||||
storage.write_next(AnnotationReading { buf: *b"Telemetry recording started " }).unwrap();
|
||||
loop {
|
||||
match firehose.receive().await {
|
||||
match firehose.next_message_pure().await {
|
||||
Measurement::IMU { accel, gyro } => {
|
||||
let reading = IMUReading {
|
||||
accel_x: accel.x as f64,
|
||||
@@ -328,24 +357,28 @@ async fn record_telemetry(firehose: DynamicReceiver<'static, Measurement>, mut s
|
||||
gyro_y: gyro.y as f64,
|
||||
gyro_z: gyro.z as f64
|
||||
};
|
||||
storage.write_next(reading).unwrap();
|
||||
info!("Wrote IMU to flash");
|
||||
//storage.write_next(reading).unwrap();
|
||||
trace!("Wrote IMU to flash");
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn print_sensor_readings(mut events: DynSubscriber<'static, Measurement>) {
|
||||
loop {
|
||||
match events.next_message_pure().await {
|
||||
Measurement::IMU { accel, gyro } => {
|
||||
esp_println::println!("accel=({},{},{}) gyro=({},{},{})", accel.x, accel.y, accel.z, gyro.x, gyro.y, gyro.z);
|
||||
},
|
||||
Measurement::GPS(gps) => {
|
||||
esp_println::println!("gps={gps:?}");
|
||||
Measurement::GPS(Some(pos)) => {
|
||||
storage.write_next(GPSReading {
|
||||
lat: pos.x,
|
||||
lon: pos.y,
|
||||
}).unwrap();
|
||||
trace!("Wrote GPS to flash");
|
||||
},
|
||||
Measurement::SensorHardwareStatus(sensor, status) => {
|
||||
let annotation = alloc::format!("{:?}={:?}", sensor, status);
|
||||
let mut buf = [0; 32];
|
||||
let bytes = annotation.as_bytes();
|
||||
let copy_len = bytes.len().min(buf.len());
|
||||
buf[..copy_len].copy_from_slice(&bytes[..copy_len]);
|
||||
if copy_len < buf.len() {
|
||||
buf[copy_len..].fill(b' ');
|
||||
}
|
||||
storage.write_next(AnnotationReading { buf }).unwrap();
|
||||
trace!("Wrote sensor status update to flash");
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
59
src/bin/playback.rs
Normal file
59
src/bin/playback.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::timer::systimer::SystemTimer;
|
||||
use log::*;
|
||||
use esp_backtrace as _;
|
||||
|
||||
use renderbug_bike::logging::RenderbugLogger;
|
||||
use renderbug_bike::tasks::simulation::{SimDataStream, SimDataTable};
|
||||
use renderbug_bike::simdata::*;
|
||||
|
||||
esp_bootloader_esp_idf::esp_app_desc!();
|
||||
|
||||
#[esp_rtos::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
|
||||
esp_alloc::heap_allocator!(size: 100000);
|
||||
|
||||
RenderbugLogger::init_logger();
|
||||
|
||||
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||
let peripherals = esp_hal::init(config);
|
||||
let sys_timer = SystemTimer::new(peripherals.SYSTIMER);
|
||||
esp_rtos::start(sys_timer.alarm0);
|
||||
|
||||
let mut storage = renderbug_bike::storage::SharedFlash::new(esp_storage::FlashStorage::new(peripherals.FLASH).multicore_auto_park());
|
||||
let mut partition_buf = [8; 1024];
|
||||
let partitions = esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut partition_buf).unwrap();
|
||||
|
||||
let sim_partition = SimDataTable::find_partition(storage, partitions).expect("Could not find sim data partition!");
|
||||
info!("Got partition: {sim_partition:?}");
|
||||
let sim_table = SimDataTable::open(sim_partition).expect("Sim data partition not found");
|
||||
|
||||
for (header, reader) in sim_table {
|
||||
info!("Found stream {header:?}");
|
||||
if header.id == StreamType::Bundle {
|
||||
let mut stream = SimDataStream::open(reader, header.id);
|
||||
let mut timestamp = 0;
|
||||
loop {
|
||||
match stream.read_next() {
|
||||
Ok(Some((timecode, next_evt))) => {
|
||||
timestamp += timecode.as_millis();
|
||||
esp_println::println!("{timestamp} {next_evt:?}");
|
||||
},
|
||||
Ok(None) => {
|
||||
warn!("End of simulation data stream");
|
||||
break
|
||||
},
|
||||
Err(err) => {
|
||||
warn!("Error during sensor stream: {err:?}");
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/bin/reset.rs
Normal file
36
src/bin/reset.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::timer::systimer::SystemTimer;
|
||||
use log::*;
|
||||
use esp_backtrace as _;
|
||||
|
||||
use renderbug_bike::logging::RenderbugLogger;
|
||||
use renderbug_bike::tasks::simulation::{SimDataStream, SimDataTable};
|
||||
use renderbug_bike::simdata::*;
|
||||
|
||||
esp_bootloader_esp_idf::esp_app_desc!();
|
||||
|
||||
#[esp_rtos::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
|
||||
esp_alloc::heap_allocator!(size: 100000);
|
||||
|
||||
RenderbugLogger::init_logger();
|
||||
|
||||
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
||||
let peripherals = esp_hal::init(config);
|
||||
let sys_timer = SystemTimer::new(peripherals.SYSTIMER);
|
||||
esp_rtos::start(sys_timer.alarm0);
|
||||
|
||||
let mut storage = renderbug_bike::storage::SharedFlash::new(esp_storage::FlashStorage::new(peripherals.FLASH));
|
||||
let mut partition_buf = [8; 1024];
|
||||
let partitions = esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut partition_buf).unwrap();
|
||||
|
||||
let sim_partition = SimDataTable::find_partition(storage, partitions).expect("Could not find sim data partition!");
|
||||
info!("Got partition: {sim_partition:?}");
|
||||
SimDataTable::create(sim_partition).expect("Could not write empty sim partition");
|
||||
error!("Overwrote sim data partition with a blank stream table");
|
||||
}
|
||||
Reference in New Issue
Block a user