diff --git a/Cargo.lock b/Cargo.lock index 670b9e3..92849c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "bcd-convert" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a18a98ca044380fc93aa29f45577996d8aee9b689176b56327f3080280d798" +dependencies = [ + "thiserror", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -88,6 +97,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" name = "micodus_server" version = "0.1.0" dependencies = [ + "bcd-convert", "tokio", ] @@ -224,6 +234,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio" version = "1.42.0" diff --git a/Cargo.toml b/Cargo.toml index e966b21..df4e370 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +bcd-convert = "0.1.0" tokio = { version = "1.42", features = ["full", "sync"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..fde0af8 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# micodus_server + +Micodus platform server + +## Build + +```cargo b -r``` + +## License + +``` + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. +``` diff --git a/src/main.rs b/src/main.rs index 3c92a8b..da6e571 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,12 +31,12 @@ pub async fn apiserver() -> io::Result<()> { loop { match listener.accept().await { Ok((socket, _remote_addr)) => { - let mut buf = vec![0; 256]; + let mut buf = vec![0; 1024]; match socket.readable().await { Ok(_) => { match socket.try_read(&mut buf) { - Ok(_) => {} + Ok(_) => handle(&buf), Err(e) => { println!("error: {e}"); continue; @@ -48,10 +48,6 @@ pub async fn apiserver() -> io::Result<()> { continue; } } - - let mut rawdata = buf.to_vec(); - let msg = parse_inbound_msg(&mut rawdata); - println!("{:X?}", msg); } Err(err) => { println!("error: {err}"); @@ -61,3 +57,9 @@ pub async fn apiserver() -> io::Result<()> { }); Ok(()) } + +pub fn handle(buf: &Vec) { + let mut rawdata = buf.to_vec(); + let msg = parse_inbound_msg(&mut rawdata); + println!("{}", msg); +} diff --git a/src/parser/body.rs b/src/parser/body.rs index 17fef60..3d3b9f5 100644 --- a/src/parser/body.rs +++ b/src/parser/body.rs @@ -1,3 +1,26 @@ +pub trait BodyMessage { + fn build() {} + fn print(&mut self, body: &Vec) { + println!("{:?}", body); + } +} + +macro_rules! generate_impl { + ($($t:ty),*) => { + $( + impl BodyMessage for $t { + fn build() {} + } + impl $t { + pub fn new(body: &Vec) -> Self { + let mut res = Self::default(); + res.parse(body); + res + } + })* + }; +} + #[derive(Default, Debug)] pub struct TerminalUniversalResponse { pub answer_serial_no: u16, @@ -5,7 +28,11 @@ pub struct TerminalUniversalResponse { pub result: u8, } -impl BodyMessage for TerminalUniversalResponse {} +impl TerminalUniversalResponse { + const ID: u16 = 0x100; + pub fn parse(&mut self, body: &Vec) {} + pub fn debug() {} +} #[derive(Default, Debug)] pub struct PlatformUniversalResponse { @@ -14,9 +41,17 @@ pub struct PlatformUniversalResponse { pub result: u8, } +impl PlatformUniversalResponse { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalHeartbeat {} +impl TerminalHeartbeat { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalRegistration { pub provincial_id: u16, @@ -28,6 +63,24 @@ pub struct TerminalRegistration { pub license_plate: String, } +impl TerminalRegistration { + pub fn parse(&mut self, body: &Vec) {} + pub fn generate_reply(&self, serial: u16) -> TerminalRegistrationReply { + let mut res = TerminalRegistrationReply::default(); + res.answer_serial_no = serial; + res.result = TerminalRegistrationResult::Success as u8; + res + } +} + +enum TerminalRegistrationResult { + Success = 0x00, + VehicleRegistered, + VehicleNotInDatabase, + TerminalRegistered, + VehicleNotInDatabase2, +} + #[derive(Default, Debug)] pub struct TerminalRegistrationReply { pub answer_serial_no: u16, @@ -35,20 +88,47 @@ pub struct TerminalRegistrationReply { pub authentication_code: String, } +impl TerminalRegistrationReply { + pub fn parse(&mut self, body: &Vec) {} + pub fn body_to_vec(&self) -> Vec { + let mut res: Vec = vec![]; + for b in self.answer_serial_no.to_be_bytes() { + res.push(b); + } + res.push(self.result); + for b in self.authentication_code.as_bytes() { + res.push(*b); + } + res + } +} + #[derive(Default, Debug)] pub struct TerminalLogout {} +impl TerminalLogout { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalAuthentication { pub authentication_code: String, } +impl TerminalAuthentication { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalParameterSetting { pub total_parameters: u8, pub parameters: Vec, } +impl TerminalParameterSetting { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalParameterData { pub parameter_id: u32, @@ -56,8 +136,15 @@ pub struct TerminalParameterData { pub parameter_value: u8, } +impl TerminalParameterData { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct QueryTerminalParameter {} +impl QueryTerminalParameter { + pub fn parse(&mut self, body: &Vec) {} +} #[derive(Default, Debug)] pub struct QueryTerminalParameterResponse { @@ -66,12 +153,20 @@ pub struct QueryTerminalParameterResponse { pub parameters: Vec, } +impl QueryTerminalParameterResponse { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct TerminalControl { pub command_word: u8, pub command_parameter: String, } +impl TerminalControl { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct LocationInformationReport { pub alert_mark: u32, @@ -84,30 +179,36 @@ pub struct LocationInformationReport { pub time: u32, } +impl LocationInformationReport { + pub fn parse(&mut self, body: &Vec) {} +} + #[derive(Default, Debug)] pub struct StartOfTrip {} +impl StartOfTrip { + pub fn parse(&mut self, body: &Vec) {} +} #[derive(Default, Debug)] pub struct EndOfTrip {} - -#[derive(Debug)] -pub enum BodyType { - TerminalUniversalResponse = 0x0001, - PlatformUniversalResponse = 0x8001, - TerminalHeartbeat = 0x0002, - TerminalRegistration = 0x0100, - TerminalRegistrationReply = 0x8100, - TerminalLogout = 0x0003, - TerminalAuthentication = 0x0102, - TerminalParameterSetting = 0x8103, - QueryTerminalParameter = 0x8104, - QueryTerminalParameterResponse = 0x0104, - TerminalControl = 0x8105, - LocationInformationReport = 0x0200, - StartOfTrip = 0x0202, - EndOfTrip = 0x0203, +impl EndOfTrip { + pub fn parse(&mut self, body: &Vec) {} } -pub trait BodyMessage { - fn parse() {} -} +generate_impl!( + TerminalUniversalResponse, + PlatformUniversalResponse, + TerminalHeartbeat, + TerminalRegistration, + TerminalRegistrationReply, + TerminalLogout, + TerminalAuthentication, + TerminalParameterSetting, + TerminalParameterData, + QueryTerminalParameter, + QueryTerminalParameterResponse, + TerminalControl, + LocationInformationReport, + StartOfTrip, + EndOfTrip +); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f8a864b..1e18ba6 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,14 +1,20 @@ mod body; use body::*; +use std::fmt::*; + +use bcd_convert::BcdNumber; const FLAGDELIMITER: u8 = 0x7E; #[allow(dead_code)] -const PropsSizeMask: u16 = 0x01FF; -const PropsSubcontractMask: u16 = 0x3000; -const PropsReservedMask: u16 = 0xC000; -const PropsDataEncryptionMask: u16 = 0x0E00; +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 Vec) -> Message { let mut msg: Message = Message::default(); @@ -22,11 +28,22 @@ pub fn parse_inbound_msg(rawdata: &mut Vec) -> Message { #[derive(Default, Debug)] pub struct Message { pub header: MessageHeader, + pub content: MessageType, pub body: Vec, 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 Vec) { let mut data = rawdata.clone().into_iter(); @@ -34,17 +51,24 @@ impl Message { if first_byte == FLAGDELIMITER { println!("first flag ok"); }; - self.header.id = ((data.next().unwrap() as u16) << 8) + data.next().unwrap() as u16; + 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; - for i in 0..self.header.terminal_id.len() { - self.header.terminal_id[i] = data.next().unwrap(); - } 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.properties as usize { + for _ in 0..self.header.bodylength as usize { self.body.push(data.next().unwrap()); } @@ -55,10 +79,16 @@ impl Message { } else { println!("error with endflag"); } + self.parse_body(); } pub fn parse_properties(&mut self) { - self.header.bodylength = (self.header.properties & PropsSizeMask) as u8; + self.header.bodylength = (self.header.properties & PROPS_SIZE_MASK) as u8; + } + + 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 Vec) { @@ -78,21 +108,128 @@ impl Message { } fn validate(&mut self, check: u8) { - println!("{}", BodyType::TerminalHeartbeat as u16); self.valid = check == 0; } pub fn is_valid(&self) -> bool { self.valid } + + pub fn parse_body(&mut self) { + match self.header.id { + 0x0001 => { + self.content = MessageType::TerminalUniversalResponse( + TerminalUniversalResponse::new(&self.body), + ) + } + 0x8001 => { + self.content = MessageType::PlatformUniversalResponse( + PlatformUniversalResponse::new(&self.body), + ) + } + 0x0002 => { + self.content = MessageType::TerminalHeartbeat(TerminalHeartbeat::new(&self.body)) + } + 0x0100 => { + self.content = + MessageType::TerminalRegistration(TerminalRegistration::new(&self.body)) + } + 0x8100 => { + self.content = MessageType::TerminalRegistrationReply( + TerminalRegistrationReply::new(&self.body), + ) + } + 0x0003 => self.content = MessageType::TerminalLogout(TerminalLogout::new(&self.body)), + 0x0102 => { + self.content = + MessageType::TerminalAuthentication(TerminalAuthentication::new(&self.body)) + } + 0x8103 => { + self.content = + MessageType::TerminalParameterSetting(TerminalParameterSetting::new(&self.body)) + } + 0x8104 => { + self.content = + MessageType::QueryTerminalParameter(QueryTerminalParameter::new(&self.body)) + } + 0x0104 => { + self.content = MessageType::QueryTerminalParameterResponse( + QueryTerminalParameterResponse::new(&self.body), + ) + } + 0x8105 => self.content = MessageType::TerminalControl(TerminalControl::new(&self.body)), + 0x0200 => { + self.content = MessageType::LocationInformationReport( + LocationInformationReport::new(&self.body), + ) + } + 0x0202 => self.content = MessageType::StartOfTrip(StartOfTrip::new(&self.body)), + 0x0203 => self.content = MessageType::EndOfTrip(EndOfTrip::new(&self.body)), + _ => self.content = MessageType::None, + } + } + + pub fn set_reply(msg: Message) -> Message { + let mut reply = Message::default(); + match msg.content { + MessageType::TerminalRegistration(t) => { + reply.content = MessageType::TerminalRegistrationReply( + t.generate_reply(msg.header.serial_number), + ); + } + _ => {} + } + reply + } } #[derive(Default, Debug)] pub struct MessageHeader { - pub id: u16, + id: u16, properties: u16, pub bodylength: u8, pub encryption: bool, - pub terminal_id: [u8; 6], + raw_terminal_id: [u8; 6], + pub terminal_id: u64, pub serial_number: u16, } + +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: {}", + self.id, self.bodylength, self.terminal_id, self.serial_number + ) + } +} + +#[derive(Debug)] +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 std::fmt::Display for MessageType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +}