You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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
解决方案

错误原因

  1. 解析逻辑不符合ITM帧格式规范:你直接将整个帧头字节作为长度参数计算,ITM刺激端口报文的头字节低5位是端口号,仅高3位为长度编码,错误的长度计算会生成超大的读取长度,直接触发EOF报错。
  2. 二进制数据先转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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 05:18:01