use std::collections::BTreeMap;
use std::fmt;
use crate::notifications::*;
use crate::IoTypeId;
type ModeId = u8;
#[derive(Debug, Default, Clone)]
pub struct Definition {
kind: IoTypeId,
port: u8,
capabilities: Vec<Capability>,
mode_count: u8,
modes: std::collections::BTreeMap<ModeId, PortMode>,
valid_combos: Vec<Vec<u8>>,
}
impl fmt::Display for Definition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:#?} on port {} ({:#x}) with {} modes: {:#?}",
self.kind,
self.port,
self.port,
self.mode_count,
self.modes
.values()
.map(|mode| &mode.name[..])
.collect::<Vec<_>>()
)
}
}
impl Definition {
pub fn kind(&self) -> &IoTypeId {
&self.kind
}
pub fn port(&self) -> u8 {
self.port
}
pub fn capabilities(&self) -> &Vec<Capability> {
&self.capabilities
}
pub fn mode_count(&self) -> &u8 {
&self.mode_count
}
pub fn modes(&self) -> &BTreeMap<ModeId, PortMode> {
&self.modes
}
pub fn valid_combos(&self) -> &Vec<Vec<u8>> {
&self.valid_combos
}
pub fn new(kind: IoTypeId, port: u8) -> Self {
Self {
kind,
port,
mode_count: Default::default(),
capabilities: Default::default(),
valid_combos: Default::default(),
modes: Default::default(),
}
}
pub fn set_mode_count(&mut self, mode_count: u8) {
self.mode_count = mode_count;
}
pub fn set_modes(&mut self, input_modes: u16, output_modes: u16) {
let mut r: BTreeMap<ModeId, PortMode> = BTreeMap::new();
for mode in 0..15 {
if (input_modes >> mode as u16) & 1 == 1 {
r.insert(mode as u8, PortMode::new(ModeKind::Sensor));
}
}
for mode in 0..15 {
if (output_modes >> mode as u16) & 1 == 1 {
r.insert(mode as u8, PortMode::new(ModeKind::Output));
}
}
while r.len() < self.mode_count as usize {
let mut empty_key = 0;
while r.contains_key(&empty_key) {
empty_key += 1
}
r.insert(empty_key, PortMode::new(ModeKind::Hidden));
}
self.modes = r;
}
pub fn set_capabilities(&mut self, capabilities: u8) {
let mut r: Vec<Capability> = Vec::new();
if (capabilities >> 3) & 1 == 1 {
r.push(Capability::LogicalSynchronizable)
}
if (capabilities >> 2) & 1 == 1 {
r.push(Capability::LogicalCombinable)
}
if (capabilities >> 1) & 1 == 1 {
r.push(Capability::ProvideData)
}
if capabilities & 1 == 1 {
r.push(Capability::AcceptData)
}
self.capabilities = r;
}
pub fn set_valid_combos(&mut self, valid: Vec<u8>) {
for combo in valid {
let mut v: Vec<u8> = Vec::new();
for mode in 0..7 {
if (combo >> mode as u8) & 1 == 1 {
v.push(mode as u8);
}
}
self.valid_combos.push(v);
}
self.valid_combos.pop(); }
pub fn set_mode_name(&mut self, mode_id: u8, chars_as_bytes: Vec<u8>) {
let mut truncated: Vec<u8> = Vec::new();
for c in chars_as_bytes {
if c == 0 {
break;
} else {
truncated.push(c)
}
}
let name = String::from_utf8(truncated).expect("Found invalid UTF-8");
let mode = self.modes.get_mut(&mode_id);
match mode {
Some(m) => m.name = name,
None => {
error!(
"Found name without matching mode. Port:{} Mode:{} Name:{}",
self.port, &mode_id, &name
);
println!(
"Found name without matching mode. Port:{} Mode:{} Name:{}",
self.port, &mode_id, &name
);
}
}
}
pub fn set_mode_raw(&mut self, mode_id: u8, min: f32, max: f32) {
self.modes.get_mut(&mode_id).unwrap().raw = (min, max);
}
pub fn set_mode_pct(&mut self, mode_id: u8, min: f32, max: f32) {
self.modes.get_mut(&mode_id).unwrap().pct = (min, max);
}
pub fn set_mode_si(&mut self, mode_id: u8, min: f32, max: f32) {
self.modes.get_mut(&mode_id).unwrap().si = (min, max);
}
pub fn set_mode_symbol(&mut self, mode_id: u8, chars_as_bytes: Vec<u8>) {
let mut truncated: Vec<u8> = Vec::new();
for c in chars_as_bytes {
if c == 0 {
break;
} else {
truncated.push(c)
}
}
let symbol = String::from_utf8(truncated).expect("Found invalid UTF-8");
let mode = self.modes.get_mut(&mode_id);
match mode {
Some(m) => m.symbol = symbol,
None => {
error!("Found symbol without matching mode. Port:{} Mode:{} Symbol:{}", self.port, &mode_id, &symbol);
println!("Found symbol without matching mode. Port:{} Mode:{} Symbol:{}", self.port, &mode_id, &symbol);
}
}
}
pub fn set_mode_mapping(
&mut self,
mode_id: u8,
input: MappingValue,
output: MappingValue,
) {
let mode = self.modes.get_mut(&mode_id).unwrap();
let mut r: Vec<Mapping> = Vec::new();
if (input.0 >> 7) & 1 == 1 {
r.push(Mapping::SupportsNull)
}
if (input.0 >> 6) & 1 == 1 {
r.push(Mapping::SupportsFunctional)
}
if (input.0 >> 4) & 1 == 1 {
r.push(Mapping::Absolute)
}
if (input.0 >> 3) & 1 == 1 {
r.push(Mapping::Relative)
}
if (input.0 >> 2) & 1 == 1 {
r.push(Mapping::Discrete)
}
mode.input_mapping = r;
let mut r: Vec<Mapping> = Vec::new();
if (output.0 >> 7) & 1 == 1 {
r.push(Mapping::SupportsNull)
}
if (output.0 >> 6) & 1 == 1 {
r.push(Mapping::SupportsFunctional)
}
if (output.0 >> 4) & 1 == 1 {
r.push(Mapping::Absolute)
}
if (output.0 >> 3) & 1 == 1 {
r.push(Mapping::Relative)
}
if (output.0 >> 2) & 1 == 1 {
r.push(Mapping::Discrete)
}
mode.output_mapping = r;
}
pub fn set_mode_valueformat(
&mut self,
mode_id: u8,
format: ValueFormatType,
) {
self.modes.get_mut(&mode_id).unwrap().value_format = format;
}
pub fn set_mode_motor_bias(&mut self, mode_id: u8, bias: u8) {
self.modes.get_mut(&mode_id).unwrap().motor_bias = bias;
}
}
#[derive(Debug, Default, Clone)]
pub struct PortMode {
pub kind: ModeKind,
pub name: String, pub raw: (f32, f32), pub pct: (f32, f32), pub si: (f32, f32), pub symbol: String, pub input_mapping: Vec<Mapping>, pub output_mapping: Vec<Mapping>,
pub motor_bias: u8, pub value_format: ValueFormatType,
}
impl fmt::Display for PortMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:<10?} {:<10} {:<10} {:}",
self.kind, self.name, self.symbol, self.value_format
)
}
}
impl PortMode {
pub fn new(mode_kind: ModeKind) -> Self {
Self {
kind: mode_kind,
name: Default::default(),
raw: Default::default(),
pct: Default::default(),
si: Default::default(),
symbol: Default::default(),
input_mapping: Default::default(),
output_mapping: Default::default(),
motor_bias: Default::default(),
value_format: Default::default(),
}
}
pub fn name(&self) -> &str {
&self.name
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
pub enum ModeKind {
#[default]
Unknown,
Sensor,
Output,
Hidden,
}
#[derive(Debug, Default, Copy, Clone)]
pub enum Capability {
#[default]
None,
LogicalSynchronizable = 0b1000,
LogicalCombinable = 0b0100,
ProvideData = 0b0010, AcceptData = 0b0001, }
#[derive(Debug, Default, Copy, Clone)]
pub enum Mapping {
#[default]
Unknown,
SupportsNull = 0b1000_0000,
SupportsFunctional = 0b0100_0000,
Absolute = 0b0001_0000, Relative = 0b0000_1000, Discrete = 0b0000_0100, }