/*
 * 模块名称：SD2506API-G RTC 实时时钟驱动
 * 模块功能：SD2506API-G 高精度温补实时时钟模块 I2C 驱动，提供时间读写、
 *          温度读取、电池电压检测、ID 读取等功能
 * 适用平台：STM32F407ZGT6，I2C1 接口 (PB6-SCL, PB7-SDA)
 * 作者：王建锋
 * 创建日期：2026-07-17
 * 修改记录：
 *     2026-07-17  王建锋  创建初始版本，参考 SD2506API-G Ver2.0 手册
 */

#ifndef __SD2506_H
#define __SD2506_H

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"

/* ======================== I2C 地址 ======================== */

/*
 * SD2506API-G 7位器件地址: 0x32
 * HAL库使用8位地址: 写 0x64, 读 0x65
 */
#define SD2506_I2C_ADDR             0x32U
#define SD2506_I2C_ADDR_WRITE       0x64U
#define SD2506_I2C_ADDR_READ        0x65U

/* ======================== 寄存器地址定义 ======================== */

/* 实时时钟寄存器 (00H~06H) */
#define SD2506_REG_SEC              0x00U   /* 秒 00~59 BCD */
#define SD2506_REG_MIN              0x01U   /* 分 00~59 BCD */
#define SD2506_REG_HOUR             0x02U   /* 时 00~23 BCD, bit7=12/24 */
#define SD2506_REG_WEEK             0x03U   /* 星期 00~06 BCD */
#define SD2506_REG_DAY              0x04U   /* 日 01~31 BCD */
#define SD2506_REG_MON              0x05U   /* 月 01~12 BCD */
#define SD2506_REG_YEAR             0x06U   /* 年 00~99 BCD */

/* 报警寄存器 (07H~0EH) */
#define SD2506_REG_AL_SEC           0x07U   /* 秒报警 */
#define SD2506_REG_AL_MIN           0x08U   /* 分报警 */
#define SD2506_REG_AL_HOUR          0x09U   /* 时报警 */
#define SD2506_REG_AL_WEEK          0x0AU   /* 星期报警 */
#define SD2506_REG_AL_DAY           0x0BU   /* 日报警 */
#define SD2506_REG_AL_MON           0x0CU   /* 月报警 */
#define SD2506_REG_AL_YEAR          0x0DU   /* 年报警 */
#define SD2506_REG_AL_EN            0x0EU   /* 报警允许寄存器 */

/* 控制寄存器 */
#define SD2506_REG_CTR1             0x0FH   /* 控制寄存器1 */
#define SD2506_REG_CTR2             0x10U   /* 控制寄存器2 */
#define SD2506_REG_CTR3             0x11U   /* 控制寄存器3 */

/* 倒计时寄存器 (13H~15H) */
#define SD2506_REG_CNT0             0x13U   /* 倒计时字节0 (LSB) */
#define SD2506_REG_CNT1             0x14U   /* 倒计时字节1 */
#define SD2506_REG_CNT2             0x15U   /* 倒计时字节2 (MSB) */

/* 温度寄存器 */
#define SD2506_REG_TEMP             0x16U   /* 温度值 (bit7=符号位) */
#define SD2506_REG_AGTC             0x17U   /* IIC控制寄存器 AGTC */
#define SD2506_REG_CHARGE           0x18U   /* 充电选择寄存器 */
#define SD2506_REG_CTR4             0x19U   /* 扩展控制寄存器 CTR4 */
#define SD2506_REG_CTR5             0x1AU   /* 控制寄存器 CTR5 */
#define SD2506_REG_BAT_VAL          0x1BU   /* 电池电压低8位 */

/* 温度报警及历史 */
#define SD2506_REG_TEMP_AL          0x1CU   /* 低温报警温度值 */
#define SD2506_REG_TEMP_AH          0x1DU   /* 高温报警温度值 */
#define SD2506_REG_TEMP_HIS_L       0x1EU   /* 历史低温 */
#define SD2506_REG_TEMP_HIS_H       0x1FU   /* 历史高温 */

/* 用户 SRAM (2CH~71H) */
#define SD2506_REG_SRAM_START       0x2CU
#define SD2506_REG_SRAM_END         0x71U
#define SD2506_SRAM_SIZE            70U     /* 70字节 */

/* ID 码 (72H~79H) */
#define SD2506_REG_ID_START         0x72U
#define SD2506_REG_ID_END           0x79U
#define SD2506_ID_SIZE              8U      /* 8字节 */

/* ======================== 控制位定义 ======================== */

/* 控制寄存器 1 (0FH) */
#define SD2506_CTR1_ARST            (1U << 5)   /* 自动复位使能 */
#define SD2506_CTR1_INTAF           (1U << 3)   /* 报警中断标志 */
#define SD2506_CTR1_INTDF           (1U << 2)   /* 倒计时中断标志 */
#define SD2506_CTR1_BLF             (1U << 0)   /* 电池欠压标志 */

/* 控制寄存器 2 (10H) */
#define SD2506_CTR2_INTAE           (1U << 5)   /* 报警中断允许 */
#define SD2506_CTR2_INTFE           (1U << 4)   /* 频率中断允许 */
#define SD2506_CTR2_INTDE           (1U << 3)   /* 倒计时中断允许 */
#define SD2506_CTR2_IM              (1U << 2)   /* 中断模式: 0=单事件, 1=周期 */
#define SD2506_CTR2_INTS1           (1U << 1)   /* INT输出选择 bit1 */
#define SD2506_CTR2_INTS0           (1U << 0)   /* INT输出选择 bit0 */

/* 报警允许寄存器 (0EH) */
#define SD2506_AL_EN_EAY            (1U << 6)   /* 年报警允许 */
#define SD2506_AL_EN_EAMO           (1U << 5)   /* 月报警允许 */
#define SD2506_AL_EN_EAD            (1U << 4)   /* 日报警允许 */
#define SD2506_AL_EN_EAW            (1U << 3)   /* 星期报警允许 */
#define SD2506_AL_EN_EAH            (1U << 2)   /* 时报警允许 */
#define SD2506_AL_EN_EAMN           (1U << 1)   /* 分报警允许 */
#define SD2506_AL_EN_EAS            (1U << 0)   /* 秒报警允许 */

/* 24/12小时制位 */
#define SD2506_HOUR_24              (1U << 7)   /* bit7=1 表示24小时制 */

/* ======================== 充电配置 ======================== */

/* 充电寄存器 (18H) 建议上电写入值: 0x82 (开启充电, 断开) */
#define SD2506_CHARGE_EN            (1U << 7)   /* 充电允许位 */
#define SD2506_CHARGE_2K            (0U << 0)   /* 2K电阻 */
#define SD2506_CHARGE_5K            (1U << 0)   /* 5K电阻 */

/* ======================== 写保护配置 ======================== */

/* 写允许时 0FH 寄存器建议值: 0xFF (WRTC1=1, WRTC2=1, WRTC3=1) */
#define SD2506_CTR1_WRITE_ON        0xFFU
/* 写禁止时 0FH 寄存器建议值: 0x7B (WRTC1=0, WRTC2=0, WRTC3=0, ARST=1) */
#define SD2506_CTR1_WRITE_OFF       0x7BU

/* ======================== 返回值定义 ======================== */

#define SD2506_OK                   0
#define SD2506_ERROR               -1
#define SD2506_I2C_ERROR           -2

/* ======================== 超时时间 ======================== */

#define SD2506_I2C_TIMEOUT_MS      100

/* ======================== 数据结构 ======================== */

/*
 * RTC 时间日期结构体
 * year: 2000~2099
 * month: 1~12
 * day: 1~31
 * hour: 0~23 (24小时制)
 * minute: 0~59
 * second: 0~59
 * week: 0~6 (0=星期天, 1=星期一, ..., 6=星期六)
 */
typedef struct {
    uint16_t year;
    uint8_t  month;
    uint8_t  day;
    uint8_t  hour;
    uint8_t  minute;
    uint8_t  second;
    uint8_t  week;
} sd2506_time_t;

/* ======================== 函数声明 ======================== */

/*
 * 函数功能：初始化 SD2506API-G RTC
 * 入口参数：无
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：CubeMX 已完成 I2C1 初始化
 * 函数说明：1. 读取芯片 ID 验证通信
 *           2. 上电重置充电寄存器 18H=82H
 *           3. 配置 24 小时制、开自动复位
 */
int sd2506_init(void);

/*
 * 函数功能：设置 RTC 时间日期
 * 入口参数：time - 时间结构体指针，包含要设置的时间
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：1. 先开写保护
 *           2. 一次性写入 7 字节时间数据 (00H~06H)
 *           3. 关闭写保护
 *           注意：不可单独写某一个时间寄存器
 */
int sd2506_set_time(const sd2506_time_t *p_time);

/*
 * 函数功能：读取 RTC 时间日期
 * 入口参数：time - 时间结构体指针，用于存储读取结果
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：1. 一次读取 7 字节时间数据 (00H~06H)
 *           2. BCD 转十进制
 *           3. 屏蔽小时 bit7 (12/24标志位)
 */
int sd2506_get_time(sd2506_time_t *p_time);

/*
 * 函数功能：读取芯片内部温度
 * 入口参数：temp - 温度输出指针 (整数部分, 有符号)
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：读取 16H 寄存器，bit7 为符号位，范围 -40~+85
 */
int sd2506_get_temperature(int8_t *p_temp);

/*
 * 函数功能：读取电池电压 (毫伏)
 * 入口参数：voltage - 电压输出指针 (单位: mV)
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：1. 读取 1AH bit7 (BAT8_VAL) 和 1BH (BAT_VL)
 *           2. 组合 9 位数据得到电压值 (如 0x135 = 309 = 3.09V)
 */
int sd2506_get_battery_voltage(uint16_t *p_voltage);

/*
 * 函数功能：读取芯片 8 字节 ID
 * 入口参数：id - 8 字节输出缓冲区
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：读取 72H~79H 共 8 字节唯一 ID
 */
int sd2506_get_id(uint8_t p_id[8]);

/*
 * 函数功能：读取用户 SRAM 数据
 * 入口参数：addr - SRAM 起始地址 (0~69)
 *           buf  - 数据输出缓冲区
 *           len  - 读取长度 (1~70)
 * 返回值：0 - 成功，-2 - I2C 通信错误，-1 - 参数错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：SRAM 地址范围 0~69，对应寄存器 2CH~71H
 */
int sd2506_read_sram(uint8_t addr, uint8_t *p_buf, uint8_t len);

/*
 * 函数功能：写入用户 SRAM 数据
 * 入口参数：addr - SRAM 起始地址 (0~69)
 *           buf  - 数据输入缓冲区
 *           len  - 写入长度 (1~70)
 * 返回值：0 - 成功，-2 - I2C 通信错误，-1 - 参数错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：SRAM 地址范围 0~69，对应寄存器 2CH~71H
 *           SRAM 无需开写保护即可写入
 */
int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len);

/*
 * 函数功能：设置报警中断
 * 入口参数：time  - 报警时间结构体
 *           mask  - 报警匹配掩码 (SD2506_AL_EN_xxx 位或组合)
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：1. 开写保护
 *           2. 写入报警寄存器 (07H~0EH)
 *           3. 使能报警中断 INTAE
 *           4. 关写保护
 */
int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask);

/*
 * 函数功能：清除报警中断标志
 * 入口参数：无
 * 返回值：0 - 成功，-2 - I2C 通信错误
 * 限定条件：sd2506_init() 已调用
 * 函数说明：读取 CTR1 自动清除 INTAF (ARST=1 时)
 */
int sd2506_clear_alarm(void);

/*
 * 函数功能：读取当前 0FH 控制寄存器1 状态
 * 入口参数：val - 输出值指针
 * 返回值：0 - 成功，-2 - I2C 通信错误
 */
int sd2506_read_ctr1(uint8_t *p_val);

/*
 * 函数功能：BCD 码转十进制
 * 入口参数：bcd - BCD 码值
 * 返回值：十进制值
 * 函数说明：内部辅助函数
 */
uint8_t sd2506_bcd_to_dec(uint8_t bcd);

/*
 * 函数功能：十进制转 BCD 码
 * 入口参数：dec - 十进制值
 * 返回值：BCD 码值
 * 函数说明：内部辅助函数
 */
uint8_t sd2506_dec_to_bcd(uint8_t dec);

#ifdef __cplusplus
}
#endif

#endif /* __SD2506_H */
