adds initial rcs implementation

This commit is contained in:
2026-01-05 20:26:54 -05:00
parent 252db5993d
commit 98541737a1
23 changed files with 1490 additions and 229 deletions

View File

@@ -46,12 +46,12 @@ pub enum PinoutChannel {
ExtB(u8),
}
pub struct DevicePin<'a, Device: PinDevice> {
pub struct DevicePin<Device: PinDevice> {
pin: u8,
device: &'a Device,
device: Device,
}
impl<Device: PinDevice> Pin for DevicePin<'_, Device> {
impl<Device: PinDevice> Pin for DevicePin<Device> {
fn set(&mut self, value: PinState, valid_until: Instant, priority: u8) {
trace!(
"ChannelPin<Device={}>::set(self, value: {value:?}, valid_until: {valid_until:?}, priority: {priority})",
@@ -61,12 +61,12 @@ impl<Device: PinDevice> Pin for DevicePin<'_, Device> {
}
}
pub enum ChannelPin<'a, A: PinDevice, B: PinDevice> {
ExtA(DevicePin<'a, A>),
ExtB(DevicePin<'a, B>),
pub enum ChannelPin<A: PinDevice, B: PinDevice> {
ExtA(DevicePin<A>),
ExtB(DevicePin<B>),
}
impl<A: PinDevice, B: PinDevice> Pin for ChannelPin<'_, A, B> {
impl<A: PinDevice, B: PinDevice> Pin for ChannelPin<A, B> {
fn set(&mut self, value: PinState, valid_until: Instant, priority: u8) {
trace!(
"ChannelPin<A={}, B={}>::set(self, value: {value:?}, valid_until: {valid_until:?}, priority: {priority})",
@@ -81,11 +81,11 @@ impl<A: PinDevice, B: PinDevice> Pin for ChannelPin<'_, A, B> {
}
impl PinoutChannel {
pub fn get_pin<'a>(
self,
ext_a: &'a (impl PinDevice + Debug),
ext_b: &'a (impl PinDevice + Debug),
) -> impl Pin {
pub fn get_pin<A, B>(self, ext_a: A, ext_b: B) -> ChannelPin<A, B>
where
A: PinDevice + Debug,
B: PinDevice + Debug,
{
trace!("PinoutChannel::get_pin(self: {self:?}, ext_a: {ext_a:?}, ext_b: {ext_b:?}");
match self {
PinoutChannel::ExtA(pin) => ChannelPin::ExtA(DevicePin { pin, device: ext_a }),

View File

@@ -1,9 +1,11 @@
use crate::commanded_state::CommandedState;
use crate::hardware::mcp23017::Mcp23017;
use crate::hardware::pin::PinDevice;
use crate::scheduler::{CyclicTask, TaskHandle};
use crate::state_vector::{SectionIdentifier, SectionWriter, StateVector};
use embedded_hal::digital::PinState;
use log::trace;
use std::array;
use std::fmt::{Debug, Formatter};
use std::sync::mpsc::Receiver;
use std::time::Instant;
@@ -20,7 +22,9 @@ pub enum Mcp23017Message {
impl<D: Debug> PinDevice for TaskHandle<Mcp23017Message, D> {
fn set_pin(&self, pin: u8, value: PinState, valid_until: Instant, priority: u8) {
trace!("Mcp23017Task::set_pin(self: {self:?}, pin: {pin}, value: {value:?})");
trace!(
"TaskHandle<Mcp23017Message, D>::set_pin(self: {self:?}, pin: {pin}, value: {value:?}, valid_until: {valid_until:?}, priority: {priority})"
);
// This can only fail if the other end is disconnected - which we intentionally want to
// ignore
let _ = self.sender.send(Mcp23017Message::SetPin {
@@ -68,107 +72,12 @@ impl AllPins {
fn new() -> Self {
trace!("AllPins::new()");
Self {
pins: [PinData::new(); _],
pins: array::repeat(PinData::new(PinState::Low)),
}
}
}
#[derive(Copy, Clone, Debug)]
struct PinData {
state: PinState,
valid_until: Option<Instant>,
priority: u8,
next_state: PinState,
next_validity: Option<Instant>,
next_priority: u8,
default: PinState,
changed: bool,
value: PinState,
}
impl PinData {
fn new() -> Self {
trace!("PinData::new()");
Self {
state: PinState::Low,
valid_until: None,
priority: 0,
next_state: PinState::Low,
next_validity: None,
next_priority: 0,
default: PinState::Low,
changed: false,
value: PinState::Low,
}
}
fn evaluate(&mut self, now: Instant) {
trace!("PinData::evaluate(self: {self:?}, now: {now:?})");
// Do this twice to check both the current and the current next
// If the current is currently invalid, we'd upgrade the next to current
for _ in 0..2 {
let is_current_valid = self.valid_until.is_some_and(|current| current >= now);
if is_current_valid {
self.value = self.state;
return;
}
if self.valid_until.is_some() {
self.changed = true;
}
self.state = self.next_state;
self.valid_until = self.next_validity;
self.priority = self.next_priority;
self.next_validity = None;
self.next_priority = 0;
}
self.value = self.default;
}
fn set(&mut self, value: PinState, valid_until: Instant, priority: u8) {
trace!(
"PinData::set(self: {self:?}, value: {value:?}, valid_until: {valid_until:?}, priority: {priority})"
);
let can_replace_current = self
.valid_until
.is_none_or(|current| current <= valid_until)
|| self.priority == priority;
let can_replace_next = self.next_validity.is_none_or(|next| next <= valid_until)
|| self.next_priority == priority;
if priority >= self.priority {
// This is now the highest priority thing (or most recent of equal priority)
if can_replace_current {
if can_replace_next {
self.next_validity = None;
self.next_priority = 0;
}
} else {
self.next_state = self.state;
self.next_validity = self.valid_until;
self.next_priority = self.priority;
}
self.state = value;
self.valid_until = Some(valid_until);
self.priority = priority;
self.changed = true;
self.value = value;
} else {
// This is not the highest priority thing
if self.priority >= self.next_priority {
// Higher priority than the next highest though
self.next_state = value;
self.next_validity = Some(valid_until);
self.next_priority = priority;
self.changed = true;
} else {
// Not high enough priority to remember
}
}
}
}
type PinData = CommandedState<PinState>;
impl<'a, M: Mcp23017 + Debug> Mcp23017Task<'a, M> {
pub fn new(mcp23017: M, state_vector: &'a StateVector) -> Self {
@@ -209,7 +118,7 @@ impl<M: Mcp23017 + Debug> CyclicTask for Mcp23017Task<'_, M> {
priority,
} => {
if (0u8..16u8).contains(&pin) {
self.pins.pins[pin as usize].set(value, valid_until, priority);
self.pins.pins[pin as usize].insert(value, valid_until, priority);
}
}
}
@@ -217,9 +126,8 @@ impl<M: Mcp23017 + Debug> CyclicTask for Mcp23017Task<'_, M> {
for pin in 0u8..16u8 {
let current_pin = &mut self.pins.pins[pin as usize];
let state = current_pin.value;
if current_pin.changed {
current_pin.changed = false;
let state = **current_pin;
if current_pin.consume_changed() {
// This shouldn't be able to fail
// TODO: handle error case
let _ = self.mcp23017.set_pin(pin, state);
@@ -229,7 +137,7 @@ impl<M: Mcp23017 + Debug> CyclicTask for Mcp23017Task<'_, M> {
if changed {
let _ = self.mcp23017.flush();
self.state.update(|s| {
s.pins = self.pins.pins.map(|pin| pin.value == PinState::High);
s.pins = array::from_fn(|i| *self.pins.pins[i] == PinState::High);
});
}
}

View File

@@ -1,5 +1,6 @@
use embedded_hal::digital::PinState;
use nautilus_common::command::{SetPin, ValidPriorityCommand};
use nautilus_common::command::set_pin::SetPin;
use nautilus_common::command::valid_priority_command::ValidPriorityCommand;
use std::time::Instant;
pub trait PinDevice {