嵌入式LOG记录

该代码实现了一个在内部Flash中记录日志并在条件满足时导出到USB设备的功能。它包括日志擦除、写入、读取和日志数量管理的函数。日志数据结构包含时间戳和特定事件信息。系统使用FF文件系统进行文件操作,并且有读取和写入文件的示例。
摘要由CSDN通过智能技术生成

log先记录在内部flash,然后导出到u盘

/*
 * user_flash.c
 *
 *  Created on: Jun 2, 2023
 *      Author: Administrator
 */
#include "user_flash.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "type.h"
#include "LLCC68_example_recive.h"

#include "ff.h"
#include "file.h"
#include "media_play_api.h"

volatile int LogNum = 0;//log 数目

#define LOG_TIME_OUT (5)
/* snail 总共32K,一块4K,总共8块,实际只用前4块(16K)*/
#define LOG_BAK_OFFSET		(AUDIO_EFFECT_ADDR)	// BP 信息在Flash中的起始地址
#define LOG_BAK_CNT			(8)					// BP 信息存储区域个数,小于8
#define LOG_BLOCK_SIZE		(4096)				// BP 信息存数区域大小

//第1块只存放 logBak 与 logLen
//第234块存放LOG
static uint32_t logBak = 1;//LOG当前存放的第几块
static uint32_t logLen = 0;//LOG当前块的长度

/* 擦除32K */
static void LogFlashErase(void)
{
	int i;

	for(i=0; i<LOG_BAK_CNT; i++)
	{
		/* SECTOR_ERASE 擦除一个扇区,一个扇区4096 byte */
		SpiFlashErase(SECTOR_ERASE, (LOG_BAK_OFFSET + i * LOG_BLOCK_SIZE) /4096 , 1);
		//APP_DBG("Erase Flash ok (%d)\n", i);
	}
}

/* 设置 logBak logLen */
static void logLenlogBakSet(uint32_t *bak, uint32_t *len)
{
	SpiFlashErase(SECTOR_ERASE, (LOG_BAK_OFFSET + 0 * LOG_BLOCK_SIZE) /4096 , 1);

	SpiFlashWrite(LOG_BAK_OFFSET, (uint8_t*)bak, 4, LOG_TIME_OUT);
	SpiFlashWrite(LOG_BAK_OFFSET+4, (uint8_t*)len, 4, LOG_TIME_OUT);
}
/* 获取 logBak logLen */
static void logLenlogBakGet(uint32_t *bak, uint32_t *len)
{
	uint8_t buff[10] = {0};

	SpiFlashRead(LOG_BAK_OFFSET, buff, 10, LOG_TIME_OUT);

	log_hex(buff, 10);

	*bak = (buff[0] & 0x000000FF) | (((buff[1]) << 8) & 0x0000FF00) | (((buff[2]) << 16) & 0x00FF0000) | (((buff[3]) << 24) & 0xFF000000);
	*len = (buff[4] & 0x000000FF) | (((buff[5]) << 8) & 0x0000FF00) | (((buff[6]) << 16) & 0x00FF0000) | (((buff[7]) << 24) & 0xFF000000);

	/* 处理第一次 */
	if(*bak < 1 || *bak > 3)//logBak 只能是123
	{
		APP_DBG("[FLASH] 处理第一次\n");
		*bak = 1;
		*len = 0;
	}
}
//长度必须为8
static void LogFlashWrite(uint8_t* Buffer, uint32_t Length)
{
	logLenlogBakGet(&logBak, &logLen);

	/* 判断当前块是否已经满了,满了需要抹掉新的块 */
	if(logLen >= 4095)
	{
		APP_DBG("[FLASH] 当前块已满\n");
		logLen = 0;
		logBak++;

		/* logBak只能是123 */
		if(logBak >= 4) logBak = 1;

		SpiFlashErase(SECTOR_ERASE, (LOG_BAK_OFFSET + logBak * LOG_BLOCK_SIZE) /4096 , 1);
	}
	APP_DBG("[FLASH] logBak = %d logLen = %d\n", (int)logBak, (int)logLen);
	/* 写入日志 */
	SpiFlashWrite(LOG_BAK_OFFSET + logBak * LOG_BLOCK_SIZE + logLen, Buffer, Length, LOG_TIME_OUT);

	/* 写入长度 */
	logLen += Length;

	logLenlogBakSet(&logBak, &logLen);
}

/** 记录LOG
 * 	ch 		车道
 * 	event 	事件
 * */
void LogRecord(uint8_t ch, uint8_t event)
{
    uint8_t str[8] = {0};

    /* 2023年,只要23 */
    str[0] = (uint16_t)gRtcTime.Year % 100;

    str[1] = (uint8_t)gRtcTime.Mon;
    str[2] = (uint8_t)gRtcTime.Date;
    str[3] = (uint8_t)gRtcTime.Hour;
    str[4] = (uint8_t)gRtcTime.Min;
    str[5] = (uint8_t)gRtcTime.Sec;
    str[6] = ch;
    str[7] = event;

    log_hex(str, 8);

    LogFlashWrite(str, 8);

    LogNumGet();
}



/** 读取全部LOG
 * */
void LogRead(void)
{
	int log_number = 0;//写入的时候统计log行数
	int i, j;
	uint8_t logbuff[8];//临时LOG缓冲区
	uint32_t logbak;//临时变量

	FIL file;          				/* 文件对象 */
	FRESULT f_res;     				/* 文件操作结果 */
	UINT fnum;         				/* 文件成功读写数量 */
	UINT WriteLen = 0;				/* 写缓冲区 的长度 */
	BYTE WriteBuffer[128] = {0};	/* 写缓冲区 */

	f_res = f_open(&file, "0:log.txt", FA_CREATE_ALWAYS | FA_WRITE);
	if(f_res != FR_OK) return;

	logLenlogBakGet(&logBak, &logLen);//先获取当前的位置,在第几块,log长度
	logbak = logBak;

	/* 1 2 3 假如当前在第1块, 那么就要 2 3 1 遍历输出  */
	/* 1 2 3 假如当前在第2块, 那么就要 3 1 2 遍历输出  */
	for(j = 0; j < 3; j++)//总共有三块,循环三次
	{
		if(++logbak == 4) logbak = 1;//第3块结束,到第4块的时候要回到第1块
		APP_DBG("logbak = %d\n", (int)logbak);

		for(i = 0; i < 512; i++)//一个块4096BYTE,一次读取8,需要读取512次  loglen>>3 == loglen/8
		{
			SpiFlashRead(LOG_BAK_OFFSET + logbak * LOG_BLOCK_SIZE + i*8, logbuff, 8, LOG_TIME_OUT);

			if(logbuff[0] == 0xFF && logbuff[1] == 0xFF && logbuff[2] == 0xFF && logbuff[3] == 0xFF) break; //如果全是F 就是没数据,跳出(判断4个可以证明了)

			/*2023/06/05 16:21:05 *///len = 20
		    sprintf((char*)WriteBuffer, "%04d: 20%02d/%02d/%02d %02d:%02d:%02d ", ++log_number,
						(uint16_t)logbuff[0],
						(uint8_t)logbuff[1],
						(uint8_t)logbuff[2],
						(uint8_t)logbuff[3],
						(uint8_t)logbuff[4],
						(uint8_t)logbuff[5]);

//			log_hex(logbuff, 8);
			switch(logbuff[7])
			{
				case 1: WriteLen = sprintf((char*)WriteBuffer+26, "收费站%02d车道有行人误闯!\n", logbuff[6]); break;//行人误闯
				case 2: break;
				default: break;
			}
//			APP_DBG("%s\n", WriteBuffer);
			f_write(&file, WriteBuffer, WriteLen+26, &fnum);
		}
	}

	/* 不再读写,关闭文件 */
	f_close(&file);
}
/* ===============file=============== */


void logFlieWrite(void)
{
	FIL file;          /* 文件对象 */
	FRESULT f_res;     /* 文件操作结果 */
	UINT fnum;                      /* 文件成功读写数量 */
	BYTE ReadBuffer[1024] = {0};    /* 读缓冲区 */
	BYTE WriteBuffer[] =            /* 写缓冲区 */
	    "哈哈哈小明\n";

	f_res = f_open(&file, "0:log.txt", FA_CREATE_ALWAYS | FA_WRITE);
	if(f_res != FR_OK)
	{
		APP_DBG("open file error : %d\r\n", f_res);
		return;
	}
	else
	{
		APP_DBG("open file sucess!!! \r\n");
	}

	f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &fnum);
	if(f_res == FR_OK)
	{
		APP_DBG("write file sucess!!! (%d)\n", fnum);
		APP_DBG("write Data : %s\r\n", WriteBuffer);
	}
	else
	{
		APP_DBG("write file error : %d\r\n", f_res);
	}

	/* 不再读写,关闭文件 */
	f_close(&file);
}

void LogTask(void)
{
	//LogFlashErase();
#if 0/*logBak logLen 读写测试*/
	uint32_t a, b;

	logBak++;
	logLen++;
	APP_DBG("logBak = %d logLen = %d\n", logBak, logLen);
	logLenlogBakSet(&logBak, &logLen);

	logLenlogBakGet(&a, &b);
	APP_DBG("logBak = %d logLen = %d\n", (int)a, (int)b);
#endif

#if 0/*写log测试*/
	static int i = 0;
	i++;
	for(i = 0; i < 128; i++)
		LogRecord(i, 1);
#endif

#if 0/*读log测试*/
	LogRead();
#endif

#if 0/*写文件测试*/
	logFlieWrite();
#endif
}

//bool get_user_addr(void)
//{
//	FIL file;          /* 文件对象 */
//	FRESULT f_res;     /* 文件操作结果 */
//	UINT fnum;                      /* 文件成功读写数量 */
//	BYTE ReadBuffer[32] = {0};    /* 读缓冲区 */
//
//	f_res = f_open(&file, "0:addr_user.txt", FA_READ);
//	if(f_res != FR_OK)
//	{
//		APP_DBG("open file error : %d\r\n", f_res);
//		return FALSE;
//	}
//	else
//	{
//		APP_DBG("open file sucess!!! \r\n");
//	}
//
//	f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);
//	if(f_res == FR_OK)
//	{
//		APP_DBG("read file sucess!!! (%d)\n", fnum);
//		APP_DBG("read Data : %s\r\n", ReadBuffer);
//
//	    userAddr = atoi(ReadBuffer);//存放命令后面的数字
//	    DBG("OK userAddr = %d\n", userAddr);
//	}
//	else
//	{
//		APP_DBG("read file error : %d\r\n", f_res);
//	}
//
//	LogNumGet();
//
//	/* 不再读写,关闭文件 */
//	f_close(&file);
//	return TRUE;
//}

void LogNumGet(void)
{
	int j;
	uint8_t logbuff[8];//临时LOG缓冲区
	uint32_t logbak;//临时变量
	uint32_t loglen;//临时变量

	logLenlogBakGet(&logBak, &logLen);//先获取当前的位置,在第几块,log长度
	logbak = logBak;
	loglen = logLen;

	/* 访问下一块 */
	if(++logbak == 4) logbak = 1;//第3块结束,到第4块的时候要回到第1块

	SpiFlashRead(LOG_BAK_OFFSET + logbak * LOG_BLOCK_SIZE, logbuff, 8, LOG_TIME_OUT);

	if(logbuff[0] == 0xFF && logbuff[1] == 0xFF && logbuff[2] == 0xFF && logbuff[3] == 0xFF)//如果全是F 就是没数据(判断4个可以证明了)
	{
		logbak = logBak;
		/* 访问上一块 */
		if(--logbak == 0) logbak = 3;//第3块结束,到第4块的时候要回到第1块
		SpiFlashRead(LOG_BAK_OFFSET + logbak * LOG_BLOCK_SIZE, logbuff, 8, LOG_TIME_OUT);
		if(logbuff[0] == 0xFF && logbuff[1] == 0xFF && logbuff[2] == 0xFF && logbuff[3] == 0xFF)//如果全是F 就是没数据(判断4个可以证明了)
		{
			LogNum = loglen>>3;
		}
		else
		{
			LogNum = 512 + (loglen>>3);
		}
	}
	else
	{
		LogNum = 1024 + (loglen>>3);
	}

}
/*
 * user_flash.h
 *
 *  Created on: Jun 2, 2023
 *      Author: Administrator
 */

#ifndef BT_AUDIO_APP_SRC_USER_USER_FLASH_H_
#define BT_AUDIO_APP_SRC_USER_USER_FLASH_H_

#include "type.h"
#include "flash_config.h"
#include "spi_flash.h"
#include "debug.h"
#include "STR7565.h"

extern void LogRecord(uint8_t ch, uint8_t event);
extern void LogRead(void);

extern void LogTask(void);
#endif /* BT_AUDIO_APP_SRC_USER_USER_FLASH_H_ */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值