use defmt::{bitflags, Format};
pub use ux::u7;
use crate::{make_u32, util::make_u16};
use core::ops::Shr;
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct NegiconFrame {
pub origin: u16,
pub destination: u16,
pub message_type: NegiconMessageType,
reserved: u8,
pub message_data: [u8; 8],
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum NegiconMessageType {
Nop = 0,
Ping = 1,
ModuleEventShort = 2,
ModuleEventLong = 3,
ModuleEventDouble = 4,
}
impl NegiconMessageType {
fn from_u8(value: u8) -> Result<Self, InvalidMessage> {
match value {
0 => Ok(NegiconMessageType::Nop),
1 => Ok(NegiconMessageType::Ping),
2 => Ok(NegiconMessageType::ModuleEventLong),
3 => Ok(NegiconMessageType::ModuleEventDouble),
_ => Err(InvalidMessage::InvalidMessageType),
}
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum NegiconModuleType {
Invalid = 0,
Router,
Buttons,
SmoothEncoder,
DetentEncoder,
ClickWheel,
DigitalPaddle,
AnalogPaddle,
}
impl NegiconModuleType {
fn from_u8(value: u8) -> Self {
match value {
0 => NegiconModuleType::Router,
1 => NegiconModuleType::Buttons,
2 => NegiconModuleType::SmoothEncoder,
3 => NegiconModuleType::DetentEncoder,
4 => NegiconModuleType::ClickWheel,
5 => NegiconModuleType::DigitalPaddle,
6 => NegiconModuleType::AnalogPaddle,
_ => NegiconModuleType::Invalid,
}
}
}
#[derive(PartialEq, Clone, Copy, Debug, Format)]
pub enum InvalidMessage {
CrcError,
InvalidMessageType,
}
const CRC: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_3740);
fn crc(data: &[u8]) -> u16 {
CRC.checksum(data)
}
fn set_crc(data: &mut [u8]) {
let crc = crc(&data[2..]);
data[1] = crc as u8;
data[0] = (crc >> 8) as u8;
}
fn verify_crc(data: &[u8]) -> Result<(), InvalidMessage> {
let expected = make_u16(data[0], data[1]);
let actual = crc(&data[2..]);
if expected == actual {
Ok(())
} else {
Err(InvalidMessage::CrcError)
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NegiconPingMessage {
pub sequence: u8,
pub ttl: u8,
pub module_type: NegiconModuleType,
pub fw_version: u16,
}
impl NegiconPingMessage {
pub fn serialize(&self) -> [u8; 8] {
[
self.sequence,
self.ttl,
self.module_type as u8,
self.fw_version.shr(8) as u8,
self.fw_version as u8,
0u8,
0u8,
0u8,
]
}
pub fn deserialize(data: &[u8; 8]) -> Result<Self, InvalidMessage> {
Ok(NegiconPingMessage {
sequence: data[0],
ttl: data[1],
module_type: NegiconModuleType::from_u8(data[2]),
fw_version: make_u16(data[3], data[4]),
})
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NegiconModuleEventLongMessage {
pub sequence: u8,
pub sub_id: u8,
pub event_data: [u8; 6],
}
impl NegiconModuleEventLongMessage {
pub fn serialize(&self) -> [u8; 8] {
[
self.sequence,
self.sub_id,
self.event_data[0],
self.event_data[1],
self.event_data[2],
self.event_data[3],
self.event_data[4],
self.event_data[5],
]
}
pub fn deserialize(data: &[u8; 8]) -> Result<Self, InvalidMessage> {
Ok(NegiconModuleEventLongMessage {
sequence: data[0],
sub_id: data[1],
event_data: [data[2], data[3], data[4], data[5], data[6], data[7]],
})
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NegiconModuleEventShortMessage {
pub sequence: u8,
pub sub_id: u8,
pub value: u16,
}
impl NegiconModuleEventShortMessage {
pub fn new(sequence: u8, sub_id: u8, value: u16) -> Self {
Self {
sequence,
sub_id,
value,
}
}
pub fn serialize(&self) -> [u8; 4] {
[
self.sequence,
self.sub_id,
self.value as u8,
(self.value >> 8) as u8,
]
}
pub fn deserialize(data: &[u8; 4]) -> Self {
NegiconModuleEventShortMessage {
sequence: data[0],
sub_id: data[1],
value: make_u16(data[3], data[2]),
}
}
pub fn deserialize_double(data: &[u8; 8]) -> (Self, Self) {
let first =
NegiconModuleEventShortMessage::deserialize(&[data[0], data[1], data[2], data[3]]);
let second =
NegiconModuleEventShortMessage::deserialize(&[data[4], data[5], data[6], data[7]]);
(first, second)
}
pub fn serialize_double(first: &Self, second: &Self) -> [u8; 8] {
let first_data = first.serialize();
let second_data = second.serialize();
[
first_data[0],
first_data[1],
first_data[2],
first_data[3],
second_data[0],
second_data[1],
second_data[2],
second_data[3],
]
}
}
impl NegiconFrame {
pub fn new(
origin: u16,
destination: u16,
message_type: NegiconMessageType,
message_data: [u8; 8],
) -> Self {
NegiconFrame {
origin,
destination,
message_type,
reserved: 0,
message_data,
}
}
pub fn ping(id: u16, module_type: NegiconModuleType, sequence: u8, fw_version: u16) -> Self {
let message = NegiconPingMessage {
sequence,
ttl: 8,
module_type,
fw_version,
};
let message_data = message.serialize();
NegiconFrame::new(id, 0, NegiconMessageType::Ping, message_data)
}
pub fn nop() -> Self {
NegiconFrame {
origin: 0,
destination: 0,
message_type: NegiconMessageType::Nop,
reserved: 0,
message_data: [0; 8],
}
}
pub fn serialize(&self) -> [u8; 16] {
let mut data = [
0u8,
0u8,
self.origin as u8,
(self.origin >> 8) as u8,
self.destination as u8,
(self.destination >> 8) as u8,
self.message_type as u8,
0u8,
self.message_data[0],
self.message_data[1],
self.message_data[2],
self.message_data[3],
self.message_data[4],
self.message_data[5],
self.message_data[6],
self.message_data[7],
];
set_crc(&mut data);
data
}
pub fn is_ping(&self) -> bool {
self.message_type == NegiconMessageType::Ping
}
pub fn is_nop(&self) -> bool {
self.message_type == NegiconMessageType::Nop
}
pub fn serialize_u16(&self) -> [u16; 4] {
let bytes = self.serialize();
[
make_u16(bytes[0], bytes[1]),
make_u16(bytes[2], bytes[3]),
make_u16(bytes[4], bytes[5]),
make_u16(bytes[6], bytes[7]),
]
}
pub fn serialize_u32(&self) -> [u32; 2] {
let bytes = self.serialize();
[
make_u32(bytes[0], bytes[1], bytes[2], bytes[3]),
make_u32(bytes[4], bytes[5], bytes[6], bytes[7]),
]
}
pub fn deserialize(data: &[u8; 16]) -> Result<Self, InvalidMessage> {
verify_crc(data)?;
Ok(NegiconFrame {
origin: make_u16(data[2], data[3]),
destination: make_u16(data[4], data[5]),
message_type: NegiconMessageType::from_u8(data[6])?,
reserved: data[7],
message_data: [
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
],
})
}
}