/******************************************************************************
 * file    Core/Src/position.c 
 * author  Changjiale
 * version 1.0.0
 * date    18-Sep-2023
 * brief   This file provides all the position related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2023 LandPower</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of WTOE nor the names of its contributors may be used to 
 *      endorse or promote products derived from this software without specific
 *      prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "string.h"

#include "usart.h"
#include "dev_config.h"
#include "ADC_collect.h"
#include "position.h"
#include "flash_if.h"

/* Private define ------------------------------------------------------------*/
#define POSITION_THRESHOLD_MIN 5        //5mv
#define POSITION_THRESHOLD_MAX 995      //995mv
#define POSITION_RX_TIMEOUT 500         //500ms
#define POSITION_TX_DELAY 100        //两条命令之间需要间隔50ms以上
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
position_buf_list_t position_buf_list_rx;
position_ctrl_t position_ctrl;
static position_data_t position_data;
static _position_ctrl_t _position_ctrl;
UART_HandleTypeDef *position_usart = &huart1;      //定位模块使用串口

/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/*发送命令消息函数*/
static HAL_StatusTypeDef _position_transmit(uint8_t *data, uint16_t len)
{
    DBG(DBG_M_POSITION, "Send(%d:%d):\r\n", len, HAL_GetTick());
    if (dbg_stat_get(DBG_M_POSITION))
    {
        buf_print(data, POSITION_MIN(len, 32));
        vty_print("\r\n");
    }

    /* 开启串口空闲接收 */
    HAL_UARTEx_ReceiveToIdle_DMA(position_usart, position_ctrl.dma_rx_buf, POSITION_CMD_BUF_LEN);
    osDelay(POSITION_TX_DELAY);
    /* 打开485Tx引脚 */
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_SET);
    return HAL_UART_Transmit_DMA(position_usart, data, len);
}

/* 检查校验值 */
static uint8_t _position_pkt_chk(void)
{
    uint16_t chk_len = _position_ctrl.cmd_buf_index - 2;     //数据长度
    uint8_t *buf = _position_ctrl.cmd_receive_buf + 1;
    uint8_t chk = 0;
    uint16_t i = 0;

    /* 设备进入复位状态后不再处理报文. */
    if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_RESET))
    {
        vty_print("@0\r\n");
        /* 这里挂住线程是因为重启时如果有收包, 会导致收包出错, 从而让设备进入休眠状态. */
        osDelay(portMAX_DELAY);
        return FALSE;
    }

    if (buf[3] != _position_ctrl.pkt_id)
    {
        vty_print("POSITION ID: %d %d\r\n", buf[3], _position_ctrl.pkt_id);
        return FALSE;
    }

    for (i = 0; i < chk_len; i++)
    {
        chk += buf[i];
    }

    if (chk == buf[chk_len])
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/* 收包函数 */
static HAL_StatusTypeDef _position_pkt_wait(void)
{
    uint8_t *buf = NULL;
    uint8_t *pkt_head = &_position_ctrl.cmd_receive_buf[0];
    uint16_t len = 0;
    uint16_t *pkt_len = (uint16_t*)(&_position_ctrl.cmd_receive_buf[1]);
    uint32_t notify_value = 0;
    uint32_t time = HAL_GetTick();
    position_buf_list_t *buf_l = &position_buf_list_rx;

    while(1)
    {
        /* 收包超时. */
        if ((HAL_GetTick() - time) > POSITION_RX_TIMEOUT)
        {
            return HAL_TIMEOUT;
        }

        /* 等待 DMA 空闲收包中断. */
        notify_value = ulTaskNotifyTake(pdTRUE, POSITION_RX_TIMEOUT);
        if (0 == notify_value)
        {
            continue;
        }

        /* 遍历所有有效的 buf. */
        while(buf_l->current != buf_l->valid)
        {
            buf = buf_l->buf[buf_l->current];
            len = buf_l->buf_cnt[buf_l->current];

            /* 更新 buf index. */
            buf_l->current++;
            if (POSITION_BUF_LIST_LEN == buf_l->current)
            {
                buf_l->current = 0;
            }

            /* 收包总长大于报文长度 */
            if (_position_ctrl.cmd_buf_index >= 3 && (_position_ctrl.cmd_buf_index + len) > (*pkt_len + 3))
            {
                _position_ctrl.cmd_buf_index = 0;
                _position_ctrl.pkt_state = POSITION_PKT_NONE;

                /* 如果收包状态为完成, 舍弃之前的包后接收最新的包 */
                if (POSITION_PKT_COMPLETE != _position_ctrl.pkt_state)
                {
                    continue;
                }
            }

            /* 如果收包大于协议报文长度, 认为报文错误. */
            if (_position_ctrl.cmd_buf_index + len > POSITION_CMD_BUF_LEN)
            {
                _position_ctrl.cmd_buf_index = 0;
                _position_ctrl.pkt_state = POSITION_PKT_NONE;
                continue;
            }

            memcpy(&_position_ctrl.cmd_receive_buf[_position_ctrl.cmd_buf_index], buf, len);
            _position_ctrl.cmd_buf_index += len;

            if (_position_ctrl.cmd_buf_index < 3)
            {
                continue;
            }

            if (POSITION_PKT_NONE == _position_ctrl.pkt_state)
            {
                if (*pkt_head != 0xa5 || (*pkt_len + 3 > POSITION_CMD_BUF_LEN))
                {
                    _position_ctrl.cmd_buf_index = 0;
                    continue;
                }

                if (_position_ctrl.cmd_buf_index < *pkt_len + 3)
                {
                    _position_ctrl.pkt_state = POSITION_PKT_HALF;
                    continue;
                }
            }
            else if (POSITION_PKT_HALF == _position_ctrl.pkt_state)
            {
                if (_position_ctrl.cmd_buf_index < *pkt_len + 3)
                {
                    continue;
                }
            }

            if (_position_pkt_chk())
            {
                _position_ctrl.pkt_state = POSITION_PKT_COMPLETE;
            }
            else
            {
                _position_ctrl.cmd_buf_index = 0;
                _position_ctrl.pkt_state = POSITION_PKT_NONE;
            }
        }

        if (POSITION_PKT_COMPLETE == _position_ctrl.pkt_state)
        {
            DBG(DBG_M_POSITION, "Recv(%d):\r\n", _position_ctrl.cmd_buf_index);
            if (dbg_stat_get(DBG_M_POSITION))
            {
                buf_print(_position_ctrl.cmd_receive_buf, POSITION_MIN(_position_ctrl.cmd_buf_index, 32));
                vty_print("\r\n");
            }
            _position_ctrl.cmd_buf_index = 0;
            _position_ctrl.pkt_state = POSITION_PKT_NONE;
            return HAL_OK;
        }
    }
}

/* 填充报文 */
static void _position_packed(uint8_t cmd, uint16_t len)
{
    uint8_t *buf = _position_ctrl.cmd_send_buf;
    uint16_t pkt_len = len - 3;
    uint8_t *chk = buf + pkt_len + 2;
    uint8_t i = 0;

    buf[0] = 0xa5;                      // 报文头.
    *(uint16_t*)(&buf[1]) = pkt_len;    // 报文长度.
    buf[3] = 0;                         // 设备 id, 单板为 0.
    buf[4] = _position_ctrl.pkt_id;     // 报文序列号.
    buf[5] = cmd;                       // 报文命令字.

    /* 填充校验值 */
    *chk = 0;
    for (i = 1; i <= pkt_len + 1; i++)
    {
        *chk += buf[i];
    }
}

/* 命令0的收包处理函数 */
static HAL_StatusTypeDef _position_pkt_state(void)
{
    uint8_t *buf = _position_ctrl.cmd_receive_buf;
    uint8_t *data = buf + POSITION_HEAD_LEN;

    if (buf[1] != 0x29
     || buf[2] != 0
     || buf[5] != POSITION_STATE)
    {
        return HAL_ERROR;
    }
    
    /* 新行波数据 */
    if (IS_MONITOR_BIT_SET(*data, 2) || IS_MONITOR_BIT_SET(*data, 1))
    {
        position_ctrl.new = TRUE;
    }

    data++;
    position_data.vol = *(uint16_t*)data;	//设备电压
    data += 2;
    position_data.temperature = *(uint16_t*)data;	//设备温度
    
    _position_ctrl.pkt_id++;
    return HAL_OK;
}

/* 命令1的收包处理函数 */
static HAL_StatusTypeDef _position_pkt_cfg(void)
{
    uint8_t *buf = _position_ctrl.cmd_receive_buf;

    if (buf[1] != 0x05
     || buf[2] != 0 
     || buf[5] != POSITION_CFG 
     || buf[6] != 0)
    {
        return HAL_ERROR;
    }
    
    _position_ctrl.pkt_id++;
    return HAL_OK;
}

/* 命令2的收包处理函数 */
static HAL_StatusTypeDef _position_pkt_query(void)
{
    uint8_t *buf = _position_ctrl.cmd_receive_buf;
    _position_data_t *data = (_position_data_t *)(buf + POSITION_HEAD_LEN);

    if (buf[1] != 0x34
     || buf[2] != 0
     || buf[5] != POSITION_QUERY)
    {
        return HAL_ERROR;
    }

    /* 新行波数据 */
	if (position_data.wave_info.file_s != data->file_s || position_data.wave_info.file_ns != data->file_ns)
    {
        for (uint8_t i = 0; i < POSITION_SUM; i++)
        {
            if (((data->wave_info[i].s == data->file_s) && (data->wave_info[i].ns >= data->file_ns))
                  || (data->wave_info[i].s > data->file_s))
            {
                position_data.wave_info.v[i] = data->wave_info[i].v;
                position_data.wave_info.s[i] = data->wave_info[i].s;
                position_data.wave_info.ns[i] = data->wave_info[i].ns;
            }
            else
            {
                position_data.wave_info.v[i] = 0.0;
                position_data.wave_info.s[i] = 0;
                position_data.wave_info.ns[i] = 0;
            }
        }
        position_data.wave_info.file_s = data->file_s;
        position_data.wave_info.file_ns = data->file_ns;
        position_data.wave_info.file_feq = data->file_feq;
		/* 写 FLASH */
        position_write(&position_data);

        /* 写日志 */
		flash_log_write(FLASH_LOG_TYPE_INFO, "\r%f %d %d\r %f %d %d\r %f %d %d\r %d %d %d\r\n",
            position_data.wave_info.v[0], position_data.wave_info.s[0], position_data.wave_info.ns[0],
            position_data.wave_info.v[1], position_data.wave_info.s[1], position_data.wave_info.ns[1],
            position_data.wave_info.v[2], position_data.wave_info.s[2], position_data.wave_info.ns[2],
            position_data.wave_info.file_s, position_data.wave_info.file_ns, position_data.wave_info.file_feq);
    }

    _position_ctrl.pkt_id++;
    return HAL_OK;
}

/* 命令3的收包处理函数 */
static int16_t _position_pkt_wave(uint8_t *data)
{
    uint8_t *buf = _position_ctrl.cmd_receive_buf;
    uint8_t *wave_data = buf + POSITION_HEAD_LEN;
    uint16_t pkt_len = 0;

    if (buf[5] != POSITION_WAVE)
    {
        return -1;
    }

    pkt_len = *(uint16_t*)(&_position_ctrl.cmd_receive_buf[1]);
    _position_ctrl.pkt_id++;
    memcpy(data, wave_data, pkt_len - 4);
    return pkt_len - 4;
}

/* 发送命令0函数 */
static HAL_StatusTypeDef _position_state(void)
{
    uint8_t *buf = _position_ctrl.cmd_send_buf;
    _position_packed(POSITION_STATE, POSITION_STATE_LEN);

    if (_position_transmit(buf, POSITION_STATE_LEN) != HAL_OK)
    {
        return HAL_ERROR;
    }

    if (_position_pkt_wait() == HAL_OK)
    {
        if (_position_pkt_state() != HAL_OK)
        {
            return HAL_ERROR;
        }
    }
    else
    {
        return HAL_TIMEOUT;
    }

    return HAL_OK;
}

/* 发送命令1函数 */
static HAL_StatusTypeDef _position_cfg(void)
{
    uint8_t *buf = _position_ctrl.cmd_send_buf;

    uint8_t *data = buf + POSITION_HEAD_LEN;
    float threshold = 0;
    if (dev_config.wave_threshold < POSITION_THRESHOLD_MIN)
    {
        threshold = POSITION_THRESHOLD_MIN;
    }
    else if (dev_config.wave_threshold > POSITION_THRESHOLD_MAX)
    {
        threshold = POSITION_THRESHOLD_MAX;
    }
    else
    {
        threshold = (float)dev_config.wave_threshold;
    }
    memcpy(data, &threshold, sizeof(float));

    data += 4;
    *(uint32_t*)data = 0;

    _position_packed(POSITION_CFG, POSITION_CFG_LEN);

    if (_position_transmit(buf, POSITION_CFG_LEN) != HAL_OK)
    {
        return HAL_ERROR;
    }

    if (_position_pkt_wait() == HAL_OK)
    {
        if (_position_pkt_cfg() != HAL_OK)
        {
            return HAL_ERROR;
        }
    }
    else
    {
        return HAL_TIMEOUT;
    }

    return HAL_OK;
}

/* 发送命令2函数 */
static HAL_StatusTypeDef _position_query(void)
{
    uint8_t *buf = _position_ctrl.cmd_send_buf;
    _position_packed(POSITION_QUERY, POSITION_QUERY_LEN);

    if (_position_transmit(buf, POSITION_QUERY_LEN) != HAL_OK)
    {
        return HAL_ERROR;
    }

    if (_position_pkt_wait() == HAL_OK)
    {
        if (_position_pkt_query() != HAL_OK)
        {
            return HAL_ERROR;
        }
    }
    else
    {
        return HAL_TIMEOUT;
    }

    return HAL_OK;
}

static void _position_err(void)
{
    if (position_ctrl.position_wave_up)
    {
        position_ctrl.position_wave_up = FALSE;
    }
    else if (position_ctrl.cfg)
    {
        position_ctrl.cfg = FALSE;
    }
    else if (position_ctrl.new)
    {
        position_ctrl.new = FALSE;
    }
    /* 串口通讯错误 */
    else
    {
        position_ctrl.offline = TRUE;
    }
    position_ctrl.send_cnt = 0;
    position_ctrl.err_cnt++;
}

/* Interface functions -------------------------------------------------------*/
/* 故障定位轮询函数 */
HAL_StatusTypeDef position_start(void)
{
    HAL_StatusTypeDef rv = HAL_OK;

    while(1)
    {
        if (position_ctrl.send_cnt > POSITION_ERR_MAX)
        {
            _position_err();
            break;
        }

        if (position_ctrl.cfg)
        {
            rv = _position_cfg();
            if (HAL_OK == rv)
            {
                position_ctrl.cfg = FALSE;
            }
            else
            {
                position_ctrl.send_cnt++;
                continue;
            }
        }

        rv = _position_state();
        if (HAL_OK != rv)
        {
            position_ctrl.send_cnt++;
            continue;
        }

        if (position_ctrl.new)
        {
            rv = _position_query();
            if (HAL_OK == rv)
            {
                position_ctrl.new = FALSE;
            }
            else
            {
                position_ctrl.send_cnt++;
                continue;
            }
        }
        else
        {
            break;
        }
    }

    position_ctrl.complete = TRUE;

    if (HAL_OK == rv)
    {
        position_ctrl.offline = FALSE;
        position_ctrl.send_cnt = 0;
        position_ctrl.err_cnt = 0;
        return HAL_OK;
    }
    else
    {
        return HAL_ERROR;
    }
}

/* 发送命令3函数 */
HAL_StatusTypeDef position_wave(uint8_t *wl_data, uint16_t index, uint16_t *data_len, uint32_t file_s, uint32_t file_ns)
{
    if (position_ctrl.send_cnt > POSITION_ERR_MAX)
    {
        _position_err();
        return HAL_ERROR;
    }

    uint8_t *buf = _position_ctrl.cmd_send_buf;
    int16_t ret = 0;

    uint8_t *data = buf + POSITION_HEAD_LEN;
    *(uint32_t*)data = file_s;
    data += 4;
    *(uint32_t*)data = file_ns;
    data += 4;
    *(uint32_t*)data = index * DEBUG_DATA_SIZE;

    _position_packed(POSITION_WAVE, POSITION_WAVE_LEN);

    if (_position_transmit(buf, POSITION_WAVE_LEN) != HAL_OK)
    {
        return HAL_ERROR;
    }
    if (_position_pkt_wait() == HAL_OK)
    {
        ret = _position_pkt_wave(wl_data);
        if (ret != -1)
        {
            *data_len = ret;
            return HAL_OK;
        }
        else
        {
            return HAL_BUSY;
        }
    }
    else
    {
        return HAL_TIMEOUT;
    }
}

/* 故障定位初始化 */
void position_init(void)
{
    position_ctrl.complete = FALSE;
    position_ctrl.cfg = TRUE;
    if (dev_config.wave_threshold == 0)
    {
        dev_config.wave_threshold = POSITION_THRESHOLD_MAX;
    }

    position_read(position_id, &position_data);
    
    /* 重新初始化串口波特率为115200 */
    HAL_UARTEx_ReceiveToIdle_DMA(position_usart, position_ctrl.dma_rx_buf, POSITION_CMD_BUF_LEN);
    MX_USART1_UART_ReInit();
    /* 开启485芯片电源 */
    HAL_GPIO_WritePin(SENSOR_EN_GPIO_Port, SENSOR_EN_Pin, GPIO_PIN_SET);
}
