/*
 * 自然写智能点阵笔嵌入式固件软件 V1.0
 * camera_driver.c - CMOS摄像头传感器驱动
 *
 * 功能说明：
 * 1. CMOS图像传感器SPI通信驱动
 * 2. 传感器寄存器配置（曝光、增益、帧率）
 * 3. 图像采集触发与数据读取
 * 4. 传感器电源管理（开/关/低功耗）
 * 5. 自检与故障检测
 */

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "hal_spi.h"
#include "hal_gpio.h"

/* ========== 传感器寄存器地址 ========== */

/* 芯片ID寄存器（只读） */
#define REG_CHIP_ID             0x00

/* 系统控制寄存器 */
#define REG_SYS_CTRL            0x01
#define SYS_CTRL_RESET          0x80    /* 软复位 */
#define SYS_CTRL_SLEEP          0x40    /* 睡眠模式 */
#define SYS_CTRL_ENABLE         0x01    /* 使能采集 */

/* 曝光时间寄存器（高/低字节） */
#define REG_EXPOSURE_H          0x02
#define REG_EXPOSURE_L          0x03

/* 模拟增益寄存器 */
#define REG_GAIN                0x04

/* 帧率控制寄存器 */
#define REG_FRAME_RATE          0x05

/* 像素数据起始寄存器（读取时自动递增） */
#define REG_PIXEL_DATA          0x10

/* 帧就绪状态位 */
#define REG_STATUS              0x0F
#define STATUS_FRAME_READY      0x01

/* 预期芯片ID值 */
#define EXPECTED_CHIP_ID        0xA5

/* ========== 传感器模式枚举 ========== */

#define CAMERA_MODE_SINGLE      0       /* 单帧模式 */
#define CAMERA_MODE_CONTINUOUS  1       /* 连续帧模式 */

/* ========== GPIO引脚定义 ========== */

#define GPIO_CAMERA_POWER       12      /* 传感器电源控制引脚 */
#define GPIO_CAMERA_CS          15      /* SPI片选引脚 */
#define GPIO_CAMERA_LED         16      /* 红外LED照明引脚 */

/* ========== SPI通信 ========== */

/* SPI端口号 */
#define CAMERA_SPI_PORT         SPI_PORT_1

/* 读寄存器标志位 */
#define SPI_READ_FLAG           0x80

/* ========== 静态变量 ========== */

/* 传感器是否已初始化 */
static bool s_camera_initialized = false;

/* 传感器是否已上电 */
static bool s_camera_powered = false;

/* 当前工作模式 */
static uint8_t s_camera_mode = CAMERA_MODE_SINGLE;

/* ========== SPI底层读写 ========== */

/**
 * SPI写单个寄存器
 * @param reg_addr  寄存器地址（7位）
 * @param value     写入值
 */
static void camera_write_reg(uint8_t reg_addr, uint8_t value) {
    uint8_t tx[2];
    tx[0] = reg_addr & 0x7F;       /* 最高位0=写操作 */
    tx[1] = value;

    hal_gpio_write(GPIO_CAMERA_CS, 0);      /* 拉低CS */
    hal_spi_transfer(CAMERA_SPI_PORT, tx, NULL, 2);
    hal_gpio_write(GPIO_CAMERA_CS, 1);      /* 拉高CS */
}

/**
 * SPI读单个寄存器
 * @param reg_addr  寄存器地址
 * @return 读取的值
 */
static uint8_t camera_read_reg(uint8_t reg_addr) {
    uint8_t tx[2], rx[2];
    tx[0] = reg_addr | SPI_READ_FLAG;      /* 最高位1=读操作 */
    tx[1] = 0x00;                           /* 空字节用于接收数据 */

    hal_gpio_write(GPIO_CAMERA_CS, 0);
    hal_spi_transfer(CAMERA_SPI_PORT, tx, rx, 2);
    hal_gpio_write(GPIO_CAMERA_CS, 1);

    return rx[1];
}

/**
 * SPI批量读取像素数据
 * 使用DMA方式高速读取整帧图像数据
 *
 * @param buffer   接收缓冲区
 * @param length   读取字节数
 */
static void camera_read_pixels(uint8_t *buffer, uint16_t length) {
    uint8_t cmd = REG_PIXEL_DATA | SPI_READ_FLAG;

    hal_gpio_write(GPIO_CAMERA_CS, 0);

    /* 先发送寄存器地址 */
    hal_spi_transfer(CAMERA_SPI_PORT, &cmd, NULL, 1);

    /* 然后连续读取像素数据 */
    hal_spi_receive(CAMERA_SPI_PORT, buffer, length);

    hal_gpio_write(GPIO_CAMERA_CS, 1);
}

/* ========== 传感器初始化 ========== */

/**
 * 初始化CMOS图像传感器
 * 配置GPIO、验证芯片ID、设置初始参数
 *
 * @return 0成功, -1芯片ID错误, -2通信失败
 */
int camera_driver_init(void) {
    /* 配置控制GPIO为输出 */
    hal_gpio_config_output(GPIO_CAMERA_POWER);
    hal_gpio_config_output(GPIO_CAMERA_CS);
    hal_gpio_config_output(GPIO_CAMERA_LED);

    /* CS默认高电平（不选中） */
    hal_gpio_write(GPIO_CAMERA_CS, 1);

    /* 上电 */
    hal_gpio_write(GPIO_CAMERA_POWER, 1);
    s_camera_powered = true;

    /* 等待传感器启动（典型10ms） */
    for (volatile int i = 0; i < 100000; i++);

    /* 软复位 */
    camera_write_reg(REG_SYS_CTRL, SYS_CTRL_RESET);
    for (volatile int i = 0; i < 50000; i++);

    /* 验证芯片ID */
    uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
    if (chip_id != EXPECTED_CHIP_ID) {
        s_camera_initialized = false;
        return -1;
    }

    /* 设置默认参数 */
    camera_write_reg(REG_EXPOSURE_H, 0x00);
    camera_write_reg(REG_EXPOSURE_L, 0x80);     /* 曝光值128 */
    camera_write_reg(REG_GAIN, 0x40);            /* 增益64 */
    camera_write_reg(REG_FRAME_RATE, 100);       /* 100Hz帧率 */

    /* 使能传感器 */
    camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);

    s_camera_initialized = true;
    return 0;
}

/* ========== 参数配置 ========== */

/**
 * 设置曝光时间
 * @param exposure  曝光值（0-255，映射到传感器实际曝光时间）
 */
void camera_set_exposure(uint8_t exposure) {
    if (!s_camera_initialized) return;
    camera_write_reg(REG_EXPOSURE_H, 0x00);
    camera_write_reg(REG_EXPOSURE_L, exposure);
}

/**
 * 设置模拟增益
 * @param gain  增益值（0-255）
 */
void camera_set_gain(uint8_t gain) {
    if (!s_camera_initialized) return;
    camera_write_reg(REG_GAIN, gain);
}

/**
 * 设置工作模式
 * @param mode  CAMERA_MODE_SINGLE 或 CAMERA_MODE_CONTINUOUS
 */
void camera_set_mode(uint8_t mode) {
    s_camera_mode = mode;
}

/* ========== 图像采集 ========== */

/**
 * 触发单帧采集
 * 在连续模式下，传感器会自动拍摄
 * 在单帧模式下，需要每次手动触发
 */
void camera_trigger_capture(void) {
    if (!s_camera_initialized || !s_camera_powered) return;

    if (s_camera_mode == CAMERA_MODE_SINGLE) {
        /* 单帧模式：写触发位 */
        uint8_t ctrl = camera_read_reg(REG_SYS_CTRL);
        camera_write_reg(REG_SYS_CTRL, ctrl | 0x02);
    }

    /* 开启红外LED照明（点阵图案需要红外光照射才能看到） */
    hal_gpio_write(GPIO_CAMERA_LED, 1);
}

/**
 * 等待帧就绪
 * @param timeout_ms  超时毫秒数
 * @return true帧已就绪, false超时
 */
bool camera_wait_frame_ready(uint16_t timeout_ms) {
    uint16_t elapsed = 0;
    while (elapsed < timeout_ms) {
        uint8_t status = camera_read_reg(REG_STATUS);
        if (status & STATUS_FRAME_READY) {
            return true;
        }
        /* 简单延时 */
        for (volatile int i = 0; i < 1000; i++);
        elapsed++;
    }
    return false;
}

/**
 * 获取传感器数据寄存器地址（用于DMA配置）
 */
uint32_t camera_get_data_register(void) {
    /* 返回SPI数据寄存器的内存映射地址 */
    return hal_spi_get_data_addr(CAMERA_SPI_PORT);
}

/* ========== 电源管理 ========== */

/**
 * 传感器上电
 */
void camera_power_on(void) {
    if (s_camera_powered) return;

    hal_gpio_write(GPIO_CAMERA_POWER, 1);
    s_camera_powered = true;

    /* 等待传感器稳定 */
    for (volatile int i = 0; i < 100000; i++);

    /* 重新使能 */
    camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);
}

/**
 * 传感器断电（最低功耗）
 */
void camera_power_off(void) {
    if (!s_camera_powered) return;

    /* 关闭红外LED */
    hal_gpio_write(GPIO_CAMERA_LED, 0);

    /* 传感器进入睡眠 */
    camera_write_reg(REG_SYS_CTRL, SYS_CTRL_SLEEP);

    /* 切断电源 */
    hal_gpio_write(GPIO_CAMERA_POWER, 0);
    s_camera_powered = false;
}

/**
 * 传感器自检
 * 检查SPI通信是否正常、芯片ID是否正确
 *
 * @return 0正常, -1通信故障, -2芯片ID异常
 */
int camera_self_test(void) {
    if (!s_camera_powered) {
        return -1;
    }

    uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
    if (chip_id != EXPECTED_CHIP_ID) {
        return -2;
    }

    /* 写读测试：写入一个可写寄存器并读回验证 */
    uint8_t test_val = 0x55;
    camera_write_reg(REG_GAIN, test_val);
    uint8_t read_back = camera_read_reg(REG_GAIN);

    if (read_back != test_val) {
        return -1;
    }

    /* 恢复原始增益值 */
    camera_write_reg(REG_GAIN, 0x40);

    return 0;
}
