RT-Thread-ulog输出到flash-基于FlashDB

ULOG_TSDB搭建详解

一、依赖

1、打开FAL,挂载好片内/片外Flash,设置分区表

2、打开FlashDB、ulog组件

3、使能硬件RTC

二、实现

1、后端设备初始化

主要实现原理:把tsdb作为ulog输出的后端设备,实现保存日志数据到flash中

仿照console_be.c文件实现tsdb_be.c,参考官方文档ulog日志-日志后端

console_be.c是实现把控制台作为后端设备输出ulog数据

主要需要实现ulog_tsdb_backend_init函数和ulog_tsdb_backend_output函数,再通过INIT_ENV_EXPORT导出命令在系统初始化时执行

tsdb_be.c实现如下👇

#include <rthw.h>
#include <ulog.h>

//需要先在rtconfig.h中定义该宏
#ifdef ULOG_BACKEND_USING_TSDB

#if defined(ULOG_ASYNC_OUTPUT_BY_THREAD) && ULOG_ASYNC_OUTPUT_THREAD_STACK < 384
#error "The thread stack size must more than 384 when using async output by thread (ULOG_ASYNC_OUTPUT_BY_THREAD)"
#endif

extern int ulog_tsdb_init(void );
extern void ulog_tsdb_append(const char *str,size_t len);

static struct ulog_backend tsdb;

void ulog_tsdb_backend_output(struct ulog_backend *backend, rt_uint32_t level, const char *tag, rt_bool_t is_raw,
        const char *log, size_t len)
{
		ulog_tsdb_append(log,len);		
}

int ulog_tsdb_backend_init(void)
{
    ulog_init();
    tsdb.output = ulog_tsdb_backend_output;
    ulog_tsdb_init();
    ulog_backend_register(&tsdb, "tsdb", RT_TRUE);

    return 0;
}
INIT_ENV_EXPORT(ulog_tsdb_backend_init);

#endif /* ULOG_BACKEND_USING_TSDB */

2、TSDB功能实现

主要实现初始化、追加、查询(全部/日期区间)、清除功能,并把查询、清除功能导出到MSH命令中

①tsdb初始化
//在tsdb_be.c的后端设备初始化时调用
int ulog_tsdb_init(fdb_tsdb_t tsdb);
//该函数主要调用官方API👇
//参数意义:TSDB结构体、TSDB分区名称、挂载分区名称、时间戳回调函数、用户自定义数据
fdb_tsdb_init(&_global_tsdb, "log", "ts_area", get_hw_rtc_time, FDB_MAX_TSL_LEN, NULL);
//注意:移植时需要根据实际情况修改挂载分区名称 "ts_area"
//get_hw_rtc_time : 调用硬件RTC的API获取当前实时时间戳
②追加日志数据
//初始化为后端设备输出函数(在tsdb_be.c中实现)
//str:ulog字符串数据  len:ulog字符串长度
void ulog_tsdb_append(const char *str,size_t len);
//主要调用官方API👇
fdb_tsl_append(&_global_tsdb, fdb_blob_make(&blob, str, len));
//实现后日志将会保存到flash中
③查询日志数据
全部查询

直接调用APIfdb_tsl_iter(&_global_tsdb, query_cb, &_global_tsdb);即可

根据日期区间查询

1、需要使用MSH_CMD_EXPORT把命令到处到MSH中,用户输入想要查询的日期区间

2、对输入的参数进行处理👇

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oA3Gmh1u-1615639547119)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\1615260645666.png)]

argv[]数据转成整型,初始化struct tm结构体,再将其转换为time_t格式

最后调用fdb_tsl_iter_by_time(&_global_tsdb,from_time,to_time,query_cb,&_global_tsdb);API即可查询输入的区间内的日志数据

还需要实现查询回调函数

把查询到的日志数据打印到控制台

static bool query_cb(fdb_tsl_t tsl, void *arg)
{
    struct fdb_blob blob;
    char str[FDB_MAX_TSL_LEN];
    fdb_tsdb_t db = arg;				
    fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, str, FDB_MAX_TSL_LEN)));
    FDB_INFO("queried a LOG: %s", str);
    return false;
}
④清空日志数据

直接调用APIfdb_tsl_clean(&_global_tsdb);即可

详细代码实现如下👇

#include <flashdb.h>
#include <string.h>
#include <stdlib.h>

#ifdef FDB_USING_TSDB

#define FDB_LOG_TAG "[tsdb log]"
#define FDB_MAX_TSL_LEN 256

static bool query_cb(fdb_tsl_t tsl, void *arg);
struct fdb_tsdb _global_tsdb = {0};
struct fdb_kvdb _global_kvdb = {0};

static fdb_time_t get_hw_rtc_time(void)
{
    time_t t = 0;
    time(&t);
    return t;
}

int ulog_tsdb_init(fdb_tsdb_t tsdb)
{
	fdb_err_t result;
	result = fdb_tsdb_init(&_global_tsdb, "log", "ts_area", get_hw_rtc_time, FDB_MAX_TSL_LEN, NULL);
	return result;
}

void ulog_tsdb_append(const char *str,size_t len)
{
		struct fdb_blob blob;
		fdb_tsl_append(&_global_tsdb, fdb_blob_make(&blob, str, len));
}

void ulog_add_tsl(int argc, char**argv)
{
	struct fdb_blob blob;
	if(argc >= 2)
	{
		fdb_tsl_append(&_global_tsdb, fdb_blob_make(&blob, argv[1], sizeof(argv[1])));
	}
}
MSH_CMD_EXPORT(ulog_add_tsl , add tsl);

static void ulog_tsdb_clr(void){
    
    fdb_tsl_clean(&_global_tsdb);
}
MSH_CMD_EXPORT(ulog_tsdb_clr , clean tsdb);

void ulog_tsdb_query(void)
{
		fdb_tsl_iter(&_global_tsdb, query_cb, &_global_tsdb);
}
MSH_CMD_EXPORT(ulog_tsdb_query,get all ulog from tsdb);

int ulog_tsdb_query_by_time(int argc, char**argv){
    if(argc >= 10){
        struct tm tm_from = { .tm_year = atoi((const char*)argv[1]) - 1900, 
															.tm_mon  = atoi((const char*)argv[2]) - 1, 		
															.tm_mday = atoi((const char*)argv[3]), 				
															.tm_hour = atoi((const char*)argv[4]), 				
															.tm_min  = atoi((const char*)argv[5]),					
															.tm_sec  = 0};								
        struct tm tm_to   = { .tm_year = atoi((const char*)argv[1]) - 1900, 
															.tm_mon  = atoi((const char*)argv[6]) - 1, 
															.tm_mday = atoi((const char*)argv[7]), 
															.tm_hour = atoi((const char*)argv[8]), 
															.tm_min  = atoi((const char*)argv[9]), 
															.tm_sec  = 0};
        //转换时间格式
        time_t from_time = mktime(&tm_from), to_time = mktime(&tm_to);
        FDB_INFO("from time = %ld,  to time = %ld\n",from_time,to_time);
        fdb_tsl_iter_by_time(&_global_tsdb,from_time,to_time,query_cb,&_global_tsdb);
    }else {
			rt_kprintf("Please input var:'time section [from_ymdh to_ymdh]'\n");
			rt_kprintf("sample : ulog_tsdb_query_by_time 2018 8 8 8 8 9 9 9 9\n");
			rt_kprintf("mean : query from 2018-08-08-8:00 to 2018-09-09-9:00\n");
		}
    return 0;
}
MSH_CMD_EXPORT(ulog_tsdb_query_by_time , tsdb search by time Please input var:time section [from_ymdh to_ymdh]);

static bool query_cb(fdb_tsl_t tsl, void *arg)
{
    struct fdb_blob blob;
    char str[FDB_MAX_TSL_LEN];
    fdb_tsdb_t db = arg;				
    fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, str, FDB_MAX_TSL_LEN)));
    FDB_INFO("queried a LOG: %s", str);
    return false;
}

三、测试

初始化成功

在这里插入图片描述

查询所有日志

日志在main函数中每20s增加一条

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKCT8ouj-1615639547129)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\1615261410234.png)]

根据时间查询日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q407sWxa-1615639547134)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\1615261464705.png)]

查询2021-3-9-11:35 到 2021-3-9-11:40产生的日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0png28D-1615639547137)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\1615261591633.png)]

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
概述随着物联网应用的不断发展,传统的传输技术在各个物联网行业应用方面渐渐不能满足我们的需求,传统的局域网技术,如2.4GHz的WiFi,蓝牙、Zigbee等,以及传统广域网技术2G/3G/4G等无线技术,不能同时兼顾远距离和低功耗。直到在低功耗广域网(Low Power Wide Area Network, LPWAN)技术出现后,能在保证更远距离的通信传输的同时,最大限度的降低功耗,节约传输成本。 本应用使用ART-PI开发板,NUCLEO-L452开发板以及本人自制的扩展板,组成LORA采集端和接收转发端,即使在条件恶略的环境下也能采集数据并通过LORA传送接收并转发至云平台. 开发环境硬件:ART-PI开发板NUCLEO-L452开发板 LORA采集扩展板(安信可Ra-02,DHT11) LORA接收扩展板(安信可Ra-02,W5500,sp485) RT-Thread版本:RT-Thread4.03(ART-PI开发板)RT-Thread4.02(NUCLEO-L452开发板) 开发工具及版本:RT-ThreadStudio V2.0 STM32CuBeMx V6.1.0 RT-Thread使用情况概述内核部分:主要使用了线程管理 时钟管理 组件部分:FinSH控制台,netdev网卡,SAL套接字抽象层,ulog日志 软件包部分:cjson webclient,pahomqtt,fal,wiznet,dhtxx 硬件框架采集端:简单的LORA模组,通过SPI跟板卡通信,以及一个可控LDO和AHT10和BH1750,以LDO控制AHT10和BH1750以达到低功耗的效果. 接收端:一个LORA模组,一个W5500芯片,SPI通信,以及一个SP485. 主要部分就是LORA模组以及W5500,本设计使用立创EDA设计,W5500参考自立创官方团队. 软件框架说明ART-PINUCLEO-L452软件模块说明ART-PI(接收端),上电自动初始化LORA和W5500,等待W5500连接上网络,这里通过判断网卡的状态,当link_up状态后,开始连接mqtt服务器,就可以把LORA接受的数据通过MQTT发送至平台. NUCLEO-L452(采集端),上电初始化软件IIC,直接采集同一总线下AHT10和BH1750的数据,并通过LORA直接发送出去.(备注:因时间关系,采集端的低功耗并没有做,年前估计没时间完善了,以后有时间继续完善) 演示效果视频展示: 比赛感悟这次比赛又学到了不少东西,最主要的就是I2C总线设备和netdev 网卡,刚开始板载WIFI使用时无法使用W5500,因为默认网卡的原因,后来查询RT-Thread 文档中心,看看API和示例,轻松解决.还有就是使用I2C总线设备,刚开始一直想要使用硬件IIC和软件包去驱动AHT10和BH1750,后来发现软件IIC加PIN设备轻松解决,对着文档中心的例子,轻松举一反三出BH1750的程序.所以感觉RT-Thread的文档是真的全乎,所有自己解决不了的东西文档中心都有.但很遗憾的是这次由于出差的原因并没能很完美的展现出来作品,其中ART-PI扩展板上的485并没写到程序中,IWIFI也没应用到(现在是以太网),采集端的低功耗也没有做,年后一定把晚上出来!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值