#![no_std]
extern crate heapless;
use embedded_shadow::prelude::*;
use heapless::Vec;
struct MotorControllerPolicy {
calibration_unlocked: bool,
}
impl MotorControllerPolicy {
fn new() -> Self {
Self {
calibration_unlocked: false,
}
}
fn unlock_calibration(&mut self) {
self.calibration_unlocked = true;
}
}
impl AccessPolicy for MotorControllerPolicy {
fn can_read(&self, _addr: u16, _len: usize) -> bool {
true }
fn can_write(&self, addr: u16, len: usize) -> bool {
let end = addr.saturating_add(len as u16);
match addr {
0x0000..=0x00FF => false,
0x0100..=0x01FF => self.calibration_unlocked && end <= 0x0200,
0x0200..=0x02FF => end <= 0x0300,
0x0300..=0x03FF => end <= 0x0400,
0x0400..=0x07FF => end <= 0x0800,
_ => false,
}
}
}
struct MotorPersistPolicy;
impl PersistPolicy<PersistKey> for MotorPersistPolicy {
fn push_persist_keys_for_range<F>(&self, addr: u16, len: usize, mut push_key: F) -> bool
where
F: FnMut(PersistKey),
{
let end = addr.saturating_add(len as u16);
let mut needs_persist = false;
if addr < 0x0200 && end > 0x0100 {
push_key(PersistKey::Calibration);
needs_persist = true;
}
if addr < 0x0300 && end > 0x0200 {
push_key(PersistKey::UserConfig);
needs_persist = true;
}
needs_persist
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
enum PersistKey {
Calibration,
UserConfig,
}
struct SmartPersistTrigger {
pending: Vec<PersistKey, 4>,
calibration_write_count: u32,
config_write_count: u32,
}
impl SmartPersistTrigger {
fn new() -> Self {
Self {
pending: Vec::new(),
calibration_write_count: 0,
config_write_count: 0,
}
}
}
impl PersistTrigger<PersistKey> for SmartPersistTrigger {
fn push_key(&mut self, key: PersistKey) {
if !self.pending.contains(&key) {
let _ = self.pending.push(key);
}
}
fn request_persist(&mut self) {
for key in self.pending.iter() {
match key {
PersistKey::Calibration => {
self.calibration_write_count += 1;
}
PersistKey::UserConfig => {
self.config_write_count += 1;
if self.config_write_count % 10 == 0 {
}
}
}
}
self.pending.clear();
}
}
struct MotorController {
speed_setpoint: u16,
current_speed: u16,
temperature: i16,
error_count: u32,
}
pub fn main() {
let mut access_policy = MotorControllerPolicy::new();
let storage = ShadowStorageBuilder::new()
.total_size::<2048>() .block_size::<64>() .block_count::<32>() .access_policy(MotorControllerPolicy::new())
.persist_policy(MotorPersistPolicy)
.persist_trigger(SmartPersistTrigger::new())
.build();
let staging_buffer = PatchStagingBuffer::<256, 16>::new();
let staged_storage = storage.with_staging(staging_buffer);
let host = staged_storage.host_shadow();
let kernel = staged_storage.kernel_shadow();
host.with_view(|view| {
let default_config = [
0x01, 0x00, 0x64, 0x00, 0x32, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, ];
view.write_range(0x200, &default_config).unwrap();
view.write_range(0x300, &[0x00; 16]).unwrap(); });
let mut controller = MotorController {
speed_setpoint: 0,
current_speed: 0,
temperature: 25,
error_count: 0,
};
host.with_view(|view| {
view.write_range_staged(0x206, &[0x00, 0x03]).unwrap(); view.write_range_staged(0x208, &[0x00, 0x04]).unwrap(); view.write_range_staged(0x20A, &[0x00, 0x02]).unwrap();
let mut p_value = [0u8; 2];
view.read_range_overlay(0x206, &mut p_value).unwrap();
let p = u16::from_le_bytes(p_value);
if p <= 10 {
view.commit().unwrap();
}
});
for cycle in 0..10 {
host.with_view(|view| {
controller.speed_setpoint = 100 + cycle * 10;
let setpoint_bytes = controller.speed_setpoint.to_le_bytes();
view.write_range(0x300, &setpoint_bytes).unwrap();
let telemetry_offset = 0x400 + cycle * 8;
let telemetry = [
controller.current_speed.to_le_bytes()[0],
controller.current_speed.to_le_bytes()[1],
controller.temperature.to_le_bytes()[0],
controller.temperature.to_le_bytes()[1],
controller.error_count.to_le_bytes()[0],
controller.error_count.to_le_bytes()[1],
controller.error_count.to_le_bytes()[2],
controller.error_count.to_le_bytes()[3],
];
view.write_range(telemetry_offset, &telemetry).unwrap();
});
kernel.with_view(|view| {
if view.is_dirty(0x300, 16).unwrap() {
view.for_each_dirty_block(|addr, data| {
if addr == 0x300 {
let _ = data;
}
Ok(())
})
.unwrap();
view.clear_dirty();
}
});
controller.current_speed =
controller.current_speed * 9 / 10 + controller.speed_setpoint / 10;
controller.temperature += 1;
}
access_policy.unlock_calibration();
let storage_unlocked = ShadowStorageBuilder::new()
.total_size::<2048>()
.block_size::<64>()
.block_count::<32>()
.access_policy(access_policy)
.persist_policy(MotorPersistPolicy)
.persist_trigger(SmartPersistTrigger::new())
.build();
let host_unlocked = storage_unlocked.host_shadow();
host_unlocked.with_view(|view| {
let calibration = [
0xFF, 0x03, 0x20, 0x00, 0x10, 0x00, ];
view.write_range(0x100, &calibration).unwrap();
});
}
#[cfg(test)]
mod tests {
#[test]
fn test_complex_example() {
super::main();
}
}