Posts 某次 debug 过程记录
Post
Cancel

某次 debug 过程记录

1. 故障

服务器上未看到某个节点的数据。

2. 使用伪代码分析节点代码

(分析后发现潜在问题蛮多的)

main 函数

1
2
3
4
5
6
7
8
9
10
初始化硬件
初始化 OS
如果初始化成功{
	使能滴答时钟
	创建 main_thread
	如果创建成功{
		启动 OS (不会返回)
	}
}
loop{}	// 如果前面的流程出错,会运行到这个地方

main_thread:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
剩余发送尝试次数赋初始值
获取序列号
射频驱动初始化
初始化数据缓冲区
loop{
	打印时间
	如果剩余发送尝试次数没变{
		读传感器数据
		封装数据
		打印 封装好的数据
	}
	信道活跃检测,最多三次
	如果检测超时{
		打印 检测超时			// to do:需要处理超时的情况
	} 否则如果检测到信道活跃 {
		打印 信道冲突			// to do:需要处理冲突的情况
	} 否则 {
		打印 信道检测完成
	}
	
	发送数据
	如果发送没有超时{
		打印 发送完成
	} 否则 {
		打印 发送超时			// to do:需要处理发送超时的情况
	}
	
	接收数据
	如果接收完成{
		打印 接收完成
		从缓冲区读数据
		如果读到了数据{
			校验应答消息
			如果校验成功{
				剩余发送尝试次数改为初始值
			} 否则 {
				打印 应答消息无效
			}
			序列号+1
			设置定时唤醒
			停机
		}
		// to do:需要处理没读到数据的情况
	} 否则如果接收超时 {
		如果剩余发送尝试次数不为0{
			剩余发送尝试次数-1
			延时
		} 否则 {
			剩余发送尝试次数改为初始值
			序列号+1
			设置定时唤醒
			停机
		}
	}
	// to do:没有处理以上两种情况之外的情况
}

3. 故障分析过程

(1)捕捉异常信息

虽然网页上没有看到该节点的数据,网关上看到该数据格式有误,且一直收到固定的数据(格式有误,数值未变化)

1
2
[2020-09-21 19:45:58 ERROR gw:original_data_handle_thread] convert from data template failed: d":2,"name":"SN-002","temperature":24.16,"humidity":53.37,"voltage":4.69,"status":0}
[2020-09-21 19:51:05 ERROR gw:original_data_handle_thread] convert from data template failed: d":2,"name":"SN-002","temperature":24.16,"humidity":53.37,"voltage":4.69,"status":0}

完成的数据应该为:

1
{"id":2,"name":"SN-002","temperature":24.16,"humidity":53.37,"voltage":4.69,"status":0}

节点串口打印:

1
2
3
4
5
6
7
8
9
10
time:00:13:17
Cad done.
Tx done.
Rx done.
Error(7)
time:00:18:24
Cad done.
Tx done.
Rx done.
Error(7)

(2)原因分析

a. 数值未变化的原因分析

从节点串口打印看,没有打印数据,即剩余发送尝试次数发生了变化。剩余发送尝试次数只有在接收超时的情况下才会减1,即发生过接收超时。超时后再次发送,应答消息校验未通过,发生了停机。醒来后继续运行,剩余发送尝试次数发生了变化,跳过数据读取,发送、接收,应答消息校验未通过(网关 mcu 功能开发不全,应答消息一直无效),停机,醒来…一直这样循环。

b. 数据不完整的可能性分析

(1)网关 mcu

另一个节点的数据一直是正常的,网关 mcu 出问题的概率不大

(2)网关 linux 侧的应用程序(使用 rust 编写)

另一个节点的数据一直是正常的,这里出问题的概率也不大

(3)节点

封装好的数据前面有四个字节的头,包含网关地址;节点上 id 是调用 strcpy 复制的,未复制完全的概率不大;网关收到了数据,说明头校验通过了,发送这块没问题。 但是发送和接收用的是同一块缓冲区,接收一次数据后就会有问题。

发送的数据:

1
{0xff, 0xff, 0x00, 0x00,  '{',  '"',  'i', 'd', ...}

接收数据后(前四个字节未网关发过来的头,应该还是 {0xff, 0xff, 0x00, 0x00}):

1
{____, ____, ____, ____, 0x00, 0x01, 0x00, 'd', ...}

数据的前三个字节都是不可见字符,用 rust 实现的网关应用程序收到数据后,转换出来的字符串应该会有问题,很可能从 ‘d’ 开始。

验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
    let a: [u8; 4] = [0, 1, 0, 100];
    let b: [u8; 4] = [123, 22, 105, 100];
    let a_slice: &[u8; 4] = &a;
    let b_slice: &[u8; 4] = &b;
    let r = String::from_utf8(a_slice[0..4 as usize].to_vec());
    if let Ok(string) = r {
        println!("a: {}", string)
    }

    let r = String::from_utf8(b_slice[0..4 as usize].to_vec());
    if let Ok(string) = r {
        println!("b: {}", string)
    }
}

输出:

1
2
a: d
b: {id
This post is licensed under CC BY 4.0 by the author.