1、背景
目前,大部分底层嵌入式控制板由于资源的限制,缺少一个可回看的日志系统,往往bug发生后,调试人员需要接串口打印并让问题复现。而实际工况往往比较复杂,难以在第一时间获取设备状态以及相关参数信息。
2 、概述
ESP32片上自带一块较大的flash,目前S3系列可选8~32M Quad SPI flash,这对一般的程序存储来说戳戳有余,而本地文件系统恰巧需要一块足够大的flash存储日志。ESP SPIFFS 是一个用于 SPI NOR flash 设备的嵌入式文件系统,支持磨损均衡、文件系统一致性检查等功能。目前,SPIFFS 尚不支持目录,但可以生成扁平结构。
3、自定义日志系统相关函数
日志写入函数
在实时打印函数内添加日志写入,如果指定路径文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留);
void log_write_send(const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen(LOG_FILE_PATH, "a");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
vfprintf(f, format, arg);
fclose(f);
va_end(arg);
}
可在系统关键位置或自定义位置添加日志打印和写入,同时记录需要写入的字符串,字符串内容:1、系统参数;2、自定义标志;3、时间戳;
日志读取函数
通过对指定路劲的文件进行分次读取,并通过无线方式发送出去。
void log_read_send(const char *format, ...)
{
char line[1000];
FILE *f = fopen(LOG_FILE_PATH, "r");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}
ESP_LOGI(TAG, "Read from file:");
while (feof(f) == 0)
{
fread(line, 1, sizeof(line), f);
ESP32_LOG_publish(line);
memset(line, 0, sizeof(line));
}
fclose(f);
}
基于WIFI-MQTT无线发送日志
日志分次读取后的字符串转换为JSON格式,利用ESP32自带的WIFI,分段发布在指定的mqtt主题下,这样电脑可无线获取板子一段时间内的日志信息。
void ESP32_LOG_publish(char *log_buffer)
{
int msg_id = 0;
cJSON *root = cJSON_CreateObject();
cJSON_AddItemToObject(root, "log_esp32", cJSON_CreateString(log_buffer));
msg_id = esp_mqtt_client_publish(mqtt_client, TOPIC_LOG_ESP32, log_buffer, 0, 1, 0);
cJSON_Delete(root);
}
日志文件大小获取
SPIFFS 只能稳定地使用约 75% 的指定分区容量,根据自己对flash空间的规划需设定最大值判断,到达最大值对日志文件清零。
long long getFileSize(char *files)
{
long long size;
FILE *fp = fopen(files, "rb+");
if (fp == NULL)
{
printf("Open File Error");
exit(0);
}
// 定义pos
fpos_t pos;
// 获取文件指针,写入pos
fgetpos(fp, &pos);
// 文件指针指向末尾
fseek(fp, 0, SEEK_END);
// 获取文件指针到文件头部的字节大小
size = ftell(fp);
// 文件指针还原
fsetpos(fp, &pos);
// 释放文件
fclose(fp);
return size;
}
日志读取流程
4、实际测试
这里利用第三方软件MQTTX下发读取指令,同时订阅/log_esp32,获取日志信息。
5、总结
这套日志系统适用于物联网领域的单片机,可替换系统的不同打印等级的日志函数用于记录bug,并可以在自定义位置对关键参数进行定时记录,方便检查以及调试。