hv_dectect.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. * HV Detect Module - v6.5 (Minimalist Pulse Capture)
  3. *
  4. * 设计哲学:一个标志位走天下
  5. * - capturing = 0 : 等待脉冲(电流<1500 或已锁定)
  6. * - capturing = 1 : 捕获脉冲(跟踪特征,直到回落或超时)
  7. *
  8. * 长放电防重复:超时退出时加锁,必须等电流回落才解锁
  9. * 快速连续:正常回落退出不加锁,立即可以开始新脉冲
  10. */
  11. /*********************↓ include ↓************************/
  12. #define DBG_TAG "HV"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #include <rtthread.h>
  16. #include <rtdevice.h>
  17. #include <board.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include "ecode.h"
  22. #include "ym310_protecl.h"
  23. /*********************↑ include ↑************************/
  24. /*********************↓ define ↓************************/
  25. #define HV_BASE_MS 5
  26. /* 固定阈值(物理分界) */
  27. #define STANDBY_THRESHOLD 1500
  28. #define SPIKE_THRESHOLD 2000
  29. #define FLAT_MIN 1500
  30. #define FLAT_MAX 2000
  31. /* 脉冲完整性(基于基准,排除噪声) */
  32. #define PULSE_MIN_OFFSET 300
  33. /* 消抖 */
  34. #define FALL_CNT_MAX 1 /* 回落确认:30ms */
  35. #define MAX_DISCHARGE_MS 5000 /* 超时:5s */
  36. /* 时间 */
  37. #define MIN_INTERVAL_MS 50 /* 同模式最小间隔 */
  38. #define STARTUP_IGNORE_MS 3000 /* 启动冻结:3s */
  39. /* 基准 */
  40. #define BASE_INIT_DELAY_MS 2000
  41. #define BASE_SAMPLE_CNT 30
  42. #define BASE_DEFAULT 1135
  43. #define BASE_MIN 1000
  44. #define BASE_MAX 1300
  45. /* 日志 */
  46. #define UNCOUNT_CNT 32
  47. #define TRACE_CNT 100
  48. /* 实时打印间隔 */
  49. #define LIVE_PRINT_EVERY 5 /* 每5周期(50ms)打印一次 */
  50. /*********************↑ define ↑************************/
  51. /*********************↓ 外部声明 ↓***********************/
  52. extern SYS_STATUS sys_sta;
  53. extern RTC_HandleTypeDef hrtc;
  54. extern rt_bool_t gpio_hv_get_status(void);
  55. /*********************↑ 外部声明 ↑***********************/
  56. /*********************↓ 枚举 ↓************************/
  57. typedef enum
  58. {
  59. MODE_NONE = 0,
  60. MODE_SINGLE_SPIKE, /* peak>=2000, flat<2 */
  61. MODE_FLAT, /* peak<2000, flat>=3 */
  62. MODE_STANDARD, /* peak>=2000, flat>=2 */
  63. } hv_mode_t;
  64. typedef enum
  65. {
  66. UNCOUNT_NONE = 0,
  67. UNCOUNT_LOW_PEAK,
  68. UNCOUNT_INTERVAL,
  69. UNCOUNT_HV_OFF,
  70. UNCOUNT_BASE_NOT_READY,
  71. } uncount_reason_t;
  72. typedef enum
  73. {
  74. TRACE_WAIT = 0,
  75. TRACE_CAPTURE,
  76. TRACE_END,
  77. TRACE_TIMEOUT,
  78. TRACE_LOCKED,
  79. TRACE_HV_OFF,
  80. } trace_mark_t;
  81. /*********************↑ 枚举 ↑************************/
  82. /*********************↓ 结构体 ↓************************/
  83. typedef struct
  84. {
  85. uint32_t tick;
  86. uint16_t cur;
  87. uint16_t peak;
  88. uint8_t reason;
  89. uint16_t duration_ms;
  90. } uncount_rec_t;
  91. typedef struct
  92. {
  93. uint32_t tick;
  94. uint16_t cur;
  95. uint8_t capturing;
  96. uint8_t locked;
  97. uint8_t mark;
  98. } trace_rec_t;
  99. typedef struct
  100. {
  101. uint16_t peak;
  102. uint8_t has_spike;
  103. uint8_t flat_cnt;
  104. uint32_t start_tick;
  105. uint8_t falling_cnt;
  106. } pulse_win_t;
  107. typedef struct
  108. {
  109. uint8_t ready;
  110. uint16_t value;
  111. uint8_t waiting_init;
  112. uint32_t init_start_tick;
  113. uint32_t sample_sum;
  114. uint8_t sample_cnt;
  115. } base_t;
  116. /*********************↑ 结构体 ↑************************/
  117. /*********************↓ 静态变量 ↓************************/
  118. static rt_thread_t s_thread = RT_NULL;
  119. static uint8_t s_capturing = 0; /* 唯一状态标志:是否在捕获脉冲 */
  120. static uint8_t s_locked = 0; /* 长放电锁:超时后锁定,需回落解锁 */
  121. static pulse_win_t s_win = {0}; /* 当前脉冲窗口统计 */
  122. static base_t s_base = {.value = BASE_DEFAULT};
  123. static uint8_t s_hv_on = 0;
  124. static uint32_t s_hv_tick = 0;
  125. static uint32_t s_last_count_tick = 0;
  126. static uint32_t s_total_count = 0;
  127. static uint32_t s_total_uncount = 0;
  128. static uint8_t s_live_cnt = 0;
  129. static hv_mode_t s_last_mode = MODE_NONE;
  130. static uncount_rec_t s_uncount_log[UNCOUNT_CNT];
  131. static uint16_t s_uncount_head = 0;
  132. static uint16_t s_uncount_cnt = 0;
  133. static rt_mutex_t s_uncount_mtx = RT_NULL;
  134. static trace_rec_t s_trace_log[TRACE_CNT];
  135. static uint16_t s_trace_head = 0;
  136. static uint8_t s_trace_full = 0;
  137. /*********************↑ 静态变量 ↑************************/
  138. /*********************↓ 前向声明 ↓************************/
  139. static uint8_t is_hv_on(void);
  140. static void reset_all(void);
  141. static const char *mode_str(hv_mode_t m);
  142. static const char *uncount_str(uncount_reason_t r);
  143. static uint8_t can_count(hv_mode_t mode);
  144. static void end_pulse(uint32_t now, uint8_t timeout);
  145. static void log_uncount(uncount_reason_t r, uint16_t cur, uint16_t peak, uint32_t dur);
  146. static void push_trace(uint16_t cur, uint8_t cap, uint8_t lock, uint8_t mark);
  147. static void live_print(uint16_t cur, uint32_t now);
  148. static hv_mode_t judge_mode(uint16_t peak, uint8_t flat, uint8_t spike);
  149. void hv_save(uint32_t c);
  150. uint32_t hv_read(void);
  151. /*********************↑ 前向声明 ↑************************/
  152. /*********************↓ 辅助函数 ↓************************/
  153. static uint8_t is_hv_on(void) { return gpio_hv_get_status() == 1; }
  154. static void reset_all(void)
  155. {
  156. s_capturing = 0;
  157. s_locked = 0;
  158. memset(&s_win, 0, sizeof(s_win));
  159. s_base.ready = 0;
  160. s_base.waiting_init = 0;
  161. s_base.sample_sum = 0;
  162. s_base.sample_cnt = 0;
  163. s_hv_tick = 0;
  164. s_live_cnt = 0;
  165. }
  166. static const char *mode_str(hv_mode_t m)
  167. {
  168. switch (m)
  169. {
  170. case MODE_SINGLE_SPIKE:
  171. return "单尖峰";
  172. case MODE_FLAT:
  173. return "平缓";
  174. case MODE_STANDARD:
  175. return "标准";
  176. default:
  177. return "未知";
  178. }
  179. }
  180. static const char *uncount_str(uncount_reason_t r)
  181. {
  182. switch (r)
  183. {
  184. case UNCOUNT_LOW_PEAK:
  185. return "峰值过低";
  186. case UNCOUNT_INTERVAL:
  187. return "间隔去抖";
  188. case UNCOUNT_HV_OFF:
  189. return "高压关闭";
  190. case UNCOUNT_BASE_NOT_READY:
  191. return "基准未就绪";
  192. default:
  193. return "未知";
  194. }
  195. }
  196. static uint8_t can_count(hv_mode_t mode)
  197. {
  198. if (s_last_count_tick == 0)
  199. return 1;
  200. uint32_t elapsed = (rt_tick_get() - s_last_count_tick) * HV_BASE_MS;
  201. if (elapsed >= MIN_INTERVAL_MS)
  202. return 1;
  203. if (mode != s_last_mode)
  204. return 1;
  205. return 0;
  206. }
  207. static void log_uncount(uncount_reason_t r, uint16_t cur, uint16_t peak, uint32_t dur)
  208. {
  209. if (s_uncount_mtx == RT_NULL)
  210. return;
  211. rt_mutex_take(s_uncount_mtx, RT_WAITING_FOREVER);
  212. uint16_t idx = s_uncount_head % UNCOUNT_CNT;
  213. s_uncount_log[idx].tick = rt_tick_get();
  214. s_uncount_log[idx].cur = cur;
  215. s_uncount_log[idx].peak = peak;
  216. s_uncount_log[idx].reason = r;
  217. s_uncount_log[idx].duration_ms = (uint16_t)dur;
  218. s_uncount_head++;
  219. if (s_uncount_cnt < UNCOUNT_CNT)
  220. s_uncount_cnt++;
  221. rt_mutex_release(s_uncount_mtx);
  222. s_total_uncount++;
  223. LOG_W("[HV] 未计[%s] cur=%u peak=%u dur=%ums", uncount_str(r), cur, peak, dur);
  224. }
  225. static void push_trace(uint16_t cur, uint8_t cap, uint8_t lock, uint8_t mark)
  226. {
  227. uint16_t idx = s_trace_head % TRACE_CNT;
  228. s_trace_log[idx].tick = rt_tick_get();
  229. s_trace_log[idx].cur = cur;
  230. s_trace_log[idx].capturing = cap;
  231. s_trace_log[idx].locked = lock;
  232. s_trace_log[idx].mark = mark;
  233. s_trace_head++;
  234. if (s_trace_head >= TRACE_CNT)
  235. s_trace_full = 1;
  236. }
  237. static void live_print(uint16_t cur, uint32_t now)
  238. {
  239. if (++s_live_cnt >= LIVE_PRINT_EVERY)
  240. {
  241. s_live_cnt = 0;
  242. uint32_t dur = (now - s_win.start_tick) * HV_BASE_MS;
  243. LOG_D("[HV] LIVE cur=%u peak=%u flat=%u spike=%u dur=%ums",
  244. cur, s_win.peak, s_win.flat_cnt, s_win.has_spike, dur);
  245. }
  246. }
  247. static hv_mode_t judge_mode(uint16_t peak, uint8_t flat, uint8_t spike)
  248. {
  249. if (spike && flat < 2)
  250. return MODE_SINGLE_SPIKE;
  251. if (spike && flat >= 2)
  252. return MODE_STANDARD;
  253. if (flat >= 3)
  254. return MODE_FLAT;
  255. if (peak >= SPIKE_THRESHOLD)
  256. return MODE_SINGLE_SPIKE;
  257. return MODE_FLAT;
  258. }
  259. static void end_pulse(uint32_t now, uint8_t is_timeout)
  260. {
  261. uint32_t dur = (now - s_win.start_tick) * HV_BASE_MS;
  262. if (!s_base.ready)
  263. {
  264. log_uncount(UNCOUNT_BASE_NOT_READY, 0, s_win.peak, dur);
  265. goto cleanup;
  266. }
  267. if (s_win.peak < s_base.value + PULSE_MIN_OFFSET)
  268. {
  269. log_uncount(UNCOUNT_LOW_PEAK, 0, s_win.peak, dur);
  270. goto cleanup;
  271. }
  272. hv_mode_t mode = judge_mode(s_win.peak, s_win.flat_cnt, s_win.has_spike);
  273. if (mode == MODE_FLAT && s_win.peak <= FLAT_MIN)
  274. {
  275. log_uncount(UNCOUNT_LOW_PEAK, 0, s_win.peak, dur);
  276. goto cleanup;
  277. }
  278. LOG_I("[HV] 结束[%s] peak=%u flat=%u spike=%u dur=%ums%s",
  279. mode_str(mode), s_win.peak, s_win.flat_cnt, s_win.has_spike,
  280. dur, is_timeout ? " [超时]" : "");
  281. if (!can_count(mode))
  282. {
  283. log_uncount(UNCOUNT_INTERVAL, s_win.peak, s_win.peak, dur);
  284. goto cleanup;
  285. }
  286. s_last_count_tick = rt_tick_get();
  287. sys_sta.hv_count++;
  288. hv_save(sys_sta.hv_count);
  289. s_total_count++;
  290. s_last_mode = mode;
  291. LOG_I("[HV] [%s] +1=%u peak=%u dur=%ums", mode_str(mode), sys_sta.hv_count, s_win.peak, dur);
  292. cleanup:
  293. s_capturing = 0;
  294. memset(&s_win, 0, sizeof(s_win));
  295. if (is_timeout)
  296. {
  297. s_locked = 1;
  298. LOG_I("[HV] 窗口锁定,等待电流回落");
  299. }
  300. }
  301. uint32_t hv_read(void)
  302. {
  303. sys_sta.hv_count = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR6);
  304. return HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR6);
  305. }
  306. void hv_save(uint32_t c)
  307. {
  308. if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR6) != c)
  309. {
  310. HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR6, c);
  311. }
  312. sys_sta.hv_count = c;
  313. }
  314. /*********************↑ 辅助函数 ↑************************/
  315. /*********************↓ 核心线程 ↓************************/
  316. static void hv_thread(void *param)
  317. {
  318. uint16_t cur;
  319. uint32_t now;
  320. uint8_t hv;
  321. s_uncount_mtx = rt_mutex_create("hv_uncount", RT_IPC_FLAG_PRIO);
  322. // LOG_I("[HV] v6.5 极简双态 待机<%d 平缓[%d,%d) 尖峰>=%d 超时=%dms",
  323. // STANDBY_THRESHOLD, FLAT_MIN, FLAT_MAX, SPIKE_THRESHOLD, MAX_DISCHARGE_MS);
  324. hv_read();
  325. LOG_I("[HV] 保存计数=%u", sys_sta.hv_count);
  326. while (1)
  327. {
  328. now = rt_tick_get();
  329. cur = sys_sta.hv_current;
  330. hv = is_hv_on();
  331. if (!hv)
  332. {
  333. if (s_hv_on)
  334. {
  335. if (s_capturing)
  336. {
  337. log_uncount(UNCOUNT_HV_OFF, cur, s_win.peak,
  338. (now - s_win.start_tick) * HV_BASE_MS);
  339. }
  340. reset_all();
  341. s_hv_on = 0;
  342. }
  343. push_trace(cur, 0, 0, TRACE_HV_OFF);
  344. rt_thread_mdelay(HV_BASE_MS);
  345. continue;
  346. }
  347. if (!s_hv_on)
  348. {
  349. s_hv_on = 1;
  350. reset_all();
  351. s_hv_tick = now;
  352. s_base.waiting_init = 1;
  353. s_base.init_start_tick = now;
  354. //LOG_I("[HV] 开启,%dms内冻结", STARTUP_IGNORE_MS);
  355. }
  356. uint32_t hv_elapse = (now - s_hv_tick) * HV_BASE_MS;
  357. if (hv_elapse < STARTUP_IGNORE_MS)
  358. {
  359. push_trace(cur, 0, 0, TRACE_WAIT);
  360. rt_thread_mdelay(HV_BASE_MS);
  361. continue;
  362. }
  363. if (s_base.waiting_init && !s_base.ready)
  364. {
  365. uint32_t elapse = (now - s_base.init_start_tick) * HV_BASE_MS;
  366. if (elapse >= BASE_INIT_DELAY_MS)
  367. {
  368. s_base.sample_sum += cur;
  369. s_base.sample_cnt++;
  370. if (s_base.sample_cnt >= BASE_SAMPLE_CNT)
  371. {
  372. uint16_t nb = s_base.sample_sum / s_base.sample_cnt;
  373. s_base.value = (nb >= BASE_MIN && nb <= BASE_MAX) ? nb : BASE_DEFAULT;
  374. s_base.ready = 1;
  375. s_base.waiting_init = 0;
  376. LOG_I("[HV] 基准=%u", s_base.value);
  377. }
  378. }
  379. }
  380. if (!s_capturing)
  381. {
  382. if (cur < STANDBY_THRESHOLD)
  383. {
  384. if (s_locked)
  385. {
  386. s_locked = 0;
  387. LOG_I("[HV] 解锁");
  388. }
  389. push_trace(cur, 0, 0, TRACE_WAIT);
  390. }
  391. else if (!s_locked && s_base.ready)
  392. {
  393. s_capturing = 1;
  394. s_win.peak = cur;
  395. s_win.has_spike = (cur >= SPIKE_THRESHOLD);
  396. s_win.flat_cnt = (cur >= FLAT_MIN && cur < FLAT_MAX) ? 1 : 0;
  397. s_win.start_tick = now;
  398. s_win.falling_cnt = 0;
  399. s_live_cnt = 0;
  400. LOG_I("[HV] 捕获开始 cur=%u", cur);
  401. push_trace(cur, 1, 0, TRACE_CAPTURE);
  402. }
  403. else
  404. {
  405. push_trace(cur, 0, 1, TRACE_LOCKED);
  406. }
  407. }
  408. else
  409. {
  410. if (cur > s_win.peak)
  411. s_win.peak = cur;
  412. if (cur >= SPIKE_THRESHOLD)
  413. s_win.has_spike = 1;
  414. if (cur >= FLAT_MIN && cur < FLAT_MAX)
  415. s_win.flat_cnt++;
  416. live_print(cur, now);
  417. if (cur < STANDBY_THRESHOLD)
  418. {
  419. if (++s_win.falling_cnt >= FALL_CNT_MAX)
  420. {
  421. end_pulse(now, 0);
  422. push_trace(cur, 0, 0, TRACE_END);
  423. }
  424. else
  425. {
  426. push_trace(cur, 1, 0, TRACE_CAPTURE);
  427. }
  428. }
  429. else
  430. {
  431. s_win.falling_cnt = 0;
  432. if ((now - s_win.start_tick) * HV_BASE_MS >= MAX_DISCHARGE_MS)
  433. {
  434. end_pulse(now, 1);
  435. push_trace(cur, 0, 1, TRACE_TIMEOUT);
  436. }
  437. else
  438. {
  439. push_trace(cur, 1, 0, TRACE_CAPTURE);
  440. }
  441. }
  442. }
  443. rt_thread_mdelay(HV_BASE_MS);
  444. }
  445. }
  446. /*********************↑ 核心线程 ↑************************/
  447. /*********************↓ 初始化 ↓************************/
  448. static void hv_start(void)
  449. {
  450. if (s_thread)
  451. return;
  452. s_thread = rt_thread_create("hv_detect", hv_thread, NULL, 1024, 10, 10);
  453. if (s_thread)
  454. rt_thread_startup(s_thread);
  455. }
  456. static int hv_init(void)
  457. {
  458. hv_start();
  459. return 0;
  460. }
  461. INIT_APP_EXPORT(hv_init);
  462. /*********************↑ 初始化 ↑************************/
  463. /*********************↓ MSH命令 ↓************************/
  464. static void cmd_status(void)
  465. {
  466. uint32_t total = s_total_count + s_total_uncount;
  467. uint32_t rate = total ? (s_total_count * 100 / total) : 100;
  468. rt_kprintf("========== HV v6.5 极简双态 ==========\n");
  469. rt_kprintf("总计数: %u\n", sys_sta.hv_count);
  470. rt_kprintf("本次计数: %u\n", s_total_count);
  471. rt_kprintf("本次未计: %u\n", s_total_uncount);
  472. rt_kprintf("成功率: %u%%\n", rate);
  473. rt_kprintf("基准: %u (%s)\n", s_base.value, s_base.ready ? "就绪" : "未就绪");
  474. rt_kprintf("状态: %s %s\n", s_capturing ? "捕获中" : "等待中", s_locked ? "[锁定]" : "");
  475. rt_kprintf("阈值: 待机<%d 平缓[%d,%d) 尖峰>=%d\n",
  476. STANDBY_THRESHOLD, FLAT_MIN, FLAT_MAX, SPIKE_THRESHOLD);
  477. rt_kprintf("======================================\n");
  478. }
  479. MSH_CMD_EXPORT(cmd_status, hvsta);
  480. static void cmd_uncount(void)
  481. {
  482. if (s_uncount_mtx == RT_NULL)
  483. {
  484. rt_kprintf("未初始化\n");
  485. return;
  486. }
  487. rt_mutex_take(s_uncount_mtx, RT_WAITING_FOREVER);
  488. if (s_uncount_cnt == 0)
  489. {
  490. rt_kprintf("========== 未计数日志 ==========\n无记录\n================================\n");
  491. rt_mutex_release(s_uncount_mtx);
  492. return;
  493. }
  494. rt_kprintf("========== 未计数日志 (%d条) ==========\n", s_uncount_cnt);
  495. rt_kprintf("%-4s %-8s %-6s %-6s %-10s %-8s\n", "序号", "时间(s)", "电流", "峰值", "原因", "时长");
  496. rt_kprintf("----------------------------------------\n");
  497. uint16_t start = (s_uncount_head < s_uncount_cnt) ? 0 : (s_uncount_head - s_uncount_cnt);
  498. for (uint16_t i = 0; i < s_uncount_cnt; i++)
  499. {
  500. uint16_t idx = (start + i) % UNCOUNT_CNT;
  501. uncount_rec_t *r = &s_uncount_log[idx];
  502. rt_kprintf("%-4u %-8u %-6u %-6u %-10s %-7ums\n",
  503. i + 1, r->tick / 100, r->cur, r->peak,
  504. uncount_str((uncount_reason_t)r->reason), r->duration_ms);
  505. }
  506. rt_kprintf("================================\n");
  507. rt_mutex_release(s_uncount_mtx);
  508. }
  509. MSH_CMD_EXPORT(cmd_uncount, hvuncount);
  510. static void cmd_trace(int argc, char **argv)
  511. {
  512. uint16_t n = (argc >= 2) ? atoi(argv[1]) : 20;
  513. if (n > TRACE_CNT)
  514. n = TRACE_CNT;
  515. if (n == 0)
  516. n = 1;
  517. uint16_t total = s_trace_full ? TRACE_CNT : s_trace_head;
  518. if (n > total)
  519. n = total;
  520. if (total == 0)
  521. {
  522. rt_kprintf("Trace 为空\n");
  523. return;
  524. }
  525. rt_kprintf("========== Trace (最近%d条) ==========\n", n);
  526. rt_kprintf("%-5s %-6s %-6s %-4s %-4s %-6s\n", "序号", "Tick", "电流", "捕获", "锁定", "标记");
  527. rt_kprintf("----------------------------------------\n");
  528. uint16_t start = (s_trace_head + TRACE_CNT - n) % TRACE_CNT;
  529. for (uint16_t i = 0; i < n; i++)
  530. {
  531. uint16_t idx = (start + i) % TRACE_CNT;
  532. trace_rec_t *t = &s_trace_log[idx];
  533. rt_kprintf("%-5u %-6u %-6u %-4u %-4u %-6c\n",
  534. i + 1, t->tick % 10000, t->cur, t->capturing, t->locked,
  535. t->mark == TRACE_WAIT ? 'W' : t->mark == TRACE_CAPTURE ? 'C'
  536. : t->mark == TRACE_END ? 'E'
  537. : t->mark == TRACE_TIMEOUT ? 'T'
  538. : t->mark == TRACE_LOCKED ? 'L'
  539. : t->mark == TRACE_HV_OFF ? 'H'
  540. : '?');
  541. }
  542. rt_kprintf("================================\n");
  543. rt_kprintf("标记: W=等待 C=捕获 E=结束 T=超时 L=锁定 H=关闭\n");
  544. }
  545. MSH_CMD_EXPORT(cmd_trace, hvtrace);
  546. static void cmd_clear(void)
  547. {
  548. sys_sta.hv_count = 0;
  549. hv_save(0);
  550. reset_all();
  551. s_last_count_tick = 0;
  552. s_total_count = 0;
  553. s_total_uncount = 0;
  554. s_trace_head = 0;
  555. s_trace_full = 0;
  556. memset(s_trace_log, 0, sizeof(s_trace_log));
  557. if (s_uncount_mtx)
  558. {
  559. rt_mutex_take(s_uncount_mtx, RT_WAITING_FOREVER);
  560. s_uncount_head = 0;
  561. s_uncount_cnt = 0;
  562. memset(s_uncount_log, 0, sizeof(s_uncount_log));
  563. rt_mutex_release(s_uncount_mtx);
  564. }
  565. LOG_I("[HV] 已清零");
  566. rt_kprintf("已清零\n");
  567. }
  568. MSH_CMD_EXPORT(cmd_clear, hvclr);
  569. /*********************↑ MSH命令 ↑************************/