关于串口调试自动化的解决方案

问题

在使用串口调试过程中,需要手动输入执行命令,交互性输入,以及等待执行结果。基本所有的信息都在 tty 中串行的进行显示。痛点有下面几个

  • 重复命令手动输入执行
  • 交互性输入
  • 等待执行信息,不能自动保存到文件
  • 串口调试环境本身edit 便利性

基于以上的问题,需要存在需求:

  • 可以将执行命令存放脚本中,而且可以去调用执行
  • 可处理交互性输入
  • 对于执行命令输出可以保存到 log 文件

基本方案

  1. 基于 SecureCRT

    SecureCRT 脚本,使用 python 语言

    优点:

    • GUI 界面,操作直观
    • python syntax 语法特性支持强大

    缺点:

    • SecureCRT 过重,本身安装麻烦
    • 仍然需要基本交互,SecureCRT 内调用脚本
    • 与 jenkins 的集成
  2. 基于 Terminal 环境

    首先要解决的是串口环境,这里使用 picocom 命令行工具,类似的有 minicom 等。

    其次,针对需要交互行输入,使用 Expect 处理,Expect 基于 TCL (Tool control language)

    最后,得到的 .expect 脚本可以通过 Jenkins pipeline 进行调用。

    优点:

    • 轻量化,可通过命令行安装
    • 所有过程都在 Terminal 操作
    • 集成到 Jenkins,完全支持自动化流程

    缺点:

    • picocom 在功能性方面较弱

##实际解决

针对上面两种方案,如果是非重复性调试,使用前者上手更快。

如果有需要多次重复性,或者自动化测试需求,选择后者。

下面给出使用 Expect 的一个 demo:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/expect 
# -d: debug mode

# expect config
set timeout 30
log_file test-expect.log

# picocom config
set baudrate "115200"
set device "/dev/ttyUSB0"
set prompt "=>"

# function define
set interval 5
set iter_cnt 10

proc start_xvr_debug { prompt } {
send "xvr_client_dbus\r"
expect $prompt
}

proc test_switch_channel_display { iter_cnt interval prompt } {

for { set i 1 } { $i < $iter_cnt } { incr i 1 } {
send "switch_channel_display -cam 0 -ch 0 -onoff 1\r"
expect $prompt
exec sleep $interval

send "switch_channel_display -cam 0 -ch 0 -onoff 0\r"
expect $prompt
exec sleep $interval

send "switch_channel_display -cam 0 -ch 1 -onoff 1\r"
expect $prompt
exec sleep $interval

send "switch_channel_display -cam 0 -ch 1 -onoff 0\r"
expect $prompt
exec sleep $interval
}
}

proc test_start_stop_pipeline { iter_cnt interval prompt } {
for { set i 1 } { $i < $iter_cnt } { incr i 1 } {
send "stop_pipeline /dev/xvr_pipeline-0\r"
expect $prompt
exec sleep $interval

send "stop_pipeline /dev/xvr_pipeline-1\r"
expect $prompt
exec sleep $interval

send "start_pipeline /dev/xvr_pipeline-0\r"
expect $prompt
exec sleep $interval

send "start_pipeline /dev/xvr_pipeline-1\r"
expect $prompt
exec sleep $interval
}
}

spawn picocom -b $baudrate $device
expect "Terminal ready\r"
send "\r"

# send "xvr_client_dbus\r"
# expect $prompt

start_xvr_debug $prompt
test_switch_channel_display $iter_cnt $interval $prompt
# test_start_stop_pipeline $iter_cnt $interval $prompt

expect eof
# interact
wait

在具体使用中遇到的有几个小坑:

  1. 集成到 jenkins 时,jenkins 用户无法获得 /dev/ttyUSB0 权限。
  2. sudo 执行 Expect 脚本进程 kill

详情见尾注意小节。

参考

注意

  1. 关于 jenkins 用户无法获取 /dev/ttyUSB0 权限

    在这里最好不要直接使用 sudo ,使用 root 权限执行的坏处在于,当你想要中断 expect 脚本时,也必须使用 root 权限。并且在集成到 Jenkins 时,jenkins 用户起了 root 权限的进程,在中断 job 的时候。expect 任然在 jenkins node 上继续执行。

    解决的方案是将 jenkins 用户加入拥有 dev 设备权限的用户组。

    1
    sudo usermod aG dialout jenkins
  2. sudo 执行的 expect 进程kill

    sudo killall -u USER expect