TinyLog.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*=====================================TINYLog======================================================
  2. **用于单片表的轻量级紧凑型记录队列,目的是能够实现静态的添加记录并查找记录,但是并不关系内部的数据内容与长度
  3. **由于是队列方式每次更新插入记录都只会将最旧的记录清除,很适合用于历史功能类的相关记录工作
  4. **
  5. **由于只是用于支持单片机的,所以支持的缓冲大小只要65K,同时单条消息只到255长度,这也是根据现实情况来考量的 ,以此为基础,
  6. **也限制了最大的条目数为65K
  7. **版本V0.1.0
  8. **author : LXZ
  9. **history:
  10. **19.12.07 LXZ 编写第一个版本
  11. **19.12.12 LXZ 调试完毕,去掉多余接,口实现预计功能
  12. =====================================================================================================*/
  13. #include "TinyLog.h"
  14. #include "MathHelper.h"
  15. #include <string.h>
  16. /*================================================================================================
  17. * 保存的数据结构
  18. * | 标志位 ’T' 'L' 两字节
  19. * | 第一条数据开始位置 两字节
  20. * | 最后一调数据开始位置 两字节
  21. * | 总记录数 两字节
  22. * | 预留功能到16字节
  23. * | 数据缓冲 N字节
  24. * | CRC两字节
  25. ==================================================================================================*/
  26. typedef struct
  27. {
  28. unsigned char flag1;
  29. unsigned char flag2;
  30. unsigned short first_index;
  31. unsigned short last_index;
  32. unsigned short total;
  33. unsigned short res[4];
  34. } tiny_log_head_t;
  35. /**
  36. * 通过缓冲初始化一个记录,缓冲必须包含有效的记录
  37. *
  38. * @author xuzhenglim:276137500 (2019-12-7)
  39. *
  40. * @param log
  41. * @param buf
  42. * @param size
  43. */
  44. void tiny_log_init(tiny_log_t *log, void *buf, int size)
  45. {
  46. unsigned char *dat = (unsigned char *)buf;
  47. //判断是否存在有效的记录
  48. if (mh_crc16_calc(buf, size) == 0 && dat[0] == 'T' && dat[1] == 'L')
  49. {
  50. //存在有效的记录,开始解析记录的数据
  51. log->log = &dat[sizeof(tiny_log_head_t)];
  52. log->size = size - sizeof(tiny_log_head_t) - 2;
  53. log->first = dat[2] + (dat[3] << 8);
  54. log->last = dat[4] + (dat[5] << 8);
  55. log->total = dat[6] + (dat[7] << 8);
  56. log->buf = dat;
  57. log->cur_site = log->first;
  58. log->last_index = 0;
  59. } else
  60. {
  61. //存在有效的记录,开始解析记录的数据
  62. log->log = (void *)((unsigned int)buf + sizeof(tiny_log_head_t));
  63. log->size = size - sizeof(tiny_log_head_t) - 2;
  64. log->first = 0;
  65. log->last = log->first;
  66. log->total = log->total;
  67. log->buf = (unsigned char *)buf;
  68. log->cur_site = log->first;
  69. log->last_index = 0;
  70. }
  71. }
  72. /**
  73. * 清空记录
  74. *
  75. * @author xuzhenglim:276137500 (2019-12-7)
  76. *
  77. * @param log
  78. */
  79. void tiny_log_clear(tiny_log_t *log)
  80. {
  81. log->first = 0;
  82. log->last = 0;
  83. log->total = 0;
  84. log->idle_size = log->size;
  85. log->cur_site = log->first;
  86. }
  87. /**
  88. * 查找下一个
  89. *
  90. * @author xuzhenglim:276137500 (2019-12-9)
  91. *
  92. * @param log
  93. *
  94. * @return int -1 表示没有记录
  95. * 大于等于0数值,表示有数据,并且直接表示记录长度
  96. */
  97. int tiny_log_foreach_entry(tiny_log_t *log)
  98. {
  99. if (log->total > 0 && (log->last_index + 1) < log->total)
  100. {
  101. int size = 0;
  102. int start = 0;
  103. if (log->last_index < 0)
  104. {
  105. log->last_index = 0;
  106. log->cur_site = log->first;
  107. }
  108. else
  109. {
  110. log->last_index++;
  111. log->cur_site = log->cur_site + log->log[log->cur_site] + 2;
  112. if (log->cur_site >= log->size)
  113. {
  114. log->cur_site -= log->size;
  115. }
  116. }
  117. size = log->log[start];
  118. return size;
  119. }
  120. return -1;
  121. }
  122. /**
  123. * 读取当前记录下的标志
  124. *
  125. * @author xuzhenglim:276137500 (2019-12-9)
  126. *
  127. * @param log
  128. * @param log_flg
  129. *
  130. * @return int -1 表示没有记录
  131. * 大于等于0数值,表示有数据,并且直接表示记录长度
  132. */
  133. int tiny_log_read_type(tiny_log_t *log,char * log_flg)
  134. {
  135. if (log->last_index >= 0 && log->total > 0)
  136. {
  137. int start = log->cur_site + 1;
  138. if (start >= log->size)
  139. {
  140. start -= log->size;
  141. }
  142. *log_flg = log->log[start];
  143. return log->log[log->cur_site];
  144. }
  145. return -1;
  146. }
  147. /**
  148. * 读取记录
  149. *
  150. * @author xuzhenglim:276137500 (2019-12-9)
  151. *
  152. * @param log
  153. * @param buf
  154. *
  155. * @return int -1 表示没有记录
  156. * 大于等于0数值,表示有数据,并且直接表示记录长度
  157. */
  158. int tiny_log_read_log(tiny_log_t *log,void * buf)
  159. {
  160. if (log->last_index >= 0 && log->total > 0)
  161. {
  162. unsigned char *dat = (unsigned char *)buf;
  163. int start = log->cur_site + 2;
  164. int size = log->log[log->cur_site];
  165. if (start >= log->size)
  166. {
  167. start -= log->size;
  168. }
  169. if (size > 0)
  170. {
  171. if ((start + size) <= log->size) //可以单次读完
  172. {
  173. memcpy(dat, &log->log[start],size);
  174. }
  175. else
  176. {
  177. //单次无法复制完的情况
  178. memcpy(dat, &log->log[start], log->size - start);
  179. memcpy(dat, &log->log[0], start + size - log->size);
  180. }
  181. }
  182. return size;
  183. }
  184. return -1;
  185. }
  186. /**
  187. * 定位到对应编号下的记录
  188. *
  189. * @author xuzhenglim:276137500 (2019-12-9)
  190. *
  191. * @param log
  192. * @param index
  193. *
  194. * @return int -1 表示没有记录
  195. * 大于等于0数值,表示有数据,并且直接表示记录长度
  196. */
  197. int tiny_log_index(tiny_log_t * log, unsigned short index)
  198. {
  199. if (index < log->total)
  200. {
  201. int start = log->first;
  202. while (index > 0)
  203. {
  204. index--;
  205. start = start + log->log[start] + 2;
  206. if (start >= log->size)
  207. {
  208. start -= log->size;
  209. }
  210. }
  211. log->cur_site = start;
  212. log->last_index = index;
  213. return log->log[start];
  214. }
  215. return -1;
  216. }
  217. /**
  218. * 在执行快读读取接口的时候必须先调用该接口,用于无效化上一次查找状态
  219. *
  220. * @author xuzhenglim:276137500 (2019-12-11)
  221. *
  222. * @param log
  223. * @param log_flg
  224. * @param buf
  225. *
  226. * @return int -1 表示没有记录
  227. * 大于等于0数值,表示有数据,并且直接表示记录长度
  228. */
  229. void tiny_log_beign_read(tiny_log_t * log)
  230. {
  231. log->last_index = -1;
  232. }
  233. /**
  234. * 读取下一条记录
  235. *
  236. * @author xuzhenglim:276137500 (2019-12-11)
  237. *
  238. * @param log
  239. * @param log_flg
  240. * @param buf
  241. *
  242. * @return int -1 表示没有记录
  243. * 大于等于0数值,表示有数据,并且直接表示记录长度
  244. */
  245. int tiny_log_foreace_read(tiny_log_t * log,char * log_flg,void *dat)
  246. {
  247. if (log->total > 0 && (log->last_index + 1) < log->total)
  248. {
  249. int size = 0;
  250. int start = 0;
  251. if (log->last_index < 0)
  252. {
  253. log->last_index = 0;
  254. log->cur_site = log->first;
  255. }
  256. else
  257. {
  258. log->last_index++;
  259. log->cur_site = log->cur_site + log->log[log->cur_site] + 2;
  260. if (log->cur_site >= log->size)
  261. {
  262. log->cur_site -= log->size;
  263. }
  264. }
  265. start = log->cur_site;
  266. size = log->log[start];
  267. ++start;
  268. if (start >= log->size)
  269. {
  270. start -= log->size;
  271. }
  272. *log_flg = log->log[start];
  273. ++start;
  274. if (start >= log->size)
  275. {
  276. start -= log->size;
  277. }
  278. if (size > 0)
  279. {
  280. if (start + size <= log->size)
  281. {
  282. memcpy(dat, &log->log[start],size);
  283. }
  284. else
  285. {
  286. memcpy(dat, &log->log[start],log->size - start);
  287. memcpy(((unsigned char *)dat) + log->size - start, &log->log[0], size - (log->size - start));
  288. }
  289. }
  290. return size;
  291. }
  292. return -1;
  293. }
  294. /**
  295. * 插入一条新的记录
  296. *
  297. * @author xuzhenglim:276137500 (2019-12-9)
  298. *
  299. * @param log
  300. * @param dat
  301. * @param size
  302. */
  303. void tiny_log_insert(tiny_log_t *log, char log_flg, void *dat, unsigned char size)
  304. {
  305. //首先判断当前剩余大小是否足够
  306. //计算最后一个数据结尾位置
  307. int tail = 0;
  308. // int restore = log->size; //剩余大小
  309. // int index = 0;
  310. //当有保存数据的时候
  311. if (log->total > 0)
  312. {
  313. tail = log->last + log->log[log->last] + 2;
  314. if (tail >= log->size)
  315. {
  316. tail -= log->size;
  317. }
  318. do
  319. {
  320. if (log->first >= tail) //剩余空间是在中间部分
  321. {
  322. if (log->first - tail > size)
  323. {
  324. //剩余空间足够
  325. break;
  326. } else
  327. {
  328. //减少一条记录
  329. log->first += log->log[log->first] + 2;
  330. if (log->first >= log->size)
  331. {
  332. log->first -= log->size;
  333. }
  334. if (log->total > 0)
  335. {
  336. log->total--;
  337. } else
  338. {
  339. break;
  340. }
  341. }
  342. }
  343. else if((log->size - tail + log->first) < size) //第一条信息地址未必是0,
  344. {
  345. //空间依然不够的情况下
  346. //减少一条记录
  347. log->first += log->log[log->first] + 2;
  348. if (log->first >= log->size)
  349. {
  350. log->first -= log->size;
  351. }
  352. if (log->total > 0)
  353. {
  354. log->total--;
  355. } else
  356. {
  357. break;
  358. }
  359. }
  360. else
  361. {
  362. //这种情况下是肯定满足大小的
  363. break;
  364. }
  365. } while (1);
  366. }
  367. if (log->total <= 0)
  368. {
  369. //记录空了,直接从头开始存储
  370. tiny_log_clear(log);
  371. tail = 0;
  372. }
  373. //先保存一个字节的长度信息
  374. log->last = tail;
  375. log->log[tail] = (unsigned char)size;
  376. if (++tail >= log->size)
  377. {
  378. tail = 0;
  379. }
  380. //保存包标志位
  381. log->log[tail] = (unsigned char)log_flg;
  382. if (++tail >= log->size)
  383. {
  384. tail = 0;
  385. }
  386. //b保存数据
  387. if (size > 0)
  388. {
  389. if (log->size > tail + size)
  390. {
  391. //可以满足一次拷贝完成
  392. memcpy(&log->log[tail], dat, size);
  393. } else
  394. {
  395. //需要分两次拷贝完成
  396. memcpy(&log->log[tail], dat, log->size - tail);
  397. //拷贝剩余的数据
  398. memcpy(&log->log[0], ((unsigned char *)dat) + log->size - tail, size + tail - log->size);
  399. }
  400. }
  401. //总条目数加1
  402. log->total++;
  403. //顺序乱掉后,需要重新寻址了
  404. log->last_index = -1;
  405. }
  406. /**
  407. * 对记录进行保存时需要调用一次
  408. *
  409. * @author xuzhenglim:276137500 (2019-12-9)
  410. *
  411. * @param log
  412. */
  413. void tiny_log_save(tiny_log_t *log)
  414. {
  415. unsigned short crc;
  416. //更新头部信息
  417. memset(log->buf, 0, sizeof(tiny_log_head_t));
  418. log->buf[0] = 'T';
  419. log->buf[1] = 'L';
  420. log->buf[2] = (log->first & 0xff);
  421. log->buf[3] = (log->first >> 8);
  422. log->buf[4] = (log->last & 0xff);
  423. log->buf[5] = (log->last >> 8);
  424. log->buf[6] = (log->total & 0xff);
  425. log->buf[7] = (log->total >> 8);
  426. crc = mh_crc16_calc(log->buf, log->size + sizeof(tiny_log_head_t));
  427. log->buf[log->size + sizeof(tiny_log_head_t)] = crc;
  428. log->buf[log->size + sizeof(tiny_log_head_t) + 1] = crc >> 8;
  429. }