guowenxue
4 days ago 53de825c4c4d8325c02341177f62ab84897eb5ee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/**********************************************************************
 * Copyright: (C)2026 LingYun IoT System Studio
 * Author: GuoWenxue<guowenxue@gmail.com>
 *
 * Description: ISL1208 RTC driver on ISKBoard (Unlocked Core Pattern)
 *
 * ChangeLog:
 * Version    Date       Author            Description
 * V1.1.0  2026.07.08    GuoWenxue      Refactor with unlocked core functions
 *
 ***********************************************************************/
 
#include <stdio.h>
#include "isl1208.h"
 
/* 隐藏在私有源文件内部的 ISL1208 寄存器映射与参数 */
#define ISL1208_I2C_ADDR        0x6F
 
#define ISL1208_REG_SC          0x00    /* 秒 (00-59) */
#define ISL1208_REG_MN          0x01    /* 分 (00-59) */
#define ISL1208_REG_HR          0x02    /* 时 (24小时模式) */
#define ISL1208_REG_DT          0x03    /* 日 (01-31) */
#define ISL1208_REG_MO          0x04    /* 月 (01-12) */
#define ISL1208_REG_YR          0x05    /* 年 (00-99) */
#define ISL1208_REG_DW          0x06    /* 星期 (00-06) */
 
#define ISL1208_REG_SR          0x07    /* 状态寄存器 */
#define ISL1208_SR_RTCF         0x80    /* 掉电/晶振失效标志位 */
#define ISL1208_SR_WRTC         0x10    /* 写使能位 */
 
/* 前置私有静态辅助函数声明 (无锁底层业务函数) */
static int __isl1208_set_time_unlocked(const rtc_time_t *time);
static int __isl1208_get_time_unlocked(rtc_time_t *time);
 
/*
 *+---------------------------------+
 *|     RTC 公共接口函数(带锁)       |
 *+---------------------------------+
 */
 
/* I2C 设备 RTC */
static i2c_dev_t rtc;
 
/**
 * @brief  ISL1208 硬件初始化与掉电自愈函数
 * @note   只有检测到掉电(RTCF=1)或停振(ST=1)时,才强制清理控制位并激活时钟,平时不干扰原有走时
 * @param  bus: 绑定的 I2C 物理总线指针 (如 &i2c1_bus)
 * @retval 0: 初始化成功; -1: 总线通信失败或芯片未响应
 */
int isl1208_init(i2c_bus_t *bus)
{
    uint8_t sr_val;
    uint8_t sc_val;
    int rv = -1;
 
    if (!bus)
        return -1;
 
    /* 绑定设备及其设备号到 I2C 总线上 */
    i2c_bind_dev(&rtc, bus, ISL1208_I2C_ADDR);
 
    /* 将I2C总线加锁让设备独占总线 */
    i2c_lock_dev(&rtc);
 
    /* 读取当前状态寄存器 (检查 RTCF) */
    if (i2c_read(rtc.bus, rtc.dev_addr, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
    {
        goto cleanup;
    }
 
    /* 读取当前秒寄存器 (检查 ST) */
    if (i2c_read(rtc.bus, rtc.dev_addr, ISL1208_REG_SC, &sc_val, 1) != I2C_OK)
    {
        goto cleanup;
    }
 
    /* 条件触发:只要 SBIB 位为 1 证明是断电冷启动,必须强制清除解冻 */
    if (sr_val & 0x01)
    {
        printf("ISL1208 Power-Loss or Stop detected! Activating oscillator...\r\n");
 
        /* 强开写保护 (WRTC=1),并抹除 SBIB 冻结位 */
        sr_val = ISL1208_SR_WRTC;
        if (i2c_write(rtc.bus, rtc.dev_addr, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
        {
            goto cleanup;
        }
 
        /* 写入完整的 2026-01-01 00:00:00 (星期四) 基准时间 */
        uint8_t init_buf[7];
        init_buf[0] = 0x00; /* 00秒,同时最高位 ST=0 激活晶振起振 */
        init_buf[1] = 0x00; /* 00分 */
        init_buf[2] = 0x80; /* 00时,Bit7=1 代表开启 24 小时制 */
        init_buf[3] = 0x01; /* 01日 (BCD: 0x01) */
        init_buf[4] = 0x01; /* 01月 (BCD: 0x01) */
        init_buf[5] = 0x26; /* 26年 (BCD: 0x26 代表 2026年) */
        init_buf[6] = 0x04; /* 星期四 (BCD: 0x04) */
 
        /* 写入 7 个时间寄存器 */
        if (i2c_write(rtc.bus, rtc.dev_addr, ISL1208_REG_SC, init_buf, 7) != I2C_OK)
        {
            goto cleanup;
        }
 
        /* 强制将秒寄存器的最高位 ST (Stop) 清零以激活晶振 */
        sc_val &= 0x7F;
        if (i2c_write(rtc.bus, rtc.dev_addr, ISL1208_REG_SC, &sc_val, 1) != I2C_OK)
        {
            goto cleanup;
        }
 
        /* 关闭写保护,并将状态寄存器洗干净 (SBIB 清零) */
        sr_val = 0x00;
        if (i2c_write(rtc.bus, rtc.dev_addr, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
        {
            goto cleanup;
        }
    }
 
    rv = 0;
 
cleanup:
    i2c_free_dev(&rtc);
    return rv;
}
 
/**
 * @brief  应用层设置 RTC 时间接口函数(rtc_time_t格式)
 * @param  time  指向待写入时间数据的 rtc_time_t 结构体常指针
 * @retval 0:成功, -1:失败
 */
int isl1208_set_time(const rtc_time_t *time)
{
    int rv = -1;
 
    if (!rtc.bus || !time)
    {
        return -1;
    }
 
    i2c_lock_dev(&rtc);
 
    /* 调用无锁底层核心实现写操作 */
    rv = __isl1208_set_time_unlocked(time);
 
    i2c_free_dev(&rtc);
 
    return rv;
}
 
/**
 * @brief  应用层设置 RTC 时间接口函数(字符串格式)
 * @param  time_str  输入的时间字符串指针,格式如 "2026-01-01 10:00:00"
 * @retval 0:成功, -1:失败
 */
int isl1208_set_time_str(const char *time_str)
{
    rtc_time_t tm;
    int year, month, day, hour, minute, second;
 
    if (!time_str)
    {
        return -1;
    }
 
    /* 1. 解析时间字符串 */
    if (sscanf(time_str, "%d-%d-%d %d:%d:%d",
               &year, &month, &day, &hour, &minute, &second) != 6)
    {
        return -1;
    }
 
    /* 2. 填充结构体(年份仅保留低两位) */
    tm.year    = year % 100;
    tm.month   = month;
    tm.day     = day;
    tm.hour    = hour;
    tm.minute  = minute;
    tm.second  = second;
    tm.weekday = 0;
 
    /* 3. 直接调用带锁的原本接口 */
    return isl1208_set_time(&tm);
}
 
/**
 * @brief  应用层获取 RTC 时间接口函数
 * @param  time  指向用于接收时间数据的 rtc_time_t 结构体指针
 * @retval 0:成功, -1:失败
 */
int isl1208_get_time(rtc_time_t *time)
{
    int rv = -1;
 
    if (!rtc.bus || !time)
    {
        return -1;
    }
 
    i2c_lock_dev(&rtc);
 
    /* 调用无锁底层核心实现读操作 */
    rv = __isl1208_get_time_unlocked(time);
 
    i2c_free_dev(&rtc);
    return rv;
}
 
/**
 * @brief  应用层获取 RTC 时间接口函数(字符串格式)
 * @param  buf      用于存储格式化时间字符串的缓冲区指针
 * @param  buf_len  接收缓冲区长度(建议至少20字节)
 * @retval 0:成功, -1:失败
 */
int isl1208_get_time_str(char *buf, size_t buf_len)
{
    rtc_time_t tm;
    int rv = -1;
 
    if (!buf || buf_len < 20)
    {
        return -1;
    }
 
    /* 直接调用带锁的原本接口获取时间结构体 */
    rv = isl1208_get_time(&tm);
    if (rv != 0)
    {
        return rv;
    }
 
    /* 格式化为字符串输出 */
    snprintf(buf, buf_len, "20%02d-%02d-%02d %02d:%02d:%02d",
             tm.year, tm.month, tm.day,
             tm.hour, tm.minute, tm.second);
 
    return 0;
}
 
/**
 * @brief  获取并格式化打印当前 RTC 时间接口函数
 * @param  bus  指向已初始化的 I2C 总线结构体指针
 * @retval 0:成功, -1:失败
 */
int isl1208_print_time(void)
{
    char time_str[32];
 
    /* 直接调用刚刚封装好的获取字符串接口 */
    if (isl1208_get_time_str(time_str, sizeof(time_str)) != 0)
    {
        return -1;
    }
 
    /* 格式化输出 */
    printf("ISL1208 Time: %s\r\n", time_str);
    return 0;
}
 
/*
 *+---------------------------------+
 *|     RTC 私有底层函数(无锁)       |
 *+---------------------------------+
 */
 
/**
 * @brief  十进制转 BCD 码
 */
static inline uint8_t rtc_dec_to_bcd(uint8_t dec)
{
    uint8_t high;
    uint8_t low;
 
    high = dec / 10;
    low = dec % 10;
 
    return (uint8_t)((high << 4) | low);
}
 
/**
 * @brief  BCD 码转十进制
 */
static inline uint8_t rtc_bcd_to_dec(uint8_t bcd)
{
    uint8_t high;
    uint8_t low;
 
    high = bcd >> 4;
    low = bcd & 0x0F;
 
    return (uint8_t)((high * 10) + low);
}
 
/**
 * @brief  向 RTC 芯片写入时间
 */
static int __isl1208_set_time_unlocked(const rtc_time_t *time)
{
    uint8_t time_buf[7];
    uint8_t sr_val;
 
    if( !rtc.bus )
        return -1;
 
    /* 读取当前状态寄存器 */
    if (i2c_read(rtc.bus, ISL1208_I2C_ADDR, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
    {
        return -1;
    }
 
    /* 解除 RTC 写保护 (WRTC 置 1) */
    sr_val |= ISL1208_SR_WRTC;
    if (i2c_write(rtc.bus, ISL1208_I2C_ADDR, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
    {
        return -1;
    }
 
    /* 将标准十进制转换为 BCD 码并打包 */
    time_buf[0] = rtc_dec_to_bcd(time->second);
    time_buf[1] = rtc_dec_to_bcd(time->minute);
    time_buf[2] = (rtc_dec_to_bcd(time->hour) & 0x3F) | 0x80;
    time_buf[3] = rtc_dec_to_bcd(time->day);
    time_buf[4] = rtc_dec_to_bcd(time->month);
    time_buf[5] = rtc_dec_to_bcd(time->year);
    time_buf[6] = rtc_dec_to_bcd(time->weekday);
 
    /* 写入 7 个时间寄存器 */
    if (i2c_write(rtc.bus, ISL1208_I2C_ADDR, ISL1208_REG_SC, time_buf, 7) != I2C_OK)
    {
        return -1;
    }
 
    /* 恢复写保护并同时清除掉电失效位 (WRTC = 0, RTCF = 0) */
    sr_val &= ~ISL1208_SR_WRTC;
    sr_val &= ~ISL1208_SR_RTCF;
    if (i2c_write(rtc.bus, ISL1208_I2C_ADDR, ISL1208_REG_SR, &sr_val, 1) != I2C_OK)
    {
        return -1;
    }
 
    return 0;
}
 
/**
 * @brief  从 RTC 芯片读取时间
 */
static int __isl1208_get_time_unlocked(rtc_time_t *time)
{
    uint8_t time_buf[7];
 
    /* 连续读取 7 个寄存器的原始 BCD 数据 */
    if (i2c_read(rtc.bus, ISL1208_I2C_ADDR, ISL1208_REG_SC, time_buf, 7) != I2C_OK)
    {
        return -1;
    }
 
    /* 解析 BCD 码并做去噪掩码隔离 */
    time->second  = rtc_bcd_to_dec(time_buf[0] & 0x7F);
    time->minute  = rtc_bcd_to_dec(time_buf[1] & 0x7F);
    time->hour    = rtc_bcd_to_dec(time_buf[2] & 0x3F);
    time->day     = rtc_bcd_to_dec(time_buf[3] & 0x3F);
    time->month   = rtc_bcd_to_dec(time_buf[4] & 0x1F);
    time->year    = rtc_bcd_to_dec(time_buf[5]);
    time->weekday = rtc_bcd_to_dec(time_buf[6] & 0x07);
 
    return 0;
}