#include "ADS1256_soft.h"
#include "cmsis_os.h"
#include "gpio.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;

// 软件SPI发送单字节（模式1，CPOL=0, CPHA=1）
static void SoftSPI_WriteByte(uint8_t data) {
    for (uint8_t i = 0; i < 8; i++) {
        SOFT_SPI_SCK_LOW();
        // 设置MOSI
        if (data & 0x80) SOFT_SPI_MOSI_HIGH();
        else SOFT_SPI_MOSI_LOW();
        data <<= 1;
			for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
        // 产生时钟上升沿（从机采样）
        SOFT_SPI_SCK_HIGH();

        for (volatile uint8_t j = 0; j < 40; j++); // ~200ns @80MHz
    }
    SOFT_SPI_SCK_LOW(); // 保持空闲状态为低
}

// 软件SPI接收单字节
static uint8_t SoftSPI_ReadByte(void) {
    uint8_t data = 0;
    for (uint8_t i = 0; i < 8; i++) {
        data <<= 1;
        SOFT_SPI_SCK_HIGH();
        // 插入小延时（确保数据稳定）
        for (volatile uint32_t j = 0; j < 40; j++);
        if (SOFT_SPI_MISO_READ()) data |= 0x01;
        SOFT_SPI_SCK_LOW();
        for (volatile uint32_t j = 0; j < 40; j++);
    }
    return data;
}

static void ADS1256_SendCommand(uint8_t cmd) {
    ADS1256_CS_LOW();
	for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
//    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, &cmd, 1, SPI_TIMEOUT);
	SoftSPI_WriteByte(cmd);
		for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
    ADS1256_CS_HIGH();
}

void ADS1256_WriteRegister(uint8_t reg, uint8_t value) {
    uint8_t tx[3];
    tx[0] = ADS1256_CMD_WREG | (reg & 0x0F);
    tx[1] = 0x00; // write 1 register
    tx[2] = value;

    ADS1256_CS_LOW();
	for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
//    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 3, SPI_TIMEOUT);
		for (uint8_t i = 0; i < 40; i++) SoftSPI_WriteByte(tx[i]);
    ADS1256_CS_HIGH();
    osDelay(2);
}

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 (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
//    HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 2, SPI_TIMEOUT);
		SoftSPI_WriteByte(tx[0]);
    SoftSPI_WriteByte(tx[1]);
    osDelay(2);
//    HAL_SPI_Receive(&ADS1256_SPI_HANDLE, &rx, 1, SPI_TIMEOUT);
		rx = SoftSPI_ReadByte();
			for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz
    ADS1256_CS_HIGH();
    return rx;
}
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) {
        return false;
    }

    ADS1256_CS_LOW();
//    HAL_SPI_Receive(&ADS1256_SPI_HANDLE, rx, 3, SPI_TIMEOUT);
		rx[0] = SoftSPI_ReadByte();
    rx[1] = SoftSPI_ReadByte();
    rx[2] = SoftSPI_ReadByte();
    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;
}
void ADS1256_Reset(void) { // 复位
		HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_RESET);
		osDelay(5);
		HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_SET);
		osDelay(5);
    ADS1256_RST_LOW();
    osDelay(5);
    ADS1256_RST_HIGH();
    osDelay(5);
    ADS1256_SendCommand(ADS1256_CMD_RESET);
    osDelay(5);
}

uint8_t ADS1256_ReadID(void) { // 读取芯片 ID（高 4 位） ID高4位应该是0x03
    ADS1256_SendCommand(ADS1256_CMD_SYNC);
    ADS1256_SendCommand(ADS1256_CMD_WAKEUP);
		osDelay(1); 
	uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS);
    return (status >> 4) & 0x0F; // 屏蔽低4位

}

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);
}


float ADS1256_ConvertToVoltage(int32_t raw, float vref, int gain) {
    return ((float)raw / 8388608.0f) * (vref / gain); // V = (raw / 2的23次方)* (vref / gain) 单位V
}
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);
		ADS1256_SetClockSource(0);		// 0使用外部晶振 1内部晶振
    ADS1256_WriteRegister(ADS1256_REG_STATUS, 0x06); // 0x06 0000 0 110 自动校准开启（ACAL = 1）, 输入缓冲器关闭（BUFEN = 0）
		ADS1256_WriteRegister(ADS1256_REG_ADCON, 0x20);  // 0x20 时钟输出禁用（CLKOUT = 00）, 增益为1倍（输入是几mV，增益增大至8）
    ADS1256_SetDataRate(ADS1256_DR_1000SPS); // ADS1256_DR_1000SPS
    ADS1256_SetChannel(ADS1256_MUX_AIN1_AINCOM); // AIN1 - AINCOM
		ADS1256_SendCommand(ADS1256_CMD_SELFCAL);// 启动自动增益和偏移校准 必须最后执行该指令
}
