shuichan_old/STM32F103_App1/HardWare/SYSINIT/reset_log.c

227 lines
7.6 KiB
C
Raw Permalink Normal View History

/* reset_log.c - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>ԭ<EFBFBD><D4AD> + <20>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD>W25Q64 0x100000 <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD> 4KB <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>10 <EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD>θ<EFBFBD><EFBFBD>ǣ<EFBFBD>
* д<EFBFBD><EFBFBD>һȦ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>¼<EFBFBD>ϡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<EFBFBD><EFBFBD>ԣ<EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> BOOT_SHARE <EFBFBD><EFBFBD><EFBFBD><EFBFBD> RAM<EFBFBD><EFBFBD>ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>£<EFBFBD><EFBFBD>ȸ<EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ź<EFBFBD>/<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵʱ RAM ʧЧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ɶϵ<EFBFBD>˲<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
* <EFBFBD><EFBFBD>PA0 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <10% <EFBFBD><EFBFBD>Ϊ<EFBFBD>ⲿ 12V <EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ 30s <EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
* ԭ<EFBFBD><EFBFBD><EFBFBD>RCC->CSR <EFBFBD><EFBFBD> BL <EFBFBD><EFBFBD><EFBFBD><EFBFBD> BOOT_SHARE <EFBFBD><EFBFBD><EFBFBD><EFBFBD> APP<EFBFBD><EFBFBD>BL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>ϸ<EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD>ɸ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD> reset_log_mark() Ԥ<EFBFBD><EFBFBD>д<EFBFBD>
*/
#include "reset_log.h"
#include "boot_share.h"
#include "log.h"
#include "main.h"
#include "app_loop.h"
#include "hlw8032.h"
#include "../W25Q64/w25q64.h"
#include "string.h"
#define RST_LOG_ADDR 0x100000u /* <20>ܿ<EFBFBD> OTA <20><>(0~0x81FFF) */
#define RST_LOG_SLOTS 10
#define RST_REC_MAGIC 0x5253544Cu /* 'RSTL' */
#define RST_REC_SIZE 32u
/* ÿ<><C3BF><EFBFBD><EFBFBD>¼<EFBFBD><C2BC>ռһ<D5BC><D2BB> 4KB <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NOR Flash ֻ<><D6BB> 1->0 <20><>λ<EFBFBD><CEBB>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD> 10 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ζ<EFBFBD><EFBFBD><EFBFBD> 9 <EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD>¼<EFBFBD><EFBFBD>
* һ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<EFBFBD><EFBFBD> 11 <20><>ֻ<EFBFBD><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<EFBFBD><EFBFBD>W25Q64 <EFBFBD><EFBFBD> 8MB<EFBFBD><EFBFBD><EFBFBD><EFBFBD> 10 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD> */
typedef struct {
uint32_t magic; /* RST_REC_MAGIC */
uint32_t seq; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ţ<EFBFBD><C5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
uint8_t reason; /* RSN_x */
uint8_t boot_seen; /* 0xFF=<3D>¼<EFBFBD>¼<EFBFBD><C2BC><EFBFBD>ϵ<EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>´ο<C2B4><CEBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѻ<EFBFBD><D1BA><EFBFBD> 0x00<30><30>λ<EFBFBD><CEBB>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
uint8_t rsvd[2];
uint32_t uptime_sec; /* <20>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>0xFFFFFFFF=δ֪<CEB4><D6AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> RAM <20><>ʧ<EFBFBD><CAA7> */
uint16_t crc16; /* ǰ 14 <20>ֽ<EFBFBD><D6BD>ۼӺ<DBBC> */
uint8_t pad[16];
} rst_rec_t;
static const char *reason_str(uint8_t r)
{
switch (r) {
case RSN_POWER_ON: return "<EFBFBD>ϵ<EFBFBD>/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_PIN_RESET: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ";
case RSN_WATCHDOG: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_KICKED: return "<EFBFBD><EFBFBD>ƽ̨<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_PING_TIMEOUT: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ)";
case RSN_NO_SERVICE: return "4G<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_NO_SIM: return "<EFBFBD><EFBFBD>SIM<EFBFBD><EFBFBD>";
case RSN_OTA_UPDATE: return "OTA<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_OTA_HEALTH: return "OTA<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鳬ʱ";
case RSN_4G_FAIL: return "4G<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>";
case RSN_CMD_RESET: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>RESET<EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_CMD_OTA: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>OTA<EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_CMD_RECOVERY: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>RECOVERY<EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_POWER_LOSS: return "<EFBFBD>ⲿ<EFBFBD>ϵ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݼ<EFBFBD>¼)";
case RSN_4G_MODULE: return "4Gģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
case RSN_OTA_FAIL: return "OTAʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹ";
case RSN_SOFT_GENERIC: return "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ(δ<><CEB4><EFBFBD><EFBFBD>)";
default: return "δ֪";
}
}
static uint16_t rec_sum(const rst_rec_t *r)
{
const uint8_t *p = (const uint8_t *)r;
uint16_t s = 0;
for (int i = 0; i < 14; i++) s += p[i]; /* magic+seq+reason+boot_seen+rsvd+uptime */
return s;
}
static int rec_valid(const rst_rec_t *r)
{
return r->magic == RST_REC_MAGIC && r->crc16 == rec_sum(r);
}
static void rec_read(uint8_t slot, rst_rec_t *r)
{
W25Q64_Read(RST_LOG_ADDR + (uint32_t)slot * W25Q64_SECTOR_SIZE, (uint8_t *)r, RST_REC_SIZE);
}
static void rec_write(uint8_t slot, rst_rec_t *r)
{
r->crc16 = rec_sum(r);
/* ÿ<><C3BF><EFBFBD><EFBFBD>ռһ<D5BC><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>дǰ<D0B4>Ȳ<EFBFBD><C8B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NOR ֻ<><D6BB> 1->0 <20><>λ<EFBFBD><CEBB> */
W25Q64_EraseRegion(RST_LOG_ADDR + (uint32_t)slot * W25Q64_SECTOR_SIZE, W25Q64_SECTOR_SIZE);
W25Q64_WriteBuffer(RST_LOG_ADDR + (uint32_t)slot * W25Q64_SECTOR_SIZE, (const uint8_t *)r, RST_REC_SIZE);
}
/* <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7>¼<EFBFBD><C2BC><EFBFBD><EFBFBD> -1 */
static int find_newest(uint32_t *seq_out)
{
rst_rec_t r;
int best = -1;
uint32_t best_seq = 0;
for (uint8_t i = 0; i < RST_LOG_SLOTS; i++) {
rec_read(i, &r);
if (rec_valid(&r) && (best < 0 || (int32_t)(r.seq - best_seq) > 0)) {
best = i;
best_seq = r.seq;
}
}
if (seq_out) *seq_out = best_seq;
return best;
}
/* ׷<><D7B7>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>θ<EFBFBD><CEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɣ<EFBFBD> */
static void append_record(uint8_t reason, uint32_t uptime_sec)
{
uint32_t seq = 0;
int newest = find_newest(&seq);
int slot = (newest < 0) ? 0 : (newest + 1) % RST_LOG_SLOTS;
rst_rec_t r;
memset(&r, 0xFF, sizeof(r));
r.magic = RST_REC_MAGIC;
r.seq = seq + 1;
r.reason = reason;
r.boot_seen = 0xFF;
r.uptime_sec = uptime_sec;
rec_write((uint8_t)slot, &r);
}
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λǰ<CEBB><C7B0><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8>ԭ<EFBFBD>򣨹<EFBFBD><F2A3A8B9><EFBFBD> RAM<41><4D><EFBFBD>ȸ<EFBFBD>λ<EFBFBD><CEBB> APP <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1> */
void reset_log_mark(uint8_t reason)
{
hlw8032_save(); /* <20>ƻ<EFBFBD><C6BB>ڸ<EFBFBD>λǰ<CEBB><C7B0><EFBFBD>ۼƵ<DBBC><C6B5><EFBFBD><EFBFBD><EFBFBD> EEPROM<4F><4D><EFBFBD>ޱ仯ʱ<E4BBAF>ղ<EFBFBD><D5B2><EFBFBD><EFBFBD><EFBFBD> */
BOOT_SHARE->pending_reason = reason;
boot_share_store();
}
/* ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> RAM<41><4D><EFBFBD>ȸ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
void reset_log_tick(uint32_t uptime_s)
{
BOOT_SHARE->uptime_sec = uptime_s;
boot_share_store();
}
/* <20>ⲿ<EFBFBD>ϵ<EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>PA0 <20>͵<EFBFBD><CDB5><EFBFBD> = 12V <20>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>¼ */
void reset_log_power_loss(void)
{
uint32_t up = boot_share_valid() ? BOOT_SHARE->uptime_sec : 0xFFFFFFFFu;
uint32_t m = up / 60;
log_warn("> <20>ϵ<EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD><EFBFBD>ⲿ 12V <20>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> %u<><75>%02uСʱ%02u<32><75>%02u<32><75>",
(unsigned)(m / 1440), (unsigned)((m % 1440) / 60), (unsigned)(m % 60), (unsigned)(up % 60));
append_record(RSN_POWER_LOSS, up);
}
/*==== <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> BL <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> CSR + Ԥ<><D4A4>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɱ<EFBFBD><C9B1>μ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD> 10 <20><> ====*/
void reset_log_boot(void)
{
uint8_t reason = RSN_UNKNOWN;
uint32_t up = 0xFFFFFFFFu;
int skip_new = 0;
if (boot_share_valid()) {
uint32_t csr = BOOT_SHARE->csr_flags;
up = BOOT_SHARE->uptime_sec; /* <20>ȸ<EFBFBD>λʱ<CEBB><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> */
if ((csr & RCC_CSR_SFTRSTF) && BOOT_SHARE->pending_reason != 0) {
reason = (uint8_t)BOOT_SHARE->pending_reason;
} else if (csr & RCC_CSR_SFTRSTF) {
reason = RSN_SOFT_GENERIC;
} else if (csr & RCC_CSR_IWDGRSTF) {
reason = RSN_WATCHDOG;
} else if (csr & RCC_CSR_WWDGRSTF) {
reason = RSN_WATCHDOG;
} else if (csr & RCC_CSR_PINRSTF) {
reason = RSN_PIN_RESET;
} else if (csr & RCC_CSR_PORRSTF) {
reason = RSN_POWER_ON;
}
}
/* <20>ϵ<EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>ѣ<EFBFBD><D1A3><EFBFBD><EFBFBD>޸<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>ϵ<EFBFBD>ʱ<EFBFBD><CAB1>Ԥд<D4A4><D0B4>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ+BL <EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
{
uint32_t seq;
int newest = find_newest(&seq);
if (newest >= 0) {
rst_rec_t last;
rec_read((uint8_t)newest, &last);
if (last.reason == RSN_POWER_LOSS && last.boot_seen == 0xFF) {
last.boot_seen = 0x00;
rec_write((uint8_t)newest, &last); /* λ<><CEBB>ת 1->0 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
skip_new = 1;
log_info("> <20>ϴ<EFBFBD>Ϊ<EFBFBD>ϵ<EFBFBD><CFB5>ػ<EFBFBD><D8BB><EFBFBD><EFBFBD>Ѽ<EFBFBD>¼<EFBFBD><C2BC>");
}
}
}
if (!skip_new) {
append_record(reason, up);
}
/* <20><><EFBFBD>ο<EFBFBD><CEBF><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> RAM ״̬<D7B4><CCAC><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>¼ƣ<C2BC> */
BOOT_SHARE->pending_reason = 0;
BOOT_SHARE->uptime_sec = 0;
BOOT_SHARE->magic = BOOT_SHARE_MAGIC;
boot_share_store();
/* <20><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD> 10 <20><><EFBFBD><EFBFBD><EFBFBD>¡<EFBFBD><C2A1>ɣ<EFBFBD><C9A3><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD>Ź̶<C5B9> 1~10<31><30>[1] <20><><EFBFBD>£<EFBFBD>д<EFBFBD><D0B4><EFBFBD>󸲸<EFBFBD><F3B8B2B8><EFBFBD><EFBFBD>ɣ<EFBFBD> */
log_info("> <20><>ʷ<EFBFBD><CAB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>¡<EFBFBD><C2A1>ɣ<EFBFBD>:");
uint32_t newest_seq;
int newest = find_newest(&newest_seq);
if (newest < 0) {
log_info(" <20><><EFBFBD>޼<EFBFBD>¼<EFBFBD><C2BC>");
return;
}
for (int i = 0; i < RST_LOG_SLOTS; i++) {
int slot = (newest - i + RST_LOG_SLOTS) % RST_LOG_SLOTS;
rst_rec_t r;
rec_read((uint8_t)slot, &r);
if (!rec_valid(&r)) continue;
if (r.uptime_sec == 0xFFFFFFFFu) {
log_info(" [%d] <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>: %s <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>: δ֪",
i + 1, reason_str(r.reason));
} else {
uint32_t m = r.uptime_sec / 60;
log_info(" [%d] <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>: %s <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>: %u<><75>%02uСʱ%02u<32><75>",
i + 1, reason_str(r.reason),
(unsigned)(m / 1440), (unsigned)((m % 1440) / 60), (unsigned)(m % 60));
}
}
}