在嵌入式系统中,日志文件既可以用来监视设备运行状况,也可以用来进行查找错误。很多情况下,我们无法判断是什么造成系统出了问题,更无法准确说出是什么时间出了问题。因为很多问题如引脚弯曲所造成的情况往往是间歇性的甚至根本无法再重复出现的,如果有了日志文件,用户就可以通过它的成功/失败率来确定情况,同时也有一份将所有的问题都详细记录下来的报告,对于那些很难隔离的错误也可以详细的记录下来方便识别。但由于各种原因,它的开发和应用并不普及。本文介绍了怎样在一个嵌入式系统中开发成本较低的日志文件系统。
1 硬件要求
对于一个由中央微处理器控制的设备来说,添加了日志文件就可以在半导体内存记录中保存时间、日期和关键事件的运行结果。通过它,用户就能将特定事件记录下来,以便于监控、改进今后的设备运行。本方法的硬件成本很低,只需要增加一个用来保存日志文件的EEPROM和一个实时时钟。由于这很容易实现,本文不做介绍。
2 软件实现
我们的方法是将日志信息记录在日志文件中,在EEPROM中保存。一旦一个事件被记录下来后,相应事件的代码就会调用日志事件函数,这个函数会与实时时钟的信息一起将相应的信息存储到EEPROM中。由于EEPROM的空间有限,当空间滿了后,最老的数据会被最新的数据代替。
对于日志记录,我们将它们划分为4个级别,分别是无、低级、中级、高级。日志文件可以在同一时间保存不同级别的日志信息。日志信息的级别越高,在EEPROM中所占空间越大,保留的记录条数就越少,同时也要花更多的时间来写入。
设置不同的日志级别是为了方便用户对任一事件改变记录的数目。例如,在使用设备过程中,通常其级别是处于低级的状态,这时用户可以得一些诸如设备何时启动、何时关闭、总体成功/失败率等较为概略性的信息。而当用户希望监控某一特定socket的成功/失败率信息时,就需将级别提升为中级了。而当一个错误反复出现却很难确定时,可将级别调整至高级,这时日志文件会将相应socket的信息、有关的地址和数据都记录下来。
下面列出的是对同一事件的不同记录级别的信息进行记录的代码:
/* 将日志数据从EEPROM复制到RAM中进行更新*/
uint get_log(Log_File_*log_ptr, ushort log_rec_num){
Log_File *find_ptr;
if ((find_ptr =find_log_rec(log_rec_num)) == NULL) return FAIL;
memcpy(log_ptr,find_ptr,find_ptr-<;>log_low.rec_len);
return PASS;
}
一旦一个事件发生,它会被记录到相应级别的数据末尾。由于事件发生所花费的时间通常是在整个事件发生后才结束,所以这不会降低相系统对相应事件的反应时间。
3 日志文件的数据结构
日志文件的数据结构可根据自己系统的具体情况来决定,这里列出我们系统的数据结构:
typedef struct { /* 低级事件的日志记录数据结构 */
ushort rec_num;
uchar event_num;
uchar level;
uchar version;
uchar rec_len;
; /* 设备专用的数据块 */
uchar rec_chksum_med;
uchar rec_chksum_high;
uchar rec_chksum_low;
} Log_Base;
typedef struct{ /* 中级事件的数据结构 */
; /* 设备专用的数据块 */
} Log_Med_Detail;
typedef struct{ /* 高级事件的数据结构 */
; /* 设备的专用数据块 */
} Log_High_Detail;
typedef struct { /* 日志文件的记录定义 */
Log_Base log_low;
Log_Med_Detail log_med;
Log_High_Detail log_high;
} Log_File;
我们列出高级事件的记录,读读者可根据下面的数据得出相应的数据结构来:
Low PV:VERIFY P:5 F:2
TP:5 TF:2 IMI#:003C
SS:1 DW:8 CRC:FOB8
MOD:3 AD:1
Passed Socket(s): 1 3 5 6 7
Failed Socket: 2 Err:Verify
Adx:0 Dev:00 RAM:FF
Failed Socket: 4 Err:Verify
Adx:12 Dev:FA RAM:FF\&]
需要注意的是日志文件的记录还应包含一个校验字节和一个状态字节,这样就可以检查并标记出受损的记录。另外日志文件的不同级别都被设置成了相应的固定大小的块,这样在检查日志文件错误或恢复受损数据时比采用动态大小的块要容易些。
最后用户还需要通过键盘或终端做如下工作:清理日志文件或删除损坏的记录、将日志文件导入计算机、抹掉整个日志文件、读日志文件记录、选择所需的日志事件、放弃选择所需的日志事件、设置日志文件层次等等。
参考文献:
[1] 彭蔓蔓,李浪,徐署华.嵌入式系统导论[M].北京:人民邮电出版社,2008.
[2] 怀特.嵌入式系统设计与实践[M].余水清,译.北京:机械工业出版社,2013.