/*=====================================TINYLog====================================================== **用于单片表的轻量级紧凑型记录队列,目的是能够实现静态的添加记录并查找记录,但是并不关系内部的数据内容与长度 **由于是队列方式每次更新插入记录都只会将最旧的记录清除,很适合用于历史功能类的相关记录工作 ** **由于只是用于支持单片机的,所以支持的缓冲大小只要65K,同时单条消息只到255长度,这也是根据现实情况来考量的 ,以此为基础, **也限制了最大的条目数为65K **版本V0.1.0 **author : LXZ **history: **19.12.07 LXZ 编写第一个版本 **19.12.12 LXZ 调试完毕,去掉多余接,口实现预计功能 =====================================================================================================*/ #include "TinyLog.h" #include "MathHelper.h" #include /*================================================================================================ * 保存的数据结构 * | 标志位 ’T' 'L' 两字节 * | 第一条数据开始位置 两字节 * | 最后一调数据开始位置 两字节 * | 总记录数 两字节 * | 预留功能到16字节 * | 数据缓冲 N字节 * | CRC两字节 ==================================================================================================*/ typedef struct { unsigned char flag1; unsigned char flag2; unsigned short first_index; unsigned short last_index; unsigned short total; unsigned short res[4]; } tiny_log_head_t; /** * 通过缓冲初始化一个记录,缓冲必须包含有效的记录 * * @author xuzhenglim:276137500 (2019-12-7) * * @param log * @param buf * @param size */ void tiny_log_init(tiny_log_t *log, void *buf, int size) { unsigned char *dat = (unsigned char *)buf; //判断是否存在有效的记录 if (mh_crc16_calc(buf, size) == 0 && dat[0] == 'T' && dat[1] == 'L') { //存在有效的记录,开始解析记录的数据 log->log = &dat[sizeof(tiny_log_head_t)]; log->size = size - sizeof(tiny_log_head_t) - 2; log->first = dat[2] + (dat[3] << 8); log->last = dat[4] + (dat[5] << 8); log->total = dat[6] + (dat[7] << 8); log->buf = dat; log->cur_site = log->first; log->last_index = 0; } else { //存在有效的记录,开始解析记录的数据 log->log = (void *)((unsigned int)buf + sizeof(tiny_log_head_t)); log->size = size - sizeof(tiny_log_head_t) - 2; log->first = 0; log->last = log->first; log->total = log->total; log->buf = (unsigned char *)buf; log->cur_site = log->first; log->last_index = 0; } } /** * 清空记录 * * @author xuzhenglim:276137500 (2019-12-7) * * @param log */ void tiny_log_clear(tiny_log_t *log) { log->first = 0; log->last = 0; log->total = 0; log->idle_size = log->size; log->cur_site = log->first; } /** * 查找下一个 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ int tiny_log_foreach_entry(tiny_log_t *log) { if (log->total > 0 && (log->last_index + 1) < log->total) { int size = 0; int start = 0; if (log->last_index < 0) { log->last_index = 0; log->cur_site = log->first; } else { log->last_index++; log->cur_site = log->cur_site + log->log[log->cur_site] + 2; if (log->cur_site >= log->size) { log->cur_site -= log->size; } } size = log->log[start]; return size; } return -1; } /** * 读取当前记录下的标志 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log * @param log_flg * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ int tiny_log_read_type(tiny_log_t *log,char * log_flg) { if (log->last_index >= 0 && log->total > 0) { int start = log->cur_site + 1; if (start >= log->size) { start -= log->size; } *log_flg = log->log[start]; return log->log[log->cur_site]; } return -1; } /** * 读取记录 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log * @param buf * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ int tiny_log_read_log(tiny_log_t *log,void * buf) { if (log->last_index >= 0 && log->total > 0) { unsigned char *dat = (unsigned char *)buf; int start = log->cur_site + 2; int size = log->log[log->cur_site]; if (start >= log->size) { start -= log->size; } if (size > 0) { if ((start + size) <= log->size) //可以单次读完 { memcpy(dat, &log->log[start],size); } else { //单次无法复制完的情况 memcpy(dat, &log->log[start], log->size - start); memcpy(dat, &log->log[0], start + size - log->size); } } return size; } return -1; } /** * 定位到对应编号下的记录 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log * @param index * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ int tiny_log_index(tiny_log_t * log, unsigned short index) { if (index < log->total) { int start = log->first; while (index > 0) { index--; start = start + log->log[start] + 2; if (start >= log->size) { start -= log->size; } } log->cur_site = start; log->last_index = index; return log->log[start]; } return -1; } /** * 在执行快读读取接口的时候必须先调用该接口,用于无效化上一次查找状态 * * @author xuzhenglim:276137500 (2019-12-11) * * @param log * @param log_flg * @param buf * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ void tiny_log_beign_read(tiny_log_t * log) { log->last_index = -1; } /** * 读取下一条记录 * * @author xuzhenglim:276137500 (2019-12-11) * * @param log * @param log_flg * @param buf * * @return int -1 表示没有记录 * 大于等于0数值,表示有数据,并且直接表示记录长度 */ int tiny_log_foreace_read(tiny_log_t * log,char * log_flg,void *dat) { if (log->total > 0 && (log->last_index + 1) < log->total) { int size = 0; int start = 0; if (log->last_index < 0) { log->last_index = 0; log->cur_site = log->first; } else { log->last_index++; log->cur_site = log->cur_site + log->log[log->cur_site] + 2; if (log->cur_site >= log->size) { log->cur_site -= log->size; } } start = log->cur_site; size = log->log[start]; ++start; if (start >= log->size) { start -= log->size; } *log_flg = log->log[start]; ++start; if (start >= log->size) { start -= log->size; } if (size > 0) { if (start + size <= log->size) { memcpy(dat, &log->log[start],size); } else { memcpy(dat, &log->log[start],log->size - start); memcpy(((unsigned char *)dat) + log->size - start, &log->log[0], size - (log->size - start)); } } return size; } return -1; } /** * 插入一条新的记录 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log * @param dat * @param size */ void tiny_log_insert(tiny_log_t *log, char log_flg, void *dat, unsigned char size) { //首先判断当前剩余大小是否足够 //计算最后一个数据结尾位置 int tail = 0; // int restore = log->size; //剩余大小 // int index = 0; //当有保存数据的时候 if (log->total > 0) { tail = log->last + log->log[log->last] + 2; if (tail >= log->size) { tail -= log->size; } do { if (log->first >= tail) //剩余空间是在中间部分 { if (log->first - tail > size) { //剩余空间足够 break; } else { //减少一条记录 log->first += log->log[log->first] + 2; if (log->first >= log->size) { log->first -= log->size; } if (log->total > 0) { log->total--; } else { break; } } } else if((log->size - tail + log->first) < size) //第一条信息地址未必是0, { //空间依然不够的情况下 //减少一条记录 log->first += log->log[log->first] + 2; if (log->first >= log->size) { log->first -= log->size; } if (log->total > 0) { log->total--; } else { break; } } else { //这种情况下是肯定满足大小的 break; } } while (1); } if (log->total <= 0) { //记录空了,直接从头开始存储 tiny_log_clear(log); tail = 0; } //先保存一个字节的长度信息 log->last = tail; log->log[tail] = (unsigned char)size; if (++tail >= log->size) { tail = 0; } //保存包标志位 log->log[tail] = (unsigned char)log_flg; if (++tail >= log->size) { tail = 0; } //b保存数据 if (size > 0) { if (log->size > tail + size) { //可以满足一次拷贝完成 memcpy(&log->log[tail], dat, size); } else { //需要分两次拷贝完成 memcpy(&log->log[tail], dat, log->size - tail); //拷贝剩余的数据 memcpy(&log->log[0], ((unsigned char *)dat) + log->size - tail, size + tail - log->size); } } //总条目数加1 log->total++; //顺序乱掉后,需要重新寻址了 log->last_index = -1; } /** * 对记录进行保存时需要调用一次 * * @author xuzhenglim:276137500 (2019-12-9) * * @param log */ void tiny_log_save(tiny_log_t *log) { unsigned short crc; //更新头部信息 memset(log->buf, 0, sizeof(tiny_log_head_t)); log->buf[0] = 'T'; log->buf[1] = 'L'; log->buf[2] = (log->first & 0xff); log->buf[3] = (log->first >> 8); log->buf[4] = (log->last & 0xff); log->buf[5] = (log->last >> 8); log->buf[6] = (log->total & 0xff); log->buf[7] = (log->total >> 8); crc = mh_crc16_calc(log->buf, log->size + sizeof(tiny_log_head_t)); log->buf[log->size + sizeof(tiny_log_head_t)] = crc; log->buf[log->size + sizeof(tiny_log_head_t) + 1] = crc >> 8; }