adds initial rcs implementation
This commit is contained in:
@@ -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 }),
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user