/**
 * \file        b_drv_qmi8658a.c
 * \version     v0.0.1
 * \date        2023-11-09
 * \author      miniminiminini (405553848@qq.com)
 * \brief
 *
 * Copyright (c) 2023 by miniminiminini. All Rights Reserved.
 */

/* Includes ----------------------------------------------*/
#include "drivers/inc/b_drv_qmi8658a.h"

#include <string.h>

#include "utils/inc/b_util_log.h"

/**
 * \defgroup QMI8658A_Private_TypesDefinitions
 * \{
 */

/**
 * }
 */

/**
 * \defgroup QMI8658A_Private_Defines
 * \{
 */
#define DRIVER_NAME QMI8658A
#define QMI8658A_ID 0X05
///< Configuration Registers>
#define address 0X6B   // device address
#define WHO_AM_I 0X00  // Device identifier
#define CTRL1 0x02     // Serial Interface and Sensor Enable
#define CTRL2 0x03     // Accelerometer Settings
#define CTRL3 0x04     // Gyroscope Settings
#define CTRL4 0X05     // Magnetometer Settings
#define CTRL5 0X06     // Sensor Data Processing Settings
#define CTRL7 0x08     // Enable Sensors and Configure Data Reads
#define CTRL8 0X09     // Reserved – Special Settings

///< Sensor Data Output Registers>
#define AccX_L 0x35
#define AccX_H 0x36
#define AccY_L 0x37
#define AccY_H 0x38
#define AccZ_L 0x39
#define AccZ_H 0x3A
#define TEMP_L 0x33

#define GyrX_L 0x3B
#define GyrX_H 0x3C
#define GyrY_L 0x3D
#define GyrY_H 0x3E
#define GyrZ_L 0x3F
#define GyrZ_H 0x40

#define RESET_REG 0x60

/**
 * }
 */

/**
 * \defgroup QMI8658A_Private_Macros
 * \{
 */
#define U8ToFloat(msb, lsb) ((float)((short)((((msb)&0xffff) << 8) | (((lsb)&0xffff)))))

/**
 * }
 */

/**
 * \defgroup QMI8658A_Private_Variables
 * \{
 */
bDRIVER_HALIF_TABLE(bQMI8658A_HalIf_t, DRIVER_NAME);

/**
 * }
 */

/**
 * \defgroup QMI8658A_Private_FunctionPrototypes
 * \{
 */

/**
 * \brief        判定iic是否失败
 * \param pdrv
 * \param reg
 * \param data
 * \param len
 * \return int
 */
static int _bQMI8658AReadCheckRegs(bDriverInterface_t *pdrv, uint8_t reg, uint8_t *data,
                                   uint16_t len)
{
    bDRIVER_GET_HALIF(_if, bQMI8658A_HalIf_t, pdrv);

    if (bHalI2CMemRead(_if, reg, 1, data, len) < 0)
    {
        return -1;
    }

    return len;
}

static int _bQMI8658AWriteCheckRegs(bDriverInterface_t *pdrv, uint8_t reg, uint8_t *data,
                                    uint16_t len)
{
    uint8_t read_buf[len];
    bDRIVER_GET_HALIF(_if, bQMI8658A_HalIf_t, pdrv);
    memset(read_buf, 0, sizeof(read_buf));

    if (bHalI2CMemWrite(_if, reg, 1, data, len) < 0)
    {
        return -1;
    }

    if (bHalI2CMemRead(_if, reg, 1, read_buf, len) < 0)
    {
        return -1;
    }

    for (uint16_t i = 0; i < len; i++)
    {
        if (read_buf[i] != data[i])
        {
            return -2;
        }
    }

    return len;
}

static void _bQMI8658ASOFTRESET(bDriverInterface_t *pdrv)
{
    uint8_t reset_reg_val = 0x0B;
    _bQMI8658AWriteCheckRegs(pdrv, RESET_REG, &reset_reg_val, 1);
    bHalDelayMs(50);
}

static int _bQMI8658AGetID(bDriverInterface_t *pdrv, uint8_t *id)
{
    if (_bQMI8658AReadCheckRegs(pdrv, WHO_AM_I, id, 1) < 0)
    {
        return -1;
    }
    // b_log("QMI8658A id:0x%x\n", id);
    return 0;
}

static int _bQMI8658ADefaultCfg(bDriverInterface_t *pdrv)
{
    uint8_t ctrl1_val =
        0x40;  // Serial Interface and Sensor Enable<串行接口(SPI或I 2 C)地址自动递增>
    uint8_t ctrl7_val =
        0x03;  // Enable Sensors and Configure Data Reads<Enable Gyroscope Accelerometer>
    uint8_t ctrl2_val = 0x34;  // Accelerometer Settings<±16g  500Hz>
    uint8_t ctrl3_val = 0x64;  // Gyroscope Settings< ±2048dps 500Hz>
    uint8_t ctrl5_val =
        0x11;  // Sensor Data Processing Settings<Enable Gyroscope Accelerometer 低通滤波>

    if (_bQMI8658AWriteCheckRegs(pdrv, CTRL1, &ctrl1_val, 1) < 0)
    {
        return -1;
    }
    if (_bQMI8658AWriteCheckRegs(pdrv, CTRL7, &ctrl7_val, 1) < 0)
    {
        return -1;
    }
    if (_bQMI8658AWriteCheckRegs(pdrv, CTRL2, &ctrl2_val, 1) < 0)
    {
        return -1;
    }
    if (_bQMI8658AWriteCheckRegs(pdrv, CTRL3, &ctrl3_val, 1) < 0)
    {
        return -1;
    }
    if (_bQMI8658AWriteCheckRegs(pdrv, CTRL5, &ctrl5_val, 1) < 0)
    {
        return -1;
    }

    return 0;
}

static int _bQMI8658ARead(bDriverInterface_t *pdrv, uint32_t off, uint8_t *pbuf, uint32_t len)
{
    uint8_t            axis6_data[12];
    bQMI8658A_6Axis_t *ptmp = (bQMI8658A_6Axis_t *)pbuf;

    if (len < sizeof(bQMI8658A_6Axis_t))
    {
        return -1;
    }

    if (_bQMI8658AReadCheckRegs(pdrv, AccX_L, &axis6_data[0], 6) < 0)
    {
        return -1;
    }

    if (_bQMI8658AReadCheckRegs(pdrv, GyrX_L, &axis6_data[6], 6) < 0)
    {
        return -1;
    }

    ptmp->acc_arr[0]  = U8ToFloat(axis6_data[1], axis6_data[0]) * 16 * 9.8f / 65536;
    ptmp->acc_arr[1]  = U8ToFloat(axis6_data[3], axis6_data[2]) * 16 * 9.8f / 65536;
    ptmp->acc_arr[2]  = U8ToFloat(axis6_data[5], axis6_data[4]) * 16 * 9.8f / 65536;
    ptmp->gyro_arr[0] = U8ToFloat(axis6_data[7], axis6_data[6]) * 2048 / 65536 / 57.3f;
    ptmp->gyro_arr[1] = U8ToFloat(axis6_data[9], axis6_data[8]) * 2048 / 65536 / 57.3f;
    ptmp->gyro_arr[2] = U8ToFloat(axis6_data[11], axis6_data[10]) * 2048 / 65536 / 57.3f;
    // b_log("acc_dat:0x%02x 0x%02x 0x%02x\n", ptmp->acc_arr[0], ptmp->acc_arr[1], ptmp->acc_arr[2]);
    // b_log("gyro_dat:0x%02x 0x%02x 0x%02x\n", ptmp->gyro_arr[0], ptmp->gyro_arr[1],
    //       ptmp->gyro_arr[2]);

    return 0;
}

static int _bQMI8658ACtl(struct bDriverIf *pdrv, uint8_t cmd, void *param)
{
    int retval = 0;
    switch (cmd)
    {
        case bCMD_QMI8658A_SET_STATUS_ERR:
        {
            pdrv->status = -1;
        }
        break;

        default:
            retval = -1;
            break;
    }
    return retval;
}

/**
 * }
 */

/**
 * \defgroup QMI8658A_Private_Functions
 * \{
 */

/**
 * }
 */

/**
 * \defgroup QMI8658A_Exported_Functions
 * \{
 */
int bQMI8658A_Init(bDriverInterface_t *pdrv)
{
    uint8_t id = 0;
    bDRIVER_STRUCT_INIT(pdrv, DRIVER_NAME, bQMI8658A_Init);
    pdrv->read = _bQMI8658ARead;
    pdrv->ctl  = _bQMI8658ACtl;

    if (_bQMI8658AGetID(pdrv, &id) < 0)
    {
        return -1;
    }

    if (id != QMI8658A_ID)
    {
        return -1;
    }

    _bQMI8658ASOFTRESET(pdrv);

    if (_bQMI8658ADefaultCfg(pdrv) < 0)
    {
        return -1;
    }

    return 0;
}

#ifdef BSECTION_NEED_PRAGMA
#pragma section driver_init
#endif
bDRIVER_REG_INIT(B_DRIVER_QMI8658A, bQMI8658A_Init);
#ifdef BSECTION_NEED_PRAGMA
#pragma section 
#endif
/**
 * }
 */

/**
 * }
 */

/**
 * }
 */

/**
 * }
 */

/***** Copyright (c) 2023 miniminiminini *****END OF FILE*****/