///-----------------------------------------------------------------------------
/// ADS1243 驱动 - Arduino Nano
/// 硬件配置: CS 接地, PDWN 接 VDD
///-----------------------------------------------------------------------------
#include <SPI.h>

// ==================== 引脚定义 ====================
// CS 已接地,不需要定义
// PDWN 已接 VDD,不需要定义
const int PIN_DRDY  = 9;      // 数据就绪
const int PIN_LED   = 13;     // 板载 LED

// ==================== SPI 设置 ====================
SPISettings spiSettings(250000, MSBFIRST, SPI_MODE1);

// ==================== 寄存器地址 ====================
enum ADS1243_REG {
    SETUP_REG = 0x00,
    MUX_REG   = 0x01,
    ACR_REG   = 0x02,
    ODAC_REG  = 0x03,
    DIO_REG   = 0x04,
    DIR_REG   = 0x05,
    IOCON_REG = 0x06,
    OCR0_REG  = 0x07,
    OCR1_REG  = 0x08,
    OCR2_REG  = 0x09,
    FSR0_REG  = 0x0A,
    FSR1_REG  = 0x0B,
    FSR2_REG  = 0x0C,
    DOR2_REG  = 0x0D,
    DOR1_REG  = 0x0E,
    DOR0_REG  = 0x0F
};

// ==================== 命令 ====================
enum ADS1243_CMD {
    RDATA_CMD     = 0x01,
    RDATAC_CMD    = 0x03,
    STOPC_CMD     = 0x0F,
    RREG_CMD      = 0x10,
    WREG_CMD      = 0x50,
    SELFCAL_CMD   = 0xF0,
    SELFOCAL_CMD  = 0xF1,
    SELFGCAL_CMD  = 0xF2,
    SYSOCAL_CMD   = 0xF3,
    SYSGCAL_CMD   = 0xF4,
    WAKEUP_CMD    = 0xFB,
    DSYNC_CMD     = 0xFC,
    SLEEP_CMD     = 0xFD,
    RESET_CMD     = 0xFE
};

// ==================== 寄存器位定义 ====================
#define SETUP_BOCS    0x08
#define SETUP_GAIN_1   0x00
#define SETUP_GAIN_2   0x01
#define SETUP_GAIN_4   0x02
#define SETUP_GAIN_8   0x03
#define SETUP_GAIN_16  0x04
#define SETUP_GAIN_32  0x05
#define SETUP_GAIN_64  0x06
#define SETUP_GAIN_128 0x07

#define ACR_U_BIPOLAR  0x40
#define ACR_SPEED      0x20
#define ACR_BUFEN      0x10
#define ACR_RANGE      0x04
#define ACR_DR_15HZ    0x00
#define ACR_DR_7_5HZ   0x01
#define ACR_DR_3_75HZ  0x02

// ==================== 全局变量 ====================
int32_t adcValue;

// ==================== SPI 事务宏(CS 已接地,无需控制) ====================
#define SPI_START() do { \
    SPI.beginTransaction(spiSettings); \
} while(0)

#define SPI_END() do { \
    SPI.endTransaction(); \
} while(0)

// ==================== 核心函数 ====================

/**
 * @brief 等待 DRDY 变为低电平(数据就绪)
 * @param timeout_ms 超时时间(毫秒)
 * @return true=就绪, false=超时
 */
static bool waitDrdy(unsigned long timeout_ms = 1000) {
    unsigned long start = millis();
    while (digitalRead(PIN_DRDY) == HIGH) {
        if (millis() - start > timeout_ms) {
            return false;
        }
    }
    return true;
}

/**
 * @brief 发送单字节命令
 */
static void sendCmd(uint8_t cmd) {
    if (!waitDrdy()) return;
    SPI_START();
    SPI.transfer(cmd);
    SPI_END();
    // 校准命令需要额外等待
    if (cmd == SELFCAL_CMD || cmd == SELFOCAL_CMD || 
        cmd == SELFGCAL_CMD || cmd == SYSOCAL_CMD || 
        cmd == SYSGCAL_CMD) {
        delay(200);
    }
}

/**
 * @brief 写寄存器
 */
static void writeReg(uint8_t reg, uint8_t value) {
    if (!waitDrdy()) return;
    SPI_START();
    SPI.transfer(WREG_CMD | reg);
    SPI.transfer(0x00);        // 写入 1 个寄存器
    SPI.transfer(value);
    SPI_END();
}

/**
 * @brief 读寄存器
 */
static uint8_t readReg(uint8_t reg) {
    if (!waitDrdy()) return 0xFF;
    SPI_START();
    SPI.transfer(RREG_CMD | reg);
    SPI.transfer(0x00);        // 读取 1 个寄存器
    uint8_t value = SPI.transfer(0xFF);
    SPI_END();
    return value;
}

/**
 * @brief 读取 ADC 转换数据(24位有符号)
 */
static int32_t readData(void) {
    if (!waitDrdy()) return 0;
    
    SPI_START();
    SPI.transfer(RDATA_CMD);
    delayMicroseconds(50);     // 等待数据准备 (t6)
    
    uint32_t raw = 0;
    raw |= (uint32_t)SPI.transfer(0xFF) << 16;
    raw |= (uint32_t)SPI.transfer(0xFF) << 8;
    raw |= (uint32_t)SPI.transfer(0xFF);
    SPI_END();
    
    return (int32_t)(raw << 8) >> 8;
}

/**
 * @brief 读取完整的校准寄存器值(24位)
 */
static uint32_t readCalReg(uint8_t reg_high) {
    uint32_t value = 0;
    value |= (uint32_t)readReg(reg_high) << 16;
    value |= (uint32_t)readReg(reg_high + 1) << 8;
    value |= (uint32_t)readReg(reg_high + 2);
    return value;
}

/**
 * @brief 设置通道和增益
 * @param pos_channel 正输入端 0~7 (AIN0~AIN7)
 * @param neg_channel 负输入端 0~7 (AIN0~AIN7)
 * @param gain        0~7 (1,2,4,8,16,32,64,128)
 */
static void setChannel(uint8_t pos_channel, uint8_t neg_channel, uint8_t gain) {
    if (pos_channel > 7 || neg_channel > 7) return;
    writeReg(MUX_REG, (pos_channel << 4) | neg_channel);
    writeReg(SETUP_REG, gain & 0x07);
}

/**
 * @brief 执行自校准(偏移+增益)
 */
static void selfCalibrate(void) {
    uint8_t setup = readReg(SETUP_REG);
    uint8_t current_gain = setup & 0x07;
    
    // 增益校准:PGA 必须为 1
    if (current_gain != SETUP_GAIN_1) {
        writeReg(SETUP_REG, SETUP_GAIN_1);
        delay(10);
    }
    sendCmd(SELFGCAL_CMD);
    
    // 恢复增益并做偏移校准
    if (current_gain != SETUP_GAIN_1) {
        writeReg(SETUP_REG, current_gain);
        delay(10);
    }
    sendCmd(SELFOCAL_CMD);
}

/**
 * @brief 打印所有寄存器(调试用)
 */
static void printRegisters(void) {
    Serial.println("--- ADC Registers ---");
    Serial.print("SETUP: 0x"); Serial.println(readReg(SETUP_REG), HEX);
    Serial.print("MUX:   0x"); Serial.println(readReg(MUX_REG), HEX);
    Serial.print("ACR:   0x"); Serial.println(readReg(ACR_REG), HEX);
    Serial.print("ODAC:  0x"); Serial.println(readReg(ODAC_REG), HEX);
    Serial.print("DIO:   0x"); Serial.println(readReg(DIO_REG), HEX);
    Serial.print("DIR:   0x"); Serial.println(readReg(DIR_REG), HEX);
    Serial.print("IOCON: 0x"); Serial.println(readReg(IOCON_REG), HEX);
    
    uint32_t ocr = readCalReg(OCR2_REG);
    uint32_t fsr = readCalReg(FSR2_REG);
    Serial.print("OCR:   0x"); Serial.println(ocr, HEX);
    Serial.print("FSR:   0x"); Serial.println(fsr, HEX);
    Serial.println("----------------------");
}

// ==================== 初始化 ====================
void setup() {
    pinMode(PIN_DRDY, INPUT);
    pinMode(PIN_LED, OUTPUT);
    
    // PDWN 已接 VDD,不需要控制
    // CS 已接地,不需要控制
    
    SPI.begin();
    
    Serial.begin(115200);
    while (!Serial) { delay(10); }
    
    Serial.println("ADS1243 Initializing...");
    Serial.println("CS = GND, PDWN = VDD");
    
    // 1. 复位芯片
    sendCmd(RESET_CMD);
    delay(10);
    
    // 2. 配置: AIN0(+) AIN1(-), 增益 1
    setChannel(0, 1, SETUP_GAIN_1);
    
    // 3. 配置 ACR: 双极性 + 缓冲器 + 15SPS
    writeReg(ACR_REG, ACR_U_BIPOLAR | ACR_BUFEN | ACR_DR_15HZ);
    
    // 4. 自校准
    Serial.println("Self-calibrating...");
    selfCalibrate();
    
    // 5. 打印寄存器
    printRegisters();
    
    Serial.println("Ready!");
}

// ==================== 主循环 ====================
void loop() {
    adcValue = readData();
    
    Serial.print("ADC: ");
    Serial.println(adcValue);
    
    digitalWrite(PIN_LED, HIGH);
    delay(50);
    digitalWrite(PIN_LED, LOW);
    
    delay(500);
}