log parsing

This commit is contained in:
Will Greenberg
2023-12-04 16:47:42 -08:00
parent db18abae6f
commit e6fab5c27d
4 changed files with 338 additions and 44 deletions
Generated
+230
View File
@@ -2,6 +2,27 @@
# It is not intended for manual editing.
version = 3
[[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.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitvec"
version = "1.0.1"
@@ -14,6 +35,12 @@ dependencies = [
"wyz",
]
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -35,6 +62,41 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[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.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "crc"
version = "3.0.1"
@@ -124,6 +186,7 @@ name = "diag"
version = "0.1.0"
dependencies = [
"bytes",
"chrono",
"crc",
"deku",
"libc",
@@ -155,6 +218,29 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
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 = "ident_case"
version = "1.0.1"
@@ -171,18 +257,42 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "js-sys"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.18.0"
@@ -311,6 +421,126 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
[[package]]
name = "windows-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.19"
+1
View File
@@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
bytes = "1.5.0"
chrono = "0.4.31"
crc = "3.0.1"
deku = "0.16.0"
libc = "0.2.150"
+65 -13
View File
@@ -1,5 +1,6 @@
//! Diag protocol serialization/deserialization
use chrono::{DateTime, Local, FixedOffset};
use deku::prelude::*;
#[derive(Debug, Clone, DekuWrite)]
@@ -43,31 +44,66 @@ pub enum DataType {
}
#[derive(Debug, Clone, DekuRead)]
pub struct ResponseContainer {
pub struct MessagesContainer {
pub data_type: DataType,
pub num_responses: u32,
#[deku(count = "num_responses")]
pub responses: Vec<HdlcEncapsulatedResponse>,
pub messages: Vec<HdlcEncapsulatedMessage>,
}
#[derive(Debug, Clone, DekuRead)]
pub struct HdlcEncapsulatedResponse {
pub struct HdlcEncapsulatedMessage {
pub len: u32,
#[deku(count = "len")]
pub data: Vec<u8>,
}
// kinda unpleasant deku hackery here. deku expects an enum's variant to be
// right before its data, but in this case, a status value comes between the
// variants and the data. so we need to use deku's context (ctx) feature to pass
// those opcodes down to their respective parsers.
#[derive(Debug, Clone, DekuRead)]
pub struct Response {
opcode: u32,
subopcode: u32,
pub status: u32,
#[deku(ctx = "*opcode, *subopcode")]
pub payload: ResponsePayload,
#[deku(type = "u8")]
pub enum Message {
#[deku(id = "16")]
Log {
pending_msgs: u8,
outer_length: u16,
inner_length: u16,
log_type: u16,
timestamp: Timestamp,
#[deku(count = "inner_length - 12")]
payload: Vec<u8>,
},
// kinda unpleasant deku hackery here. deku expects an enum's variant to be
// right before its data, but in this case, a status value comes between the
// variants and the data. so we need to use deku's context (ctx) feature to
// pass those opcodes down to their respective parsers.
#[deku(id_pat = "_")]
Response {
opcode: u32,
subopcode: u32,
status: u32,
#[deku(ctx = "*opcode, *subopcode")]
payload: ResponsePayload,
},
}
#[derive(Debug, Clone, DekuRead)]
#[deku(endian = "little")]
pub struct Timestamp {
pub ts: u64,
}
impl Timestamp {
pub fn to_datetime(&self) -> DateTime<FixedOffset> {
// Upper 48 bits: epoch at 1980-01-06 00:00:00, incremented by 1 for 1/800s
// Lower 16 bits: time since last 1/800s tick in 1/32 chip units
let ts_upper = self.ts >> 16;
let ts_lower = self.ts & 0xffff;
let epoch = chrono::DateTime::parse_from_rfc3339("1980-01-06T00:00:00-00:00").unwrap();
let mut delta_seconds = ts_upper as f64 * 1.25;
delta_seconds += ts_lower as f64 / 40960.0;
let ts_delta = chrono::Duration::milliseconds(delta_seconds as i64);
epoch + ts_delta
}
}
#[derive(Debug, Clone, DekuRead)]
@@ -177,4 +213,20 @@ mod test {
1, 2, 3, 4,
]);
}
#[test]
fn test_message_parsing() {
let msg_bytes = vec![16, 0, 26, 0, 26, 0, 167, 24, 38, 161, 72, 107, 146, 30, 2, 1, 1, 1, 0, 0, 0, 0, 0, 140, 10, 0, 0, 220, 5, 0];
match Message::from_bytes((msg_bytes.as_slice(), 0)) {
Ok((_, Message::Log { pending_msgs, outer_length, inner_length, log_type, timestamp, payload })) => {
assert_eq!(pending_msgs, 0);
assert_eq!(outer_length, 26);
assert_eq!(inner_length, 26);
assert_eq!(log_type, 6311);
assert_eq!(timestamp.to_datetime().date_naive(), chrono::NaiveDate::from_ymd_opt(2023, 12, 4).unwrap());
assert_eq!(payload, vec![1, 1, 0, 0, 0, 0, 0, 140, 10, 0, 0, 220, 5, 0]);
},
_ => panic!("failed to parse message"),
}
}
}
+42 -31
View File
@@ -1,5 +1,5 @@
use crate::hdlc::{hdlc_encapsulate, hdlc_decapsulate, HdlcError};
use crate::diag::{Response, ResponsePayload, Request, LogConfigRequest, LogConfigResponse, build_log_mask_request, RequestContainer, DataType, ResponseContainer};
use crate::diag::{Message, ResponsePayload, Request, LogConfigRequest, LogConfigResponse, build_log_mask_request, RequestContainer, DataType, MessagesContainer};
use std::fs::File;
use std::io::{Cursor, Read, Write};
@@ -72,32 +72,35 @@ impl DiagDevice {
})
}
fn parse_response_container(&self, container: ResponseContainer) -> DiagResult<Vec<Response>> {
fn parse_response_container(&self, container: MessagesContainer) -> DiagResult<Vec<Message>> {
let mut result = Vec::new();
for msg in container.responses {
let data = hdlc_decapsulate(msg.data, &self.crc)?;
match Response::from_bytes((&data, 0)) {
Ok(((_, leftover_bytes), res)) => {
if leftover_bytes > 0 {
println!("warning: {} leftover bytes when Response", leftover_bytes);
}
result.push(res);
},
Err(e) => {
println!("{:?}", data);
println!("error parsing response: {:?}", e);
for msg in container.messages {
match hdlc_decapsulate(msg.data, &self.crc) {
Ok(data) => match Message::from_bytes((&data, 0)) {
Ok(((_, leftover_bytes), res)) => {
if leftover_bytes > 0 {
println!("warning: {} leftover bytes when Response", leftover_bytes);
}
result.push(res);
},
Err(e) => {
println!("error parsing response: {:?}", e);
},
},
Err(err) => {
println!("error decapsulating response: {:?}", err);
}
}
}
Ok(result)
}
pub fn read_response(&mut self) -> DiagResult<Vec<Response>> {
pub fn read_response(&mut self) -> DiagResult<Vec<Message>> {
let mut buf = vec![0; BUFFER_LEN];
loop {
let _ = self.file.read(&mut buf)?;
let ((_, leftover_bytes), res_container) = ResponseContainer::from_bytes((&buf, 0))?;
let ((_, leftover_bytes), res_container) = MessagesContainer::from_bytes((&buf, 0))?;
if leftover_bytes > 0 {
println!("warning: {} leftover bytes when parsing ResponseContainer", leftover_bytes);
}
@@ -124,7 +127,7 @@ impl DiagDevice {
let msg = format!("write failed with error code {}", ret);
return Err(DiagDeviceError::DeviceReadFailed(msg));
}
println!("{}. wrote {} bytes to device", buf.len(), ret);
println!("wrote {} bytes to device", ret);
}
Ok(())
}
@@ -133,15 +136,18 @@ impl DiagDevice {
let req = Request::LogConfig(LogConfigRequest::RetrieveIdRanges);
self.write_request(&req)?;
for res in self.read_response()? {
match res.payload {
ResponsePayload::LogConfig(LogConfigResponse::RetrieveIdRanges { log_mask_sizes }) => {
if res.status != 0 {
return Err(DiagDeviceError::RequestFailed(res.status, req));
}
return Ok(log_mask_sizes);
for msg in self.read_response()? {
match msg {
Message::Log { .. } => println!("skipping log response..."),
Message::Response { payload, status, .. } => match payload {
ResponsePayload::LogConfig(LogConfigResponse::RetrieveIdRanges { log_mask_sizes }) => {
if status != 0 {
return Err(DiagDeviceError::RequestFailed(status, req));
}
return Ok(log_mask_sizes);
},
_ => println!("skipping non-LogConfigResponse response..."),
},
_ => println!("skipping non-LogConfigResponse response..."),
}
}
@@ -153,12 +159,17 @@ impl DiagDevice {
let req = build_log_mask_request(log_type, log_mask_bitsize);
self.write_request(&req)?;
for res in self.read_response()? {
if let ResponsePayload::LogConfig(LogConfigResponse::SetMask) = res.payload {
if res.status != 0 {
return Err(DiagDeviceError::RequestFailed(res.status, req));
}
return Ok(());
for msg in self.read_response()? {
match msg {
Message::Log { .. } => println!("skipping log response..."),
Message::Response { payload, status, .. } => {
if let ResponsePayload::LogConfig(LogConfigResponse::SetMask) = payload {
if status != 0 {
return Err(DiagDeviceError::RequestFailed(status, req));
}
return Ok(());
}
},
}
}