diff --git a/.gitignore b/.gitignore index ea8c4bf..a727c0a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/data diff --git a/Cargo.lock b/Cargo.lock index 734c9bf..285e9d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -142,6 +154,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "funty" version = "2.0.0" @@ -165,6 +189,24 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -210,6 +252,17 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -242,6 +295,7 @@ dependencies = [ "encoding_rs", "lazy_static", "rand", + "rusqlite", "tokio", ] @@ -318,6 +372,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -390,6 +450,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -505,6 +579,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 9be0740..a916531 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ chrono = { version = "0.4" } encoding_rs = { version = "0.8" } lazy_static = { version = "1.5" } rand = { version = "0.8" } +rusqlite = { version = "0.32.0", features = ["bundled"] } tokio = { version = "1.42", features = ["full", "sync"] } diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..4667e7e --- /dev/null +++ b/src/db.rs @@ -0,0 +1,42 @@ +use rusqlite::*; + +const DBPATH: &'static str = "data/tracker.db"; +const STATEMENTS: [&str; 2] = [ +"CREATE TABLE log (id integer primary key autoincrement, time text, latitude float, longitude float);", +"CREATE INDEX idx_time on log (time);",]; +const QUERY_INSERT: &'static str = + "INSERT INTO log (time, latitude, longitude) values (:time, :latitude, :longitude)"; + +pub fn connectdb() -> Result { + let conn = Connection::open(DBPATH)?; + Ok(conn) +} + +pub fn initdb(conn: &Connection) -> Result<()> { + create_tables(&conn)?; + set_pragmas(&conn)?; + Ok(()) +} + +fn create_tables(conn: &Connection) -> Result<()> { + for s in STATEMENTS { + match conn.execute(s, params![]) { + Ok(_) => {} + Err(err) => println!("update failed: {}", err), + } + } + Ok(()) +} + +fn set_pragmas(conn: &Connection) -> Result<()> { + conn.pragma_update(Some(DatabaseName::Main), "journal_mode", "WAL")?; + Ok(()) +} + +pub fn insert(conn: &Connection, time: &String, latitude: &f64, longitude: &f64) -> Result<()> { + match conn.execute(QUERY_INSERT, params![time, latitude, longitude]) { + Ok(inserted) => println!("{} rows were inserted", inserted), + Err(err) => println!("insert failed: {}", err), + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index a36df56..f4d3bef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ +mod db; mod parser; +use crate::db::*; use crate::parser::*; use std::io; @@ -11,9 +13,21 @@ const BUFSIZE: usize = 1024; #[tokio::main] async fn main() { + //test(); + let conn = connectdb().unwrap(); + initdb(&conn).unwrap(); apiserver().await.unwrap(); } +#[allow(dead_code)] +fn test() { + use bcd_convert::BcdNumber; + let data: Vec = vec![0x36, 0x31, 0x33, 0x32, 0x31, 0x31, 0x38]; + let code = BcdNumber::try_from(&data as &[u8]).unwrap(); + println!("{code}"); + std::process::exit(0); +} + async fn apiserver() -> io::Result<()> { let listener = match TcpListener::bind(ADDR).await { Ok(o) => o, diff --git a/src/parser/body.rs b/src/parser/body.rs index 1ce2573..e45cab1 100644 --- a/src/parser/body.rs +++ b/src/parser/body.rs @@ -4,7 +4,6 @@ use chrono::prelude::*; use encoding_rs::*; #[allow(dead_code)] - pub trait BodyMessage { fn build(&self) {} @@ -23,6 +22,7 @@ pub trait BodyMessage { fn parse(&mut self, rawbody: &Vec) {} } +#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct TerminalUniversalResponse { pub answer_serial_no: u16, @@ -30,12 +30,14 @@ pub struct TerminalUniversalResponse { pub result: u8, } +#[allow(dead_code)] impl TerminalUniversalResponse { pub const ID: u16 = 0x0001; pub fn debug() {} } +#[allow(dead_code)] impl BodyMessage for TerminalUniversalResponse { fn parse(&mut self, rawbody: &Vec) {} } @@ -44,7 +46,7 @@ impl BodyMessage for TerminalUniversalResponse { pub struct PlatformUniversalResponse { pub answer_serial_no: u16, pub answer_id: u16, - pub result: u8, + pub result: PlatformUniversalResponseResult, } impl PlatformUniversalResponse { @@ -62,11 +64,27 @@ impl BodyMessage for PlatformUniversalResponse { for b in self.answer_id.to_be_bytes() { res.push(b); } - res.push(self.result); + res.push(self.result.clone() as u8); res } } +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum PlatformUniversalResponseResult { + Success = 0x00, + Failed, + MessageError, + NotSupported, + AlertProcessingConfirm, +} + +impl Default for PlatformUniversalResponseResult { + fn default() -> Self { + PlatformUniversalResponseResult::Success + } +} + #[derive(Default, Debug, Clone)] pub struct TerminalHeartbeat {} @@ -79,7 +97,7 @@ impl TerminalHeartbeat { let mut res = PlatformUniversalResponse::default(); res.answer_serial_no = serial; res.answer_id = answer_id; - res.result = TerminalRegistrationResult::Success as u8; + res.result = PlatformUniversalResponseResult::Success; res } } @@ -108,9 +126,7 @@ impl TerminalRegistration { let mut res = TerminalRegistrationReply::default(); res.answer_serial_no = serial; res.result = TerminalRegistrationResult::Success as u8; - //res.authentication_code = String::from_utf8(terminal_id).unwrap(); - println!("{:?}", terminal_id); - res.authentication_code = vec![0x36, 0x31, 0x33, 0x32, 0x31, 0x31, 0x38]; + res.authentication_code = self.terminal_id.into(); res } } @@ -166,7 +182,7 @@ impl std::fmt::Display for TerminalRegistration { } #[allow(dead_code)] -enum TerminalRegistrationResult { +pub enum TerminalRegistrationResult { Success = 0x00, VehicleRegistered, VehicleNotInDatabase, @@ -212,7 +228,7 @@ impl TerminalLogout { let mut res = PlatformUniversalResponse::default(); res.answer_serial_no = serial; res.answer_id = answer_id; - res.result = TerminalRegistrationResult::Success as u8; + res.result = PlatformUniversalResponseResult::Success; res } } @@ -239,7 +255,7 @@ impl TerminalAuthentication { let mut res = PlatformUniversalResponse::default(); res.answer_serial_no = serial; res.answer_id = answer_id; - res.result = TerminalRegistrationResult::Success as u8; + res.result = PlatformUniversalResponseResult::Success; res } } @@ -263,6 +279,7 @@ impl std::fmt::Display for TerminalAuthentication { } } +#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct TerminalParameterSetting { pub total_parameters: u8, @@ -277,6 +294,7 @@ impl BodyMessage for TerminalParameterSetting { fn parse(&mut self, rawbody: &Vec) {} } +#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct TerminalParameterData { pub parameter_id: u32, @@ -300,6 +318,7 @@ impl BodyMessage for QueryTerminalParameter { fn parse(&mut self, rawbody: &Vec) {} } +#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct QueryTerminalParameterResponse { pub response_serial_no: u16, @@ -315,6 +334,7 @@ impl BodyMessage for QueryTerminalParameterResponse { fn parse(&mut self, rawbody: &Vec) {} } +#[allow(dead_code)] #[derive(Default, Debug, Clone)] pub struct TerminalControl { pub command_word: u8, @@ -343,15 +363,29 @@ pub struct LocationInformationReport { impl LocationInformationReport { pub const ID: u16 = 0x0200; + pub const TABLE: &'static str = "LocationInformationReport"; pub fn generate_reply(&self, answer_id: u16, serial: u16) -> PlatformUniversalResponse { let mut res = PlatformUniversalResponse::default(); res.answer_serial_no = serial; res.answer_id = answer_id; - res.result = TerminalRegistrationResult::Success as u8; + res.result = PlatformUniversalResponseResult::Success; res } + fn parse_time(&mut self, timeslice: [u8; 6]) { + let code = BcdNumber::try_from(×lice as &[u8]).unwrap(); + let time = format!("{}", code.to_u64().unwrap()); + match NaiveDateTime::parse_from_str(time.as_str(), "%y%m%d%H%M%S") { + Ok(o) => { + self.time = o; + } + Err(e) => { + println!("{timeslice:?} {code} {time} {e}"); + } + }; + } + fn parse_latitude(&self, latitude: u32) -> f64 { let mut res = latitude as f64 / 1_000_000.; if self.status.south { @@ -434,16 +468,7 @@ impl BodyMessage for LocationInformationReport { for i in 0..tmptime.len() { tmptime[i] = *bd.next().unwrap(); } - let code = BcdNumber::try_from(&tmptime as &[u8]).unwrap(); - let time = format!("{}", code.to_u64().unwrap()); - match NaiveDateTime::parse_from_str(time.as_str(), "%y%m%d%H%M%S") { - Ok(o) => { - self.time = o; - } - Err(e) => { - println!("{tmptime:?} {code} {time} {e}"); - } - }; + self.parse_time(tmptime); res = true; () } diff --git a/src/parser/header.rs b/src/parser/header.rs index d145c4b..c432d66 100644 --- a/src/parser/header.rs +++ b/src/parser/header.rs @@ -67,20 +67,20 @@ impl MessageHeader { } pub fn to_raw(&self) -> Vec { - let mut r: Vec = vec![]; + let mut raw: Vec = vec![]; for b in self.id.to_be_bytes() { - r.push(b); + raw.push(b); } for b in self.properties.to_be_bytes() { - r.push(b); + raw.push(b); } for b in self.raw_terminal_id.into_iter() { - r.push(b); + raw.push(b); } for b in self.serial_number.to_be_bytes() { - r.push(b); + raw.push(b); } - r + raw } } @@ -88,7 +88,7 @@ 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?}", + "id: {:X?}, length: {}, terminal id: {}, serial: {:X?}", self.id, self.bodylength, self.terminal_id, self.serial_number ) } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3ed8b7d..2cd8376 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -6,6 +6,8 @@ use body::*; use error::*; use header::*; +use crate::db::*; + use std::collections::VecDeque; const FLAG_DELIMITER: u8 = 0x7E; @@ -65,20 +67,23 @@ impl Iterator for InboundDataWrapper { match self.data.pop_front() { Some(o) => { if self.started { - if o == FLAG_DELIMITER { - match self.data.pop_front() { + match o { + FLAG_DELIMITER_ESCAPE => match self.data.pop_front() { Some(o) => match o { 0x02 => res = Some(FLAG_DELIMITER), 0x01 => res = Some(FLAG_DELIMITER_ESCAPE), _ => { self.escaped = Some(o); - self.ended = true; } }, - None => {} + None => res = None, + }, + FLAG_DELIMITER => { + res = None; + } + _ => { + res = Some(o); } - } else { - res = Some(o); } } if o == FLAG_DELIMITER && self.index == 0 { @@ -105,6 +110,7 @@ pub struct Message { pub body: Vec, pub checksum: u8, valid: bool, + pub status: bool, } impl Message { @@ -299,6 +305,32 @@ impl Message { pub fn store(inmsg: &Message) { match inmsg.content { MessageType::LocationInformationReport(ref t) => { + /*{ + use std::fs::OpenOptions; + use std::io::prelude::*; + + let mut file = OpenOptions::new() + .write(true) + .append(true) + .open("data/log.txt") + .unwrap(); + + //if let Err(e) = writeln!(file, ) { + // eprintln!("Couldn't write to file: {}", e); + //} + file.write(format!("{},{},{}\n", t.time, t.latitude, t.longitude).as_bytes()) + .unwrap(); + }*/ + + let conn = connectdb().unwrap(); + insert( + &conn, + &t.time.format("%Y-%m-%d %H:%M:%S").to_string(), + &t.latitude, + &t.longitude, + ) + .unwrap(); + println!("{:?}", t); } _ => {}