micodus_server/src/parser/mod.rs
2024-12-27 10:58:04 +01:00

394 lines
12 KiB
Rust

pub mod body;
pub mod error;
use body::*;
use error::*;
use std::collections::VecDeque;
use bcd_convert::BcdNumber;
use rand::prelude::*;
const FLAGDELIMITER: u8 = 0x7E;
#[allow(dead_code)]
const PROPS_SIZE_MASK: u16 = 0x01FF;
#[allow(dead_code)]
const PROPS_SUBCONTRACT_MASK: u16 = 0x3000;
#[allow(dead_code)]
const PROPS_RESERVED_MASK: u16 = 0xC000;
#[allow(dead_code)]
const PROPS_DATAENCRYPTION_MASK: u16 = 0x0E00;
pub fn parse_inbound_msg(rawdata: &mut DataWrapper) -> std::result::Result<Message, MessageError> {
let mut msg: Message = Message::default();
match msg.parse_header(rawdata) {
Ok(_) => {
msg.check(rawdata);
}
Err(e) => {
println!("error parsing header {e}");
return Err(MessageError);
}
};
Ok(msg)
}
#[derive(Default, Debug)]
pub struct DataWrapper {
pub data: VecDeque<u8>,
pub count: usize,
}
impl DataWrapper {
pub fn new(data: Vec<u8>) -> DataWrapper {
DataWrapper {
data: data.into(),
count: 0,
}
}
}
impl Iterator for DataWrapper {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
let res: Option<u8>;
if self.count < 6 {
res = self.data.pop_front()
} else {
res = None
}
self.count += 1;
res
}
}
#[derive(Default, Debug)]
pub struct Message {
pub header: MessageHeader,
pub content: MessageType,
pub body: Vec<u8>,
pub checksum: u8,
valid: bool,
}
impl std::fmt::Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Message: (header: {}), content: {}, checksum: {}, valid: {}",
self.header, self.content, self.checksum, self.valid
)
}
}
impl Message {
pub fn parse_header(
&mut self,
rawdata: &mut DataWrapper,
) -> std::result::Result<(), NotOurProtocolError> {
let mut data = rawdata.data.clone().into_iter();
let first_byte = data.next().unwrap();
if first_byte != FLAGDELIMITER {
return Err(NotOurProtocolError);
};
let mut tmpid = vec![];
tmpid.push(data.next().unwrap());
tmpid.push(data.next().unwrap());
self.header.id = u16::from_be_bytes(tmpid.try_into().unwrap());
//self.header.id = ((data.next().unwrap() as u16) << 8) + data.next().unwrap() as u16;
self.header.properties = ((data.next().unwrap() as u16) << 8) + data.next().unwrap() as u16;
self.parse_properties();
for i in 0..self.header.raw_terminal_id.len() {
self.header.raw_terminal_id[i] = data.next().unwrap();
}
self.parse_terminal_id();
self.header.serial_number =
((data.next().unwrap() as u16) << 8) + data.next().unwrap() as u16;
for _ in 0..self.header.bodylength as usize {
self.body.push(data.next().unwrap());
}
self.checksum = data.next().unwrap();
if data.next().unwrap() != FLAGDELIMITER {
return Err(NotOurProtocolError);
}
self.parse_body();
Ok(())
}
pub fn parse_properties(&mut self) {
self.header.bodylength = (self.header.properties & PROPS_SIZE_MASK) as u8;
self.header.encryption =
((self.header.properties & PROPS_DATAENCRYPTION_MASK) as u16 >> 10) as u8;
self.header.encrypted = self.header.encryption != 0;
self.header.subcontract =
((self.header.properties & PROPS_SUBCONTRACT_MASK) as u16 >> 13) == 1;
self.header.reserved = ((self.header.properties & PROPS_RESERVED_MASK) as u16 >> 14) as u16;
}
pub fn parse_terminal_id(&mut self) {
let code = BcdNumber::try_from(&self.header.raw_terminal_id as &[u8]).unwrap();
self.header.terminal_id = code.to_u64().unwrap();
}
pub fn check(&mut self, rawdata: &mut DataWrapper) {
let mut data = rawdata.data.iter();
data.next().unwrap();
let mut check: u8 = 0;
loop {
let b = data.next().unwrap();
if *b == FLAGDELIMITER {
break;
}
check = *b ^ check;
}
self.validate(check);
}
fn validate(&mut self, check: u8) {
self.valid = check == 0;
}
pub fn is_valid(&self) -> bool {
self.valid
}
pub fn parse_body(&mut self) {
match self.header.id {
TerminalUniversalResponse::ID => {
self.content = MessageType::TerminalUniversalResponse(
TerminalUniversalResponse::new(&self.body),
)
}
PlatformUniversalResponse::ID => {
self.content = MessageType::PlatformUniversalResponse(
PlatformUniversalResponse::new(&self.body),
)
}
TerminalHeartbeat::ID => {
self.content = MessageType::TerminalHeartbeat(TerminalHeartbeat::new(&self.body))
}
TerminalRegistration::ID => {
self.content =
MessageType::TerminalRegistration(TerminalRegistration::new(&self.body))
}
TerminalRegistrationReply::ID => {
self.content = MessageType::TerminalRegistrationReply(
TerminalRegistrationReply::new(&self.body),
)
}
TerminalLogout::ID => {
self.content = MessageType::TerminalLogout(TerminalLogout::new(&self.body))
}
TerminalAuthentication::ID => {
self.content =
MessageType::TerminalAuthentication(TerminalAuthentication::new(&self.body))
}
TerminalParameterSetting::ID => {
self.content =
MessageType::TerminalParameterSetting(TerminalParameterSetting::new(&self.body))
}
QueryTerminalParameter::ID => {
self.content =
MessageType::QueryTerminalParameter(QueryTerminalParameter::new(&self.body))
}
QueryTerminalParameterResponse::ID => {
self.content = MessageType::QueryTerminalParameterResponse(
QueryTerminalParameterResponse::new(&self.body),
)
}
TerminalControl::ID => {
self.content = MessageType::TerminalControl(TerminalControl::new(&self.body))
}
LocationInformationReport::ID => {
self.content = MessageType::LocationInformationReport(
LocationInformationReport::new(&self.body),
)
}
StartOfTrip::ID => {
self.content = MessageType::StartOfTrip(StartOfTrip::new(&self.body))
}
EndOfTrip::ID => self.content = MessageType::EndOfTrip(EndOfTrip::new(&self.body)),
_ => {
self.content = MessageType::TerminalUniversalResponse(
TerminalUniversalResponse::new(&self.body),
)
}
}
}
pub fn set_reply(inmsg: Message) -> Option<Message> {
let mut reply: Message = Message::default();
let mut rng = rand::thread_rng();
match inmsg.content {
MessageType::TerminalRegistration(t) => {
let cnt = t.generate_reply(
inmsg.header.raw_terminal_id.into(),
inmsg.header.serial_number,
);
reply.header.id = TerminalRegistrationReply::ID;
reply.header.properties = cnt.to_raw().len() as u16;
reply.header.raw_terminal_id = inmsg.header.raw_terminal_id;
reply.header.serial_number = rng.gen();
reply.content = MessageType::TerminalRegistrationReply(cnt);
}
MessageType::TerminalAuthentication(t) => {
let cnt = t.generate_reply(TerminalAuthentication::ID, inmsg.header.serial_number);
reply.header.id = PlatformUniversalResponse::ID;
reply.header.raw_terminal_id = inmsg.header.raw_terminal_id;
reply.header.properties = cnt.to_raw().len() as u16;
reply.header.serial_number = rng.gen();
reply.content = MessageType::PlatformUniversalResponse(cnt);
}
_ => {
println!("no type");
return None;
}
}
Some(reply)
}
pub fn to_raw(&self) -> VecDeque<u8> {
let mut resp: VecDeque<u8> = vec![].into();
let mut checksum: u8 = 0;
for b in self.header.to_raw() {
resp.push_back(b);
}
for b in self.content.to_raw() {
resp.push_back(b);
}
for b in resp.iter() {
checksum = checksum ^ b;
}
resp.push_back(checksum);
resp.push_front(FLAGDELIMITER);
resp.push_back(FLAGDELIMITER);
resp
}
}
#[derive(Default, Debug)]
pub struct MessageHeader {
id: u16,
properties: u16,
pub bodylength: u8,
encryption: u8,
pub encrypted: bool,
pub subcontract: bool,
reserved: u16,
raw_terminal_id: [u8; 6],
pub terminal_id: u64,
pub serial_number: u16,
}
impl MessageHeader {
fn to_raw(&self) -> Vec<u8> {
let mut r: Vec<u8> = vec![];
for b in self.id.to_be_bytes() {
r.push(b);
}
for b in self.properties.to_be_bytes() {
r.push(b);
}
for b in self.raw_terminal_id.into_iter() {
r.push(b);
}
for b in self.serial_number.to_be_bytes() {
r.push(b);
}
r
}
}
impl std::fmt::Display for MessageHeader {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"message header: id: {:X?}, length: {}, terminal id: {}, serial: {:X?}",
self.id, self.bodylength, self.terminal_id, self.serial_number
)
}
}
#[derive(Debug, Clone)]
pub enum MessageType {
None,
TerminalUniversalResponse(TerminalUniversalResponse),
PlatformUniversalResponse(PlatformUniversalResponse),
TerminalHeartbeat(TerminalHeartbeat),
TerminalRegistration(TerminalRegistration),
TerminalRegistrationReply(TerminalRegistrationReply),
TerminalLogout(TerminalLogout),
TerminalAuthentication(TerminalAuthentication),
TerminalParameterSetting(TerminalParameterSetting),
QueryTerminalParameter(QueryTerminalParameter),
QueryTerminalParameterResponse(QueryTerminalParameterResponse),
TerminalControl(TerminalControl),
LocationInformationReport(LocationInformationReport),
StartOfTrip(StartOfTrip),
EndOfTrip(EndOfTrip),
}
impl Default for MessageType {
fn default() -> Self {
Self::None
}
}
impl BodyMessage for MessageType {
fn to_raw(&self) -> Vec<u8> {
let res = match self {
MessageType::TerminalRegistrationReply(o) => o.to_raw(),
MessageType::PlatformUniversalResponse(o) => o.to_raw(),
//MessageType::TerminalHeartbeat(o) => o.to_raw(),
_ => vec![],
};
res
}
}
impl std::fmt::Display for MessageType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
/*
macro_rules! generate_switch {
($($t:ty),*) => {
$(
//impl BodyMessage for $t {
// fn build() {}
// fn body_to_iter<'a>(&'a self, rawbody: &'a Vec<u8>) -> std::slice::Iter<'a, u8> {
// rawbody.into_iter()
// }
//}
impl $t {
pub fn new(rawbody: &Vec<u8>) -> Self {
let mut res = Self::default();
res.parse(rawbody);
res
}
})*
};
}*/