diff --git a/Cargo.lock b/Cargo.lock index 4550f22..734c9bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -65,6 +80,12 @@ dependencies = [ "wyz", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -77,12 +98,41 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +[[package]] +name = "cc" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -115,6 +165,39 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -137,6 +220,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.7.4" @@ -149,6 +238,7 @@ version = "0.1.0" dependencies = [ "bcd-convert", "bitvec", + "chrono", "encoding_rs", "lazy_static", "rand", @@ -175,6 +265,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.7" @@ -184,6 +283,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "parking_lot" version = "0.12.3" @@ -297,6 +402,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -400,6 +511,69 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 0f69f4f..9be0740 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] bcd-convert = { version = "0.1" } bitvec = { version = "1.0.1" } +chrono = { version = "0.4" } encoding_rs = { version = "0.8" } lazy_static = { version = "1.5" } rand = { version = "0.8" } diff --git a/src/main.rs b/src/main.rs index 912d858..b727863 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,9 +73,9 @@ pub async fn apiserver() -> io::Result<()> { pub fn handle(buf: &Vec) -> Option> { let mut rawdata = InboundDataWrapper::new(buf.to_vec()); let reply = match parse_inbound_msg(&mut rawdata) { - Ok(mut o) => { + Ok(o) => { println!("query: {}", o); - println!("raw query: {:X?}", o.to_raw()); + //println!("raw query: {:X?}", o.to_raw()); Message::store(&o); Message::set_reply(o) } @@ -86,9 +86,10 @@ pub fn handle(buf: &Vec) -> Option> { }; match reply { - Some(mut o) => { + Some(o) => { println!("reply: {}", o); - println!("raw reply {:X?}", o.to_raw()); + //println!("raw reply {:X?}", o.to_raw()); + println!("\n"); return Some(o.to_raw().into()); } None => { diff --git a/src/parser/body.rs b/src/parser/body.rs index ecfbfcf..aab58bf 100644 --- a/src/parser/body.rs +++ b/src/parser/body.rs @@ -1,33 +1,19 @@ use bcd_convert::BcdNumber; +use bitvec::prelude::*; +use chrono::prelude::*; use encoding_rs::*; -macro_rules! generate_impl { - ($($t:ty),*) => { - $( - //impl BodyMessage for $t { - // fn build() {} - // fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { - // rawbody.into_iter() - // } - //} - impl $t { - pub fn new(rawbody: &Vec) -> Self { - let mut res = Self::default(); - res.parse(rawbody); - res - } - })* - }; -} - pub trait BodyMessage { fn build(&self) {} + fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { rawbody.into_iter() } + fn print(&mut self, rawbody: &Vec) { println!("{:?}", rawbody); } + fn to_raw(&self) -> Vec { vec![] } @@ -95,6 +81,12 @@ impl TerminalHeartbeat { } } +impl std::fmt::Display for TerminalHeartbeat { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Default, Debug, Clone)] pub struct TerminalRegistration { pub provincial_id: u16, @@ -191,6 +183,7 @@ impl TerminalRegistrationReply { impl BodyMessage for TerminalRegistrationReply { fn parse(&mut self, rawbody: &Vec) {} + fn to_raw(&self) -> Vec { let mut res: Vec = vec![]; for b in self.answer_serial_no.to_be_bytes() { @@ -260,6 +253,12 @@ impl BodyMessage for TerminalAuthentication { } } +impl std::fmt::Display for TerminalAuthentication { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "authentication_code: {}", self.authentication_code,) + } +} + #[derive(Default, Debug, Clone)] pub struct TerminalParameterSetting { pub total_parameters: u8, @@ -329,13 +328,13 @@ impl BodyMessage for TerminalControl { #[derive(Default, Debug, Clone)] pub struct LocationInformationReport { pub alert_mark: u32, - pub status: u32, - pub latitude: u32, - pub longitude: u32, + pub status: LocationInformationReportStatus, + pub latitude: f64, + pub longitude: f64, pub height: u16, pub speed: u16, pub direction: u16, - pub time: String, + pub time: NaiveDateTime, } impl LocationInformationReport { @@ -348,6 +347,22 @@ impl LocationInformationReport { res.result = TerminalRegistrationResult::Success as u8; res } + + fn parse_latitude(&self, lat: u32) -> f64 { + let mut res = lat as f64 / 1_000_000f64; + if self.status.south { + res = -res + }; + res + } + + fn parse_longitude(&self, long: u32) -> f64 { + let mut res = long as f64 / 1_000_000f64; + if self.status.west { + res = -res + }; + res + } } impl BodyMessage for LocationInformationReport { @@ -363,7 +378,7 @@ impl BodyMessage for LocationInformationReport { .try_into() .unwrap(), ); - self.status = u32::from_be_bytes( + let status = u32::from_be_bytes( vec![ *bd.next().unwrap(), *bd.next().unwrap(), @@ -373,7 +388,8 @@ impl BodyMessage for LocationInformationReport { .try_into() .unwrap(), ); - self.latitude = u32::from_be_bytes( + self.status = status.into(); + self.latitude = self.parse_latitude(u32::from_be_bytes( vec![ *bd.next().unwrap(), *bd.next().unwrap(), @@ -382,8 +398,8 @@ impl BodyMessage for LocationInformationReport { ] .try_into() .unwrap(), - ); - self.longitude = u32::from_be_bytes( + )); + self.longitude = self.parse_longitude(u32::from_be_bytes( vec![ *bd.next().unwrap(), *bd.next().unwrap(), @@ -392,7 +408,7 @@ impl BodyMessage for LocationInformationReport { ] .try_into() .unwrap(), - ); + )); self.height = u16::from_be_bytes( vec![*bd.next().unwrap(), *bd.next().unwrap()] .try_into() @@ -412,8 +428,55 @@ impl BodyMessage for LocationInformationReport { for i in 0..tmptime.len() { tmptime[i] = *bd.next().unwrap(); } + println!("{:X?}", rawbody); + println!("{:?}", tmptime); let code = BcdNumber::try_from(&tmptime as &[u8]).unwrap(); - self.time = format!("{}", code.to_u64().unwrap()); + println!("{}", code); + let time = format!("{}", code.to_u64().unwrap()); + println!("{}", time); + self.time = NaiveDateTime::parse_from_str(time.as_str(), "%y%m%d%H%M%S").unwrap(); + } +} + +impl std::fmt::Display for LocationInformationReport { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "latitude: {}, longitude: {}, direction: {}, speed: {}", + self.latitude, self.longitude, self.direction, self.speed + ) + } +} + +#[derive(Default, Debug, Clone)] +pub struct LocationInformationReportStatus { + acc: bool, + positionning: bool, + south: bool, + west: bool, + stop_running: bool, + secret: bool, + vehicule_power_loop_disconnected: bool, + gps: bool, + beidou: bool, + glonass: bool, +} + +impl From for LocationInformationReportStatus { + fn from(status: u32) -> Self { + let mut res = LocationInformationReportStatus::default(); + let bits = status.view_bits::(); + res.acc = bits[0]; + res.positionning = bits[1]; + res.south = bits[2]; + res.west = bits[3]; + res.stop_running = bits[4]; + res.secret = bits[5]; + res.vehicule_power_loop_disconnected = bits[11]; + res.gps = bits[18]; + res.beidou = bits[19]; + res.glonass = bits[20]; + res } } @@ -437,6 +500,7 @@ impl BodyMessage for EndOfTrip { fn parse(&mut self, rawbody: &Vec) {} } +/* struct BCDTime { pub time: String, } @@ -444,6 +508,26 @@ struct BCDTime { impl BCDTime { pub fn parse() {} } +*/ + +macro_rules! generate_impl { + ($($t:ty),*) => { + $( + /*impl BodyMessage for $t { + fn build() {} + fn body_to_iter<'a>(&'a self, rawbody: &'a Vec) -> std::slice::Iter<'a, u8> { + rawbody.into_iter() + } + }*/ + impl $t { + pub fn new(rawbody: &Vec) -> Self { + let mut res = Self::default(); + res.parse(rawbody); + res + } + })* + }; +} generate_impl!( TerminalUniversalResponse, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f0603b5..32634c9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8,7 +8,8 @@ use header::*; use std::collections::VecDeque; -const FLAGDELIMITER: u8 = 0x7E; +const FLAG_DELIMITER: u8 = 0x7E; +const FLAG_DELIMITER_ESCAPE: u8 = 0x7D; pub fn parse_inbound_msg( rawdata: &mut InboundDataWrapper, @@ -31,18 +32,20 @@ pub fn parse_inbound_msg( #[derive(Default, Debug)] pub struct InboundDataWrapper { pub data: VecDeque, - pub count: usize, - pub start: bool, - pub end: bool, + pub index: usize, + pub started: bool, + pub ended: bool, + pub escaped: Option, } impl InboundDataWrapper { pub fn new(data: Vec) -> InboundDataWrapper { InboundDataWrapper { data: data.into(), - count: 0, - start: false, - end: false, + index: 0, + started: false, + ended: false, + escaped: None, } } } @@ -51,21 +54,34 @@ impl Iterator for InboundDataWrapper { type Item = u8; fn next(&mut self) -> Option { - let res: Option; + let mut res: Option = None; + + match self.escaped { + Some(o) => return Some(o), + None => {} + } loop { match self.data.pop_front() { Some(o) => { - if o == FLAGDELIMITER { - if self.start { - self.end = true; - res = None; - break; + if self.started { + if o == FLAG_DELIMITER { + match self.data.pop_front() { + Some(o) => match o { + 0x02 => res = Some(FLAG_DELIMITER), + 0x01 => res = Some(FLAG_DELIMITER_ESCAPE), + _ => self.escaped = Some(o), + }, + None => {} + } + } else { + res = Some(o); } - self.start = true; + } + if o == FLAG_DELIMITER && self.index == 0 { + self.started = true; continue; } - res = Some(o); } None => { res = None; @@ -73,7 +89,7 @@ impl Iterator for InboundDataWrapper { }; break; } - self.count += 1; + self.index += 1; res } @@ -155,63 +171,64 @@ impl Message { fn parse_body(&mut self) { match self.header.get_id() { TerminalUniversalResponse::ID => { - self.content = MessageType::TerminalUniversalResponse( - TerminalUniversalResponse::new(&self.body), - ) + let obj = TerminalUniversalResponse::new(&self.body); + self.content = MessageType::TerminalUniversalResponse(obj) } PlatformUniversalResponse::ID => { - self.content = MessageType::PlatformUniversalResponse( - PlatformUniversalResponse::new(&self.body), - ) + let obj = PlatformUniversalResponse::new(&self.body); + self.content = MessageType::PlatformUniversalResponse(obj) } TerminalHeartbeat::ID => { - self.content = MessageType::TerminalHeartbeat(TerminalHeartbeat::new(&self.body)) + let obj = TerminalHeartbeat::new(&self.body); + self.content = MessageType::TerminalHeartbeat(obj) } TerminalRegistration::ID => { - self.content = - MessageType::TerminalRegistration(TerminalRegistration::new(&self.body)) + let obj = TerminalRegistration::new(&self.body); + self.content = MessageType::TerminalRegistration(obj) } TerminalRegistrationReply::ID => { - self.content = MessageType::TerminalRegistrationReply( - TerminalRegistrationReply::new(&self.body), - ) + let obj = TerminalRegistrationReply::new(&self.body); + self.content = MessageType::TerminalRegistrationReply(obj) } TerminalLogout::ID => { - self.content = MessageType::TerminalLogout(TerminalLogout::new(&self.body)) + let obj = TerminalLogout::new(&self.body); + self.content = MessageType::TerminalLogout(obj) } TerminalAuthentication::ID => { - self.content = - MessageType::TerminalAuthentication(TerminalAuthentication::new(&self.body)) + let obj = TerminalAuthentication::new(&self.body); + self.content = MessageType::TerminalAuthentication(obj) } TerminalParameterSetting::ID => { - self.content = - MessageType::TerminalParameterSetting(TerminalParameterSetting::new(&self.body)) + let obj = TerminalParameterSetting::new(&self.body); + self.content = MessageType::TerminalParameterSetting(obj) } QueryTerminalParameter::ID => { - self.content = - MessageType::QueryTerminalParameter(QueryTerminalParameter::new(&self.body)) + let obj = QueryTerminalParameter::new(&self.body); + self.content = MessageType::QueryTerminalParameter(obj) } QueryTerminalParameterResponse::ID => { - self.content = MessageType::QueryTerminalParameterResponse( - QueryTerminalParameterResponse::new(&self.body), - ) + let obj = QueryTerminalParameterResponse::new(&self.body); + self.content = MessageType::QueryTerminalParameterResponse(obj) } TerminalControl::ID => { - self.content = MessageType::TerminalControl(TerminalControl::new(&self.body)) + let obj = TerminalControl::new(&self.body); + self.content = MessageType::TerminalControl(obj) } LocationInformationReport::ID => { - self.content = MessageType::LocationInformationReport( - LocationInformationReport::new(&self.body), - ) + let obj = LocationInformationReport::new(&self.body); + self.content = MessageType::LocationInformationReport(obj) } StartOfTrip::ID => { - self.content = MessageType::StartOfTrip(StartOfTrip::new(&self.body)) + let obj = StartOfTrip::new(&self.body); + self.content = MessageType::StartOfTrip(obj) + } + EndOfTrip::ID => { + let obj = EndOfTrip::new(&self.body); + self.content = MessageType::EndOfTrip(obj) } - EndOfTrip::ID => self.content = MessageType::EndOfTrip(EndOfTrip::new(&self.body)), _ => { - self.content = MessageType::TerminalUniversalResponse( - TerminalUniversalResponse::new(&self.body), - ) + let obj = TerminalUniversalResponse::new(&self.body); + self.content = MessageType::TerminalUniversalResponse(obj) } } } @@ -297,7 +314,7 @@ impl Message { self.valid = true; } - pub fn to_raw(&mut self) -> VecDeque { + pub fn to_raw(&self) -> VecDeque { let mut resp: VecDeque = vec![].into(); for b in self.header.to_raw() { @@ -310,8 +327,8 @@ impl Message { resp.push_back(self.checksum); - resp.push_front(FLAGDELIMITER); - resp.push_back(FLAGDELIMITER); + resp.push_front(FLAG_DELIMITER); + resp.push_back(FLAG_DELIMITER); resp } } @@ -320,7 +337,7 @@ impl std::fmt::Display for Message { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "Message: (header: {}), content: {}, checksum: {}, valid: {}", + "Message: (header: {}), (content: {}), checksum: {}, valid: {}", self.header, self.content, self.checksum, self.valid ) } @@ -365,6 +382,13 @@ impl BodyMessage for MessageType { impl std::fmt::Display for MessageType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:?}", self) + let res = match self { + MessageType::TerminalRegistration(o) => o.fmt(f), + MessageType::LocationInformationReport(o) => o.fmt(f), + MessageType::TerminalHeartbeat(o) => o.fmt(f), + MessageType::TerminalAuthentication(o) => o.fmt(f), + _ => write!(f, "{:?}", self), + }; + res } }