/*
 * @Author: mypx
 * @Email: mypx_coder@163.com
 * @Date: 2025-06-19 12:29:17
 * @LastEditors: mypx mypx_coder@163.com
 * @Description: 
 */
#include "pm_board.h"
#include "ad7793.h"
#include "adc.h"
#include "dma.h"
#include "et_log.h"
#include "gpio.h"
#include "i2c.h"
#include "rtdef.h"
#include "rthw.h"
#include "rtthread.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include <stdbool.h>
#include <string.h>

#define AT24C128_I2C_ADDR 0xA0

#if (DEBUG_MB_ENABLE == 1)
#define DBG_MB(...) ET_DBG("[MB] " __VA_ARGS__)
#else
#define DBG_MB(...)
#endif

volatile uint64_t timestamp_tim_overflow_count = 0;

#if (USING_SOFT_SPI == 1)
soft_spi_t soft_spi = {
    .sck_port  = GPIOB,
    .sck_pin   = GPIO_PIN_5,
    .mosi_port = GPIOB,
    .mosi_pin  = GPIO_PIN_6,
    .miso_port = GPIOB,
    .miso_pin  = GPIO_PIN_4,
    .cs_port   = GPIOB,
    .cs_pin    = GPIO_PIN_7,
    .mode      = SOFT_SPI_MODE0,
    .bit_order = SOFT_SPI_MSB_FIRST,
    .lock      = RT_NULL, // 使用 RT_NULL，初始化时会创建
    .delay_us  = 1,       // 每半个 SPI 时钟周期延时 1 微秒
};

void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len)
{
    soft_spi_transfer_buffer(&soft_spi, tx_buf, rx_buf, len);
}

void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len)
{
    soft_spi_write(&soft_spi, &cmd, 1, data, len);
}

void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len)
{
    soft_spi_read(&soft_spi, &cmd, 1, rx_buf, len);
}

void pm_ad7793_gpio_set(uint8_t pin, bool state)
{
    if (pin == soft_spi.cs_pin)
    {
        HAL_GPIO_WritePin(soft_spi.cs_port, soft_spi.cs_pin, state);
    }
}

bool pm_ad7793_gpio_get(uint8_t pin)
{
    if (pin == soft_spi.miso_pin)
    {
        return HAL_GPIO_ReadPin(soft_spi.miso_port, soft_spi.miso_pin) == GPIO_PIN_SET;
    }
    return false;
}
#else
#define AD7793_CS_LOW()  HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_RESET)
#define AD7793_CS_HIGH() HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_SET)
void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len)
{
    HAL_StatusTypeDef status;
    status = HAL_SPI_TransmitReceive(&AD7793_SPI, tx_buf, rx_buf, len, 1000);
    if (status != HAL_OK)
    {
        ET_ERR("SPI transfer error:%d!", status);
    }
}

void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len)
{
    uint8_t           tx_buffer[256];
    HAL_StatusTypeDef status;

    tx_buffer[0] = cmd;
    if (data && len > 0)
    {
        for (uint16_t i = 0; i < len; i++)
        {
            tx_buffer[i + 1] = data[i];
        }
    }
    status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, len + 1, 1000);
    if (status != HAL_OK)
    {
        ET_ERR("SPI write error:%d!", status);
    }
}

void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len)
{
    uint8_t           tx_buffer[1] = {cmd};
    HAL_StatusTypeDef status;
    status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, 1, 1000);
    if (status != HAL_OK)
    {
        ET_ERR("SPI write error:%d!", status);
    }
    status = HAL_SPI_Receive(&AD7793_SPI, rx_buf, len, 1000);
    if (status != HAL_OK)
    {
        ET_ERR("SPI read error:%d!", status);
    }
}

void pm_ad7793_gpio_set(uint8_t pin, bool state)
{
    if (pin == SPI3_CS_AD7793_Pin)
    {
        HAL_GPIO_WritePin(SPI3_CS_AD7793_GPIO_Port, SPI3_CS_AD7793_Pin, state);
    }
}

bool pm_ad7793_gpio_get(uint8_t pin)
{
    if (pin == SPI3_MISO_AD7793_Pin)
    {
        return HAL_GPIO_ReadPin(SPI3_MISO_AD7793_GPIO_Port, SPI3_MISO_AD7793_Pin) == GPIO_PIN_SET;
    }
    return false;
}
#endif

void pm_ad7793_delay_ms(uint16_t ms)
{
    rt_thread_mdelay(ms); // 使用 RT-Thread 的延时函数
}

ad7793_hw_if_t ad7793_hw_if = {
    .spi_transfer = pm_ad7793_spi_transfer,
    .spi_write    = pm_ad7793_spi_write,
    .spi_read     = pm_ad7793_spi_read,
    .gpio_set     = pm_ad7793_gpio_set,
    .gpio_get     = pm_ad7793_gpio_get,
    .delay_ms     = pm_ad7793_delay_ms,
};

#if (ENABLE_SV630P == 1)
struct rt_messagequeue servo_mq;
static char            mq_pool[SERVO_RX_QUEUE_SIZE];
#endif // USING_SOFT_SPI
void pm_system_led_toggle(void)
{
    HAL_GPIO_TogglePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin);
}

void pm_system_led_on(void)
{
    HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_SET);
}

void pm_system_led_off(void)
{
    HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_RESET);
}

void pm_error_led_on(void)
{
    HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_SET);
}

void pm_error_led_off(void)
{
    HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_RESET);
}

void pm_error_led_toggle(void)
{
    HAL_GPIO_TogglePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin);
}

int pm_i2c_write_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef res;

    // AT24C128 单页为 64 字节，写入时建议不要跨页，否则需要拆包
    if (len > 64)
        return HAL_ERROR;

    res = HAL_I2C_Mem_Write(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY);

    HAL_Delay(5); // EEPROM写入周期，典型为5ms

    return res;
}

int pm_i2c_read_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len)
{
    return HAL_I2C_Mem_Read(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY);
}


void pm_uart_print_send(const uint8_t *data, uint16_t len)
{
#ifdef USING_RTT_AS_CONSOLE
#warning "USING_RTT_AS_CONSOLE defined, use uart1 as hmi interface"

#else
    HAL_UART_Transmit(&huart1, data, len, 1000);
#endif
}

void pm_lcd_cmd_send(const uint8_t *data, uint16_t len)
{
    //#ifdef USING_RTT_AS_CONSOLE
    HAL_UART_Transmit(&huart1, data, strlen(data), 1000);
    // #else
    //     HAL_UART_Transmit(&huart2, data, strlen(data), 1000);
    // #endif
}

struct rt_messagequeue mb_hmi_mq;
static char            mq_pool[MB_HMI_RX_QUEUE_SIZE];

int pm_mb_hmi_init(void)
{
    MX_USART1_UART_Init();  // used tx
    MX_USART2_UART_Init();  // used rx

    rt_err_t result = rt_mq_init(&mb_hmi_mq, "mb_hmi_mq", mq_pool, 1, MB_HMI_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO);
    if (result != RT_EOK)
    {
        ET_ERR("mb_hmi mq init failed\n");
        return -1;
    }
    //__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);

    __HAL_UART_ENABLE_IT(&HMI_COM, UART_IT_RXNE);

    return 0;
}

int32_t pm_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg)
{
    UNUSED(arg);
    uint16_t  bytes_read = 0;
    uint8_t   byte;
    rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms);
    DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms);

    while (bytes_read < count)
    {
        rt_err_t result = rt_mq_recv(&mb_hmi_mq, &byte, sizeof(byte), timeout_ticks);
        if (result == RT_EOK)
        {
            DBG_MB("rx: %02X\n", byte);
            buf[bytes_read++] = byte;
        }
        else
        {
            if (bytes_read > 0)
            {
                DBG_MB("Modbus read finished %d\n", bytes_read);
                return bytes_read;
            }
            DBG_MB("HMI read timeout, no data received\n");
            return 0;
        }
    }
    DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count);

    return bytes_read;
}

int32_t pm_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg)
{
    UNUSED(arg);
    rt_thread_mdelay(2);
    //#ifdef USING_RTT_AS_CONSOLE
    if (HAL_UART_Transmit(&huart1, buf, count, byte_timeout_ms) == HAL_OK)
    // #else
    //     if (HAL_UART_Transmit(&HMI_COM, buf, count, byte_timeout_ms) == HAL_OK)
    // #endif
    {
        ET_DBG("HMI write:%d", count);
        return count;
    }
    else
    {
        return 0;
    }
}


#if (ENABLE_SV630P == 1)
int pm_servo_init(void)
{
    MX_USART3_UART_Init();

    rt_err_t result = rt_mq_init(&servo_mq, "servo_mq", mq_pool, 1, SERVO_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO);
    if (result != RT_EOK)
    {
        ET_ERR("servo mq init failed\n");
        return -1;
    }

    __HAL_UART_ENABLE_IT(&SERVO_COM, UART_IT_RXNE);
    return 0;
}

int32_t pm_servo_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg)
{
    UNUSED(arg);
    uint16_t  bytes_read = 0;
    uint8_t   byte;
    rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms);
    DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms);

    while (bytes_read < count)
    {
        rt_err_t result = rt_mq_recv(&servo_mq, &byte, sizeof(byte), timeout_ticks);
        if (result == RT_EOK)
        {
            DBG_MB("rx: %02X\n", byte);
            buf[bytes_read++] = byte;
        }
        else
        {
            if (bytes_read > 0)
            {
                DBG_MB("Modbus read finished %d\n", bytes_read);
                return bytes_read;
            }
            DBG_MB("Servo read timeout, no data received\n");
            return 0;
        }
    }
    DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count);

    return bytes_read;
}

int32_t pm_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg)
{
    UNUSED(arg);
    rt_thread_mdelay(2);
    if (HAL_UART_Transmit(&SERVO_COM, buf, count, byte_timeout_ms) == HAL_OK)
    {
        return count;
    }
    else
    {
        return 0;
    }
}
#endif // ENABLE_SV630P

#if (ENABLE_TEC == 1)
void pm_tec_init(void)
{
#if (USING_SOFT_SPI == 0)
    MX_SPI3_Init();
#endif
    MX_TIM1_Init();
}

void pm_tec_start(void)
{
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
}

void pm_tec_stop(void)
{
    HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
    HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1);
}

void pm_tec_set_duty(float pid_output)
{
    uint32_t period = htim1.Init.Period;
    // 限制PID输出范围
    const float MIN_POWER = 2.0f; // 最小有效功率(%)
    if (pid_output > 100.0f)
        pid_output = 100.0f;
    if (pid_output < -100.0f)
        pid_output = -100.0f;

    // 应用最小功率限制
    if (pid_output > 0 && pid_output < MIN_POWER)
        pid_output = MIN_POWER;
    if (pid_output < 0 && pid_output > -MIN_POWER)
        pid_output = -MIN_POWER;

    // 计算占空比
    uint32_t compare_value;
    if (pid_output >= 0)
    {
        // 制热：占空比50%~0%
        compare_value = period / 2 + (uint32_t)(period * pid_output / 200.0f);
    }
    else
    {
        // 制热：占空比50%~0%
        compare_value = period / 2 - (uint32_t)(period * fabs(pid_output) / 200.0f);
    }

    ET_DBG("PWM COMAPRE: %d", compare_value);
    // 设置PWM占空比
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, compare_value);
    //__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 2);
}

void pm_fan_start(void)
{
    HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_SET);
}

void pm_fan_stop(void)
{
    HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_RESET);
}

#endif // ENABLE_TEC

void pm_timestamp_tim_init(void)
{
    MX_TIM4_Init();
}

void pm_timestamp_start(void)
{
    __HAL_TIM_SET_COUNTER(&TIMESTAMP_TIM, 0);
    timestamp_tim_overflow_count = 0;
    HAL_TIM_Base_Start_IT(&TIMESTAMP_TIM);
}

void pm_timestamp_stop(void)
{
    HAL_TIM_Base_Stop_IT(&TIMESTAMP_TIM);
}

uint64_t pm_get_timestamp_us(void)
{
    uint16_t current_cnt = __HAL_TIM_GET_COUNTER(&TIMESTAMP_TIM);
    return (uint64_t)timestamp_tim_overflow_count * 65536 + current_cnt;
}

void pm_adc_init(void)
{
    MX_DMA_Init();
    MX_ADC1_Init();
}

uint32_t pm_adc_get_value(void)
{
    if (HAL_ADC_PollForConversion(&LIGHT_ADC, 10) != HAL_OK)
    {
        ET_ERR("ADC read should not wait!");
        pm_error_led_on();
        return 0;
    }
    return HAL_ADC_GetValue(&LIGHT_ADC);
}

void pm_sampling_tim_init(void)
{
    MX_TIM3_Init();
}

void pm_sampling_tim_start(void)
{
    HAL_TIM_Base_Start_IT(&SAMPLING_TIM);
}

void pm_sampling_tim_stop(void)
{
    HAL_TIM_Base_Stop_IT(&SAMPLING_TIM);
}

void pm_sampling_adc_start(uint16_t *buffer, uint32_t length)
{
    if (HAL_ADC_Start_DMA(&LIGHT_ADC, (uint32_t *)buffer, length) != HAL_OK)
    {
        ET_ERR("ADC start DMA error!");
        pm_error_led_on();
    }
    //HAL_ADC_Start(&LIGHT_ADC);
}

void pm_sampling_adc_stop(void)
{
    //HAL_ADC_Stop(&hadc1);
    HAL_ADC_Stop_DMA(&LIGHT_ADC);
}

float pm_sampling_tim_get_freq(void)
{
    uint32_t pclk1 = HAL_RCC_GetPCLK1Freq();
    uint32_t timer_clk;

    // 获取APB1预分频系数（来自RCC配置寄存器）
    uint32_t apb1_prescaler = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos;

    // 根据APB1预分频计算定时器时钟源
    if (apb1_prescaler == RCC_HCLK_DIV1)
    {
        // APB1预分频=1，定时器时钟=PCLK1
        timer_clk = pclk1;
    }
    else
    {
        // APB1预分频>1，定时器时钟=2×PCLK1
        timer_clk = pclk1 * 2;
    }

    // 计算定时器计数频率（经过PSC分频后）
    uint32_t counter_freq = timer_clk / (SAMPLING_TIM.Init.Prescaler + 1);

    // 计算最终输出频率（周期触发频率 = 计数频率 / (Period + 1)）
    // 注意：如果是向上计数模式，完整周期是从0到Period，共Period+1个计数
    return (float)counter_freq / (SAMPLING_TIM.Init.Period + 1);
}

int pm_board_init(void)
{
    MX_GPIO_Init();
    // MX_USART1_UART_Init();
#if (USING_SOFT_SPI == 1)
    soft_spi_init(&soft_spi);
    soft_spi_set_mode(&soft_spi, SOFT_SPI_MODE3);          // 设置 SPI 模式
    soft_spi_set_bit_order(&soft_spi, SOFT_SPI_MSB_FIRST); // 设置位序
    soft_spi_set_delay(&soft_spi, 1);                      // 设置延时为 1 微秒
    soft_spi_select(&soft_spi);                            // 选择 SPI 设备
#endif

    return 0;
}
