#include "includes.h"

// Modbus(RS485接口）工作模式：单向发送，向上位机发送数据, 每30秒向上位机发送一个心跳。

// modbus通讯处理
#pragma pack(push, 1)

// RF串口发送帧的循环缓冲
#define MODBUS_SENDM_DATA_COUNT 512
loopbuff_t Modbus_SendM;
uint8_t Modbus_SendM_Data[sizeof(ext_data_t) * (MODBUS_SENDM_DATA_COUNT + 1)] = {0};
// RF串口接收的消息通知
SemaphoreHandle_t	   Modbus_SendQ = NULL;    // 二值信号量句柄

typedef struct
{
    uint8_t head_L;
    uint8_t head_S;
    uint8_t id;		// 通信地址
    uint8_t cmd;	// 功能码
    uint8_t len_H;
    uint8_t len_L;
    uint8_t index;	// 包序号
    uint8_t all;	// 包数
    uint8_t PSN[7];
    uint8_t BOX[12];
//	union
//	{
//		uint16_t cnt;	// 读取：寄存器数量
//		uint16_t data;	// 写入：寄存器数据
//	};
    uint16_t crc;
} modbus_request_t;

#pragma pack(pop)

// 发送心跳报文缓冲
#define HEART_SENDBUFF_SIZE 64
uint8_t Heart_sendBuff[HEART_SENDBUFF_SIZE];

// 发送数据报文缓冲
uint8_t Modbus_sendBuff[TASK_SENDBUFF_SIZE];
void ReadModbus_Task(uint8_t c);

static void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)
{
    /* Send data */
    UART_Transmit(&huart4, pu8TxBuf, u32WriteBytes);
}
void Slave_IRQHandler(USART_Handle *huart)
{
    uint8_t u8DTU = (uint8_t) huart->Instance->DR;

    /* Handle received data */
    ReadModbus_Task(u8DTU);
}

void Modbus_Open()
{
    // 创建消息队列
    LoopBuff_Create(&Modbus_SendM, sizeof(ext_data_t), MODBUS_SENDM_DATA_COUNT, 0, (uint32_t) Modbus_SendM_Data);

    // 创建信号量
    Modbus_SendQ = xSemaphoreCreateBinary();
}

uint8_t pack_heart_send_data()
{
    uint8_t i;
    uint16_t crc;

    // 打包上报数据（按modbus从机响应的格式）
    memset(Heart_sendBuff, 0, HEART_SENDBUFF_SIZE);
    i = 0;

    // PSN
    memmove(Heart_sendBuff + i, dcBuff.configBottle.PSN, 6);
    i += 6;

    Heart_sendBuff[i++] = 0x02;	// 命令码：心跳

    // 数据长度：先预设为0，最后再修改，位置为Heart_sendBuff[7]
    Heart_sendBuff[i++] = 0;

    // 硬件版本
    Heart_sendBuff[i++] = dcBuff.powerInfo.hardVer.minor;
    // 软件版本
    Heart_sendBuff[i++] = dcBuff.powerInfo.softVer.minor;
    // 软件日期
    Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.year;
    Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.month;
    Heart_sendBuff[i++] = dcBuff.powerInfo.softDate.day;

    // 射频自检状态
    Heart_sendBuff[i++] = RF_initStatus;
    // 网口自检状态
    Heart_sendBuff[i++] = Ethernet_initStatus;
    // 网络连接状态
    Heart_sendBuff[i++] = Ethernet_IsConnected();
    // GPRS入网状态
    Heart_sendBuff[i++] = dcBuff.dtuData.networked;
    // GPRS信号强度
    Heart_sendBuff[i++] = dcBuff.dtuData.rssi;
    // GPRS连接状态
    Heart_sendBuff[i++] = dcBuff.dtuData.connected;

    // 保留备用
    i += 41;

    // 修改数据长度
    Heart_sendBuff[7] = i - 8;

    // 校验码
    crc = MODBUS_RTU_CRC16((uint8_t *) Heart_sendBuff, i);
    *(uint16_t *)(Heart_sendBuff + i) = htons(crc);
    i += 2;
    // 结束符
    Heart_sendBuff[i++] = 0x0d;
    Heart_sendBuff[i++] = 0x0a;

    return i;
}

// 任务主体
void Modbus_Task(void *p_arg)
{
    uint8_t i;
    uint32_t heartTick = 0;
    ext_data_t Gprs;

    while(TRUE)
    {
        // 本任务读取发送队列的记录
        // 这条语句用于任务切换（让其它任务有机会得到执行）
        xSemaphoreTake(Modbus_SendQ, 1000);

        if(IsTickOut(heartTick))
        {
            heartTick = GetDelayTick(30000); // 30秒以后再发

            // TODO: 发送心跳到上位机，不等待返回
//			i = pack_heart_send_data();
//			RS485_SendDataByte(Heart_sendBuff, i);
        }

        if(LoopBuff_GetCount(&Modbus_SendM))
        {
//            // 取数据
            memmove(&Gprs, LoopBuff_GetDataPtr(&Modbus_SendM, Modbus_SendM.info.rdPtr), sizeof(ext_data_t));
            LoopBuff_RemoveItems(&Modbus_SendM, 1);
//            i = pack_modbus_tran_data(&Gprs);

//            // TODO: 发送数据到上位机，不等待返回
//            RS485_SendDataByte(Modbus_sendBuff, i);
        }
    }
}

// 处理modbus rtu命令（已经验证过长度和CRC的包）
void MODBUS_RTU_CMD(modbus_request_t *req)
{
    static uint8_t BUFF2[100];	// 响应包
    uint8_t err = 0;  	// 错误代码
    uint8_t len = 0;  	// 发送数据长度
    ext_bottle_t	bottleRec;
  	uint16_t count;	  	// 通信地址
//	uint16_t reg;	  	// 数据地址
    uint16_t cnt;	  	// 数据个数
    uint16_t crc;
    ext_box_t boxRec;
	ext_data_t Gprs;
	uint8_t i;
	char* psn;
//	// 检查通信地址
		// 添加记录
//	boxCnt.count = 5;
//	for(i = 0; i < boxCnt.count; i++)
//	{
//		memset(&boxRec, 0, sizeof(ext_box_t));
//		boxRec.PSN[0] = 26;
//		boxRec.PSN[3] = (0 + i * 1) / 1000;
//		boxRec.PSN[4] = ((0 + i * 1) % 1000) >> 8;
//		boxRec.PSN[5] = ((0 + i * 1) % 1000) & 0xFF;
//		strcpy(boxRec.TGGU, "TGGU2000000");
//		boxRec.TGGU[7] = '0' + (0 + i) / 100;
//		boxRec.TGGU[8] = '0' + (0 + i) % 100 / 10;
//		boxRec.TGGU[9] = '0' + (0 + i) % 10;
//		FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * i, (uint8_t *) &boxRec, sizeof(ext_box_t));
//	}	
//	FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t));

	
	
    if(req->cmd == 0x02)		// 读保持数据
    {
        cnt = req->index;	// 参数个数      
        memset(&boxRec, 0, sizeof(ext_box_t));
			  memset(&bottleRec, 0, sizeof(ext_bottle_t));
        boxRec.PSN[0] = req->PSN[0];
        boxRec.PSN[1] = req->PSN[1];
        boxRec.PSN[2]	= req->PSN[2];
        boxRec.PSN[3] = req->PSN[3];
        boxRec.PSN[4] = req->PSN[4];
        boxRec.PSN[5] = req->PSN[5];
			
			  bottleRec.PSN[0] = req->PSN[0];
			  bottleRec.PSN[1] = req->PSN[1];
        bottleRec.PSN[2] = req->PSN[2];
        bottleRec.PSN[3] = req->PSN[3];
        bottleRec.PSN[4] = req->PSN[4];
        bottleRec.PSN[5] = req->PSN[5];
        for(int i=0; i<11; i++)
            boxRec.TGGU[i]=req->BOX[i];
						boxRec.TGGU[11]=0;
        if(req->index>0)count=req->index-1;
				
		FRAM_BufferWrite(FRAM_BOX_DATA_BASE + sizeof(ext_box_t) * count, (uint8_t *) &boxRec, sizeof(ext_box_t));
//		// 更新索引信息
		bottleRec.lastData = -1;
		FRAM_BufferWrite(FRAM_BOTTLE_DATA_BASE + sizeof(ext_bottle_t) * count, (uint8_t *) &bottleRec, sizeof(ext_bottle_t));

//		strcpy(boxTGGU[count].TGGU, boxRec.TGGU);
//		memmove(boxTGGU[count].PSN, boxRec.PSN, 6);
//		boxTGGU[count].recNo = count;
//		strcpy(boxPSN[count].TGGU, boxRec.TGGU);
//		memmove(boxPSN[count].PSN, boxRec.PSN, 6);
//		boxPSN[count].recNo = count;	

        if(req->index==req->all)		
				{					
					  boxCnt.count=req->all;
						bottleCnt.count = req->all;
            FRAM_SaveInfo(FRAM_BOX_INFO_BASE, (uint8_t *) &boxCnt, sizeof(ext_count_t));
				  	FRAM_SaveInfo(FRAM_BOTTLE_INFO_BASE, (uint8_t *) &bottleCnt, sizeof(ext_count_t));	
				}
				
    memset(BUFF2, 0, sizeof(BUFF2));
    BUFF2[len++]='L';
    BUFF2[len++]='S';
    BUFF2[len++] = dcBuff.configBottle.addr;  		// 从机地址
    BUFF2[len++] = 2;//req->cmd;							// 命令代码
    BUFF2[len++] = 0;
    BUFF2[len++] = 1;	//LEN
    BUFF2[len++] = 1;

    // 计算CRC
    crc = MODBUS_RTU_CRC16(BUFF2, len);
    crc = htons(crc);

    memmove(BUFF2 + len, &crc, 2);
    len += 2;
    RS485_SendDataByte(BUFF2, len);
    }
	else if(req->cmd == 0x05)	
	{
	          if(LoopBuff_GetCount(&Modbus_SendM))
        {
            // 取数据
            memmove(&Gprs, LoopBuff_GetDataPtr(&Modbus_SendM, Modbus_SendM.info.rdPtr), sizeof(ext_data_t));
            LoopBuff_RemoveItems(&Modbus_SendM, 1);
            i = pack_modbus_tran_data(&Gprs);

            // TODO: 发送数据到上位机，不等待返回
            RS485_SendDataByte(Modbus_sendBuff, i);
        }
	
	}
		


}

// 任务主体
uint8_t BUFF[1000] = {0};
void ReadModbus_Task(uint8_t c)
{

    static uint8_t len = 0;
    static uint16_t data_len = 0;
    static uint16_t data_len2 = 0;
//	// 取数据
//	if((len==0)&&(c=='L')) len++;
//	else return;
//	if((len==1)&&(c=='S')) len++;
//	else return;
//
//	BUFF[len++] = c;
//
//	// 验证长度和CRC值
//	if(len == sizeof(modbus_request_t))
//	{
//		if(MODBUS_RTU_CRC16(BUFF, sizeof(modbus_request_t)) == 0)
//		{
//			MODBUS_RTU_CMD((modbus_request_t *) BUFF);
//			len = 0;
//		}
//		else
//		{
//			// 丢掉第一个字节
//			memmove(BUFF, BUFF + 1, --len);
//		}
//	}
    switch(len)
    {
    case 0:
        BUFF[len]=c;
        if(c=='L') len++;
        else len=0;
        break;
    case 1:
        BUFF[len]=c;
        if(c=='S') len++;
        else len=0;
        break;
    case 2:
        BUFF[len++]=c;
        break;
    case 3:
        BUFF[len]=c;
        if(c==2) len++;
        else len=0;
        break;
    case 4:
        BUFF[len]=c;
        data_len=c<<8;
        len++;
        break;
    case 5:
        BUFF[len]=c;
        data_len|=c;
        len++;
        break;
    case 6:
        BUFF[6+data_len2++]=c;
        if(data_len2+1>data_len)
            len++;
        break;
    case 7:
        BUFF[6+data_len2++]=c;
        len++;
        break;
    case 8:
        BUFF[6+data_len2]=c;
        len=0;
        break;
    default:
        len=0;
    }
    if((len==0)&&(data_len2>1))
    {
        if(MODBUS_RTU_CRC16(BUFF, 7+data_len2) == 0)
        {
            MODBUS_RTU_CMD((modbus_request_t *) BUFF);

        }
        data_len2=0;
    }
}
