#include "ADS1256.h"
#include "cmsis_os.h"
#include "printf.h"
/**
  ******************************************************************************
  * @file    ADS1256.c
  ******************************************************************************
  * @attention
  *	ADS1256模块
  * +5V   <------  5.0V      5V供电
  * GND   -------  GND       地
  * DRDY  ------>  PA11      准备就绪 低准备好  高未准备好
  *	CS    <------  PB12      SPI_CS 低有效，操作完拉高
  *	DIN   <------  PB15      SPI_MOSI
  *	DOUT  ------>  PB14      SPI_MISO
  *	SCLK  <------  PB13      SPI时钟
  *	GND   -------  GND       地
  *	PDWN  <------  VDD       掉电控制 常高
  *	RST   <------  PA8       复位信号 常高，拉低再拉高生效复位
  *	
  *	ADS1256基本特性:
  *	1、模拟部分供电5V;
  *	2、SPI数字接口电平：3.3V
  *	3、PGA设置范围： 1、2、4、8、16、32、64、
  *	4、参考电压2.5V (推荐缺省的，外置的）
  *	5、输入电压范围：PGA = 1 时, 可输入正负5V
  *	6. 自动校准 （当设置了PGA,BUF使能、数据采样率时，会启动自校准)
  *	7. 输入的缓冲器可设置启用和关闭（一般选启用）
  *	外部晶振频率 = 7.68MHz,
  *	时钟频率 tCLK = 1/7.68M = 0.13uS
  *	输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

  *	对SPI的时钟速度要求: (ads1256.pdf page 6)
  *	最快 4个tCLK = 0.52uS
  *	最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

  *	SCL高电平和低电平持续时间最小 200ns

  *	RREG, WREG, RDATA 命令之后，需要延迟 4 * tCLK = 0.52uS;
  *	RDATAC, RESET, SYNC 命令之后，需要延迟 24 * tCLK = 3.12uS;

  *	实际测试，在3.3V上电后, 及时不做任何配置，ADS125的DRDY 口线即开始输出脉冲信号（2.6us高,33.4低，频率30KHz）

  ******************************************************************************
  */

extern SPI_HandleTypeDef ADS1256_SPI_HANDLE;

void ADS1256_SendCommand(uint8_t cmd) { // 发送单字节命令给ADS
    ADS1256_CS_LOW();	
		for (volatile uint8_t i = 0; i < 5; i++) {}  // ≈300~500ns 延迟	
    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, &cmd, 1, SPI_TIMEOUT);
		for (volatile uint8_t i = 0; i < 5; i++) {}  // ≈300~500ns 延迟
    ADS1256_CS_HIGH();
}

void ADS1256_WriteRegister(uint8_t reg, uint8_t value) {
    uint8_t tx[3] = {
        ADS1256_CMD_WREG | (reg & 0x0F),
        0x00,  // 写1个寄存器
        value
    };
    ADS1256_CS_LOW();
    for (volatile uint8_t i = 0; i < 5; i++) {}
    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 3, SPI_TIMEOUT);
    for (volatile uint8_t i = 0; i < 5; i++) {}
    ADS1256_CS_HIGH();
}

uint8_t ADS1256_ReadRegister(uint8_t reg) {
    uint8_t tx[2] = { ADS1256_CMD_RREG | (reg & 0x0F), 0x00 };
    uint8_t rx = 0;
    ADS1256_CS_LOW();
    for (volatile uint8_t i = 0; i < 5; i++) {}
    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 2, SPI_TIMEOUT);
    for (volatile uint8_t i = 0; i < 5; i++) {}  // ≈读取前延迟
    HAL_SPI_Receive(&ADS1256_SPI_HANDLE, &rx, 1, SPI_TIMEOUT);
    for (volatile uint8_t i = 0; i < 5; i++) {}
    ADS1256_CS_HIGH();
    return rx;
}


void ADS1256_Reset(void) { // 复位
    ADS1256_RST_LOW();
    osDelay(1);
    ADS1256_RST_HIGH();
    osDelay(5);
		ADS1256_SendCommand(ADS1256_CMD_RESET); // 软件复位
    osDelay(5);
}



void ADS1256_SetChannel(uint8_t mux) { // 设置输入通道（MUX 寄存器值）
    ADS1256_WriteRegister(ADS1256_REG_MUX, mux);
    ADS1256_SendCommand(ADS1256_CMD_SYNC);
    ADS1256_SendCommand(ADS1256_CMD_WAKEUP);
}

void ADS1256_SetGain(ADS1256_Gain_t gain) { // 设置增益
    uint8_t adcon = ADS1256_ReadRegister(ADS1256_REG_ADCON);
    adcon &= 0xF8;
    adcon |= (gain & 0x07);
    ADS1256_WriteRegister(ADS1256_REG_ADCON, adcon);
}

void ADS1256_SetDataRate(ADS1256_DataRate_t dr) { // 设置采样率
    ADS1256_WriteRegister(ADS1256_REG_DRATE, (uint8_t)dr);
}

void ADS1256_StartConversion(void) { // 启动一次转换
    ADS1256_SendCommand(ADS1256_CMD_SYNC);
    ADS1256_SendCommand(ADS1256_CMD_WAKEUP);
    ADS1256_SendCommand(ADS1256_CMD_RDATA);
}
uint8_t ADS1256_ReadID(void) { // 读取芯片 ID（高 4 位） ID高4位应该是0x03
    ADS1256_SendCommand(ADS1256_CMD_SYNC);
		osDelay(1);  // 延迟 ≥6us，这里用1ms最保险，兼容RTOS调度延迟
    ADS1256_SendCommand(ADS1256_CMD_WAKEUP);
		for (volatile uint8_t i = 0; i < 5; i++) {}  // 补一点 CS 往后延
		uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS);
    return (status >> 4) & 0x0F; 
}
bool ADS1256_ReadData(int32_t* out) { // 读取数据（需判断 DRDY 是否为低）
    uint8_t rx[3];

    if (HAL_GPIO_ReadPin(ADS1256_DRDY_GPIO_PORT, ADS1256_DRDY_PIN) != GPIO_PIN_RESET) {
			ADS_PRINTF("[ADS1256] DRDY pin not low, skipping read.\r\n");
        return false;
    }

    ADS1256_CS_LOW();
    HAL_SPI_Receive(&ADS1256_SPI_HANDLE, rx, 3, SPI_TIMEOUT);
    ADS1256_CS_HIGH();

    *out = ((int32_t)rx[0] << 16) | ((int32_t)rx[1] << 8) | rx[2];
    if (*out & 0x800000) *out |= 0xFF000000; // Sign extend if negative
    return true;
}

float ADS1256_ConvertToVoltage(int32_t raw, float vref, int gain) {
    return ((float)raw / 8388608.0f) * (vref / gain); // V = (raw / 2的23次方 —— 8388608)* (vref / gain) 单位V ，2的22次方= 4194304
}
void ADS1256_SetClockSource(uint8_t useInternal) // CLK = 0：使用外部晶振 1：使用内部晶振
{
		if (useInternal > 1) return;

    uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS);

    if (useInternal)
        status |= (1 << 2);   // CLK = 1：使用内部晶振
    else
        status &= ~(1 << 2);  // CLK = 0：使用外部晶振

    ADS1256_WriteRegister(ADS1256_REG_STATUS, status);
}


bool ADS1256_IsUsingExternalClock(void)
{
    uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS);
    return (status & (1 << 3)) != 0; // CLKSTAT
}

void ADS1256_Init(void) { // 初始化 ADS1256
//    ADS1256_Reset();
//    osDelay(50);
		// 默认外部晶振，连续采样模式
	HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_SET);
	
		ADS1256_SetClockSource(0);		// 0使用外部晶振 1内部晶振
		ADS1256_WriteRegister(ADS1256_REG_STATUS, 0x06); // 0000 0 110 自动校准开启（ACAL = 1）, 输入缓冲器关闭（BUFEN = 0）
		ADS1256_WriteRegister(ADS1256_REG_ADCON, 0x20);  // 时钟输出禁用（CLKOUT = 00）, 增益为1倍（输入是几mV，增益增大至8）
		ADS1256_SetDataRate(ADS1256_DR_1000SPS); // ADS1256_DR_1000SPS
		ADS1256_SetChannel(ADS1256_MUX_AIN0_AINCOM); // AIN1 - AINCOM
		ADS1256_SendCommand(ADS1256_CMD_SELFCAL);// 启动自动增益和偏移校准 必须最后执行该指令
		 ADS1256_SendCommand(ADS1256_CMD_RDATAC); // 连续采样
} 
