如何在Rust中解析嵌入式开发传感器输出的itm.txt格式文件数据
问题说明
我是嵌入式和Rust编程领域的新手,目前正在进行传感器相关开发,已经可以成功获取传感器读数。
数据存储在itm.txt文件中,包含报文头和可变长度载荷,目前无法找到Rust中解析该数据的方法。
现有代码
use std::io; use std::fs::File; use std::io::{Read, BufReader}; fn decode<R: io::Read>(mut r: R) -> io::Result<Vec<u8>> { let mut output = vec![]; loop { let mut len = 0u8; r.read_exact(std::slice::from_mut(&mut len))?; let len = 1 << (len - 1); let mut buf = vec![0; len]; let res = r.read_exact(&mut buf); if buf == b"\0" { break; } output.extend(buf); } Ok(output) } fn main() { //let data = "{ x: 579, y: -197 , z: -485 }\0"; let mut file = File::open("/tmp/itm.txt").expect("No such file is present at this location"); let mut buf_reader = Vec::new(); file.read_to_end(&mut buf_reader).expect("error"); let content = std::str::from_utf8(&buf_reader).unwrap(); println!("raw str: {:?}", content); println!("raw hex: {:x?}", content.as_bytes()); let decoded = decode(content.as_bytes()).unwrap(); let s = std::str::from_utf8(&decoded).expect("Failed"); println!("decoded str: {:?}", s); }
报错信息
raw str: "\u{2}Un\u{3}scal\u{3}edMe\u{3}asur\u{3}emen\u{1}t\u{1} \u{2}{ \u{1}x\u{2}: \u{2}31\u{1}3\u{1},\u{1} \n\n" raw hex: [2, 55, 6e, 3, 73, 63, 61, 6c, 3, 65, 64, 4d, 65, 3, 61, 73, 75, 72, 3, 65, 6d, 65, 6e, 1, 74, 1, 20, 2, 7b, 20, 1, 78, 2, 3a, 20, 2, 33, 31, 1, 33, 1, 2c, 1, 20, a, a] thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }', src/main.rs:51:46 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
解决方案
错误原因
- 解析逻辑不符合ITM帧格式规范:你直接将整个帧头字节作为长度参数计算,ITM刺激端口报文的头字节低5位是端口号,仅高3位为长度编码,错误的长度计算会生成超大的读取长度,直接触发EOF报错。
- 二进制数据先转UTF-8字符串的操作错误:ITM是二进制格式,中间可能包含非UTF-8字节,转字符串操作会破坏原始数据结构,导致后续解析出错。
修正后代码
use std::io; use std::fs::File; use std::io::Read; fn decode_itm<R: io::Read>(mut r: R) -> io::Result<Vec<u8>> { let mut output = Vec::new(); let mut buf = [0u8; 4]; loop { // 读取帧头 match r.read_exact(&mut buf[0..1]) { Ok(_) => {}, Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => break, Err(e) => return Err(e), } let header = buf[0]; // 过滤非刺激端口报文 if (header & 0b11000000) != 0 { continue; } // 提取长度编码和端口号 let len_code = (header >> 5) & 0b11; let port = header & 0b11111; // 仅保留串口打印常用的0端口数据,不需要可删除该判断 if port != 0 { continue; } let len = match len_code { 0 => 1, 1 => 2, 2 => 4, _ => continue, }; // 读取载荷 match r.read_exact(&mut buf[0..len]) { Ok(_) => output.extend_from_slice(&buf[0..len]), Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => break, Err(e) => return Err(e), } // 遇到终止符提前退出,不需要可删除 if output.ends_with(b"\0") { output.pop(); break; } } Ok(output) } fn main() { let mut file = File::open("/tmp/itm.txt").expect("指定路径不存在该文件"); let mut raw_data = Vec::new(); file.read_to_end(&mut raw_data).expect("读取文件失败"); println!("原始十六进制数据: {:x?}", raw_data); let decoded = decode_itm(raw_data.as_slice()).expect("解码失败"); let s = std::str::from_utf8(&decoded).expect("解码结果不是合法UTF-8字符串"); println!("解码后内容: {:?}", s); }
内容的提问来源于stack exchange,提问作者user15692170
相关产品推荐
相关产品推荐

