#include "protocol.h"
#include "stdint.h"
#include "stdlib.h"
#include "string.h"
#include "node_message.h"
/*****************************protocol主要为主网关与子节点通讯的协议使用**********************************/
/*****************************其主要作用主网关给子节点轮询发送数据的编码**********************************/
/*****************************子节点解析该主网关发送的数据              **********************************/
/*****************************子节点回应对应的响应                     **********************************/
/*****************************子节点回应对应的响应的解析               **********************************/

static volatile int deviceNum = 0;		// 记录轮询读取设备的结束位置
static volatile int paramsNum = 0;		// 记录轮询读取属性的结束位置
static volatile int startDeviceNum = 0; // 记录轮询读取设备的开始位置
static volatile int startParamsNum = 0; // 记录轮询读取设备属性的开始位置
void insertHexData(uint8_t *String, const uint8_t *hexData, uint8_t insertIndex, uint8_t length);

enum
{
	protocol_dlt645_97 = 0x08,
	protocol_modbus_read,
	protocol_dlt645_07
} PROTOCOL_LENGTH; // 每个协议的数据包长度用于最开始区分不同协议
// 枚举采集数据的存储个数
enum
{
	typeInt = 1,
	typeFloat,
	typeDouble
} DATAType;
// 枚举MODBUS协议具体功能
enum
{
	READ_COIL = 0x01,
	WRITE_COIL = 0x05,
	WRITE_COILS = 0x0F,
	READ_REGISTER = 0x03,
	WRITE_REFISTER = 0x06,
	WRITE_REGISTERS = 0x10
} MODBUS_COMMAND;
// 大小端
typedef enum
{
	MModBus_16bitOrder_AB = 1, // 大端
	MModBus_16bitOrder_BA,
} MModBus_16bitOrder_t;
/*
*********************************************************************************************************
*	函 数 名: void masterSendNodeString(uint8_t nodeIndex)Index下标从0开始
*	功能说明: 负责取出网关第nodeIndex下的数据组成下发格式的数据,注：此处没有对node是否为NULL进行判断，请确保有该节点的信息
*	形    参：nodeIndex第几个节点数据、string所总成的传递的字符串、size组成的字符串大小
*	返 回 值: 0:该节点下已经没有属性需要在去读出了，1:该节点下还拥有其他属性等待读出。
	注：其一次性只能传输20条属性的值若超出其范围还有数据则要多次组成发送
	逻辑：每次调用该函数都会总成一条string,属性足够的时候会组成一条具有20个属性的指令，并记录结束的设备链表位置，属性链表位置，下次再调用从结束位置再开始，到最后可能就组成不了20个属性的string了，此时将开始的设备num,属性都归位
				且也要记录每次开始的设备位置和属性位置，方便接收应答信号的解析
*********************************************************************************************************
*/

int masterSendNodeString(uint8_t nodeIndex, uint8_t *string, uint16_t *size)
{
	startDeviceNum = deviceNum; // 起始位置等于上次结束的位置
	startParamsNum = paramsNum; // 起始位置等于上次结束的位置
	int nowDeviceNum = deviceNum;
	int nowparamsNum = paramsNum;
	GATEWAY_PARAMS *gateway;
	gateway = get_gateway_config_params();

	// 将当前的节点指针指到需要读取的节点位置
	NODE_PARAMS *currentNode = gateway->node_params;
	while (nodeIndex)
	{
		currentNode = currentNode->nextNode;
		nodeIndex--;
	}
	memset(string, 0, 256); // 清除上一次数据
	// 将首字符用nodeAdress
	string[0] = currentNode->node_address[0];
	string[1] = currentNode->node_address[1];
	// 找到当前的设备结束位置
	DEVICE_PARAMS *currentDevice = currentNode->device_params;
	while (nowDeviceNum)
	{
		currentDevice = currentDevice->nextDevice;
		nowDeviceNum--;
	}

	// 移动位置到结束位置属性的下一位
	NODE_READ_MODBUS_COMMAND *currentModbusParams = currentDevice->params->node_read_modbus_command;
	NODE_READ_DLT645_COMMAND *currentDlt645Params = currentDevice->params->node_read_dlt645_command;
	switch (currentDevice->protocol)
	{
	case MODBUS:
		while (nowparamsNum)
		{
			currentModbusParams = currentModbusParams->nextParams;
			nowparamsNum--;
		}
		break;
	case DLT645_07:
	case DLT645_97:

		while (nowparamsNum)
		{
			currentDlt645Params = currentDlt645Params->nextParams;
			nowparamsNum--;
		}
		break;
	default:
		break;
	}

	// 最多进行20次循环组成下发数据
	int i = 0;
	int len;
	len = strlen(string);
	do
	{
		switch (currentDevice->protocol)
		{
		case MODBUS_READ:
		{
			uint8_t protocolHexData = protocol_modbus_read;
			insertHexData(string, &protocolHexData, len, 1); // 插入modbus长度
			len++;
			insertHexData(string, &currentModbusParams->functionCode, len, 1); // 插入读取功能码
			len++;
			insertHexData(string, &currentModbusParams->dataType, len, 1); // 插入读取的数据格式
			len++;
			insertHexData(string, &currentModbusParams->slaveAddress, len, 1); // 插入modbus从站地址
			len++;
			insertHexData(string, (uint8_t *)&currentModbusParams->registerAddress, len, 2); // 插入modbus寄存器地址
			len += 2;
			insertHexData(string, &currentModbusParams->decimalPoint, len, 1); // 插入小数点位数
			len++;
			insertHexData(string, &currentModbusParams->bigLittleFormat, len, 1); // 插入大小端
			len++;
			// 属性读取完毕，移位到下一个属性
			i++;
			currentModbusParams = currentModbusParams->nextParams;
			if (currentModbusParams == NULL)
			{
				currentDevice = currentDevice->nextDevice;
				if (currentModbusParams == NULL)
				{
					deviceNum = 0; // 将结束位置全部归0
					paramsNum = 0;
					*size = len;
					return 1;
				}
				currentModbusParams = currentDevice->params->node_read_modbus_command;
				nowDeviceNum++;
				nowparamsNum = 0;
			}
			break;
		}
		case DLT645_07:
		{
			uint8_t protocolHexData = protocol_dlt645_07;
			insertHexData(string, &protocolHexData, len, 1); // 插入dlt645_07数据长度
			len++;
			insertHexData(string, (uint8_t *)&currentDlt645Params->deviceID645, len, 6); // 插入dlt645地址域
			len += 6;
			insertHexData(string, (uint8_t *)&currentDlt645Params->Identification, len, 4);
			len += 4;
			// 属性读取完毕，移位到下一个属性
			i++;
			currentDlt645Params = currentDlt645Params->nextParams;
			if (currentDlt645Params == NULL)
			{
				currentDevice = currentDevice->nextDevice;
				if (currentDevice == NULL)
				{
					deviceNum = 0; // 将结束位置全部归0
					paramsNum = 0;
					*size = len;
					return 1;
				}
				currentDlt645Params = currentDevice->params->node_read_dlt645_command;
				nowDeviceNum++;
				nowparamsNum = 0;
			}
			break;
		}
		case DLT645_97:
		{
			uint8_t protocolHexData = protocol_dlt645_97;
			insertHexData(string, &protocolHexData, len, 1); // 插入dlt645_97数据长度
			len++;
			insertHexData(string, (uint8_t *)&currentDlt645Params->deviceID645, len, 6); // 插入dlt645_97地址域
			len += 6;
			insertHexData(string, (uint8_t *)&currentDlt645Params->Identification, len, 2); // 插入dlt645_97数据标识
			len += 2;
			// 属性读取完毕，移位到下一个属性
			i++;
			currentDlt645Params = currentDlt645Params->nextParams;
			if (currentDlt645Params == NULL)
			{
				currentDevice = currentDevice->nextDevice;
				if (currentDlt645Params == NULL)
				{
					deviceNum = 0; // 将结束位置全部归0
					paramsNum = 0;
					*size = len;
					return 1;
				}
				currentDlt645Params = currentDevice->params->node_read_dlt645_command; // 还有属性则更新位置
				nowDeviceNum++;
				nowparamsNum = 0;
			}
			break;
		}
		default:
			goto end_while;
		}
		nowparamsNum++;
	} while (i != 20);
end_while:
	// 更新结束的位置分为两种情况，一种还在当前设备的属性中轮询此时nowDeviceNum没有改变过,另外一种情况设备内的属性
	if (nowDeviceNum == 0)
	{
		deviceNum = startDeviceNum;
		paramsNum = startParamsNum + nowparamsNum;
	}
	else
	{
		deviceNum = startDeviceNum + nowDeviceNum;
		paramsNum = nowparamsNum - 1;
	}
	*size = len;
	return 0;
}
/*
*********************************************************************************************************
*	函 数 名: void insertHexData(uint8_t *originalString,const uint8_t *hexData,int position)
*	形    参：uint8_t *String需要插入的字符串，hexData插入的hex数据，insertIndex插入的下标位置，length插入的数据长度
*	返 回 值: 无
  注：插入的数据以被插入的字符串都可能包含0x00不要使用strlen
*********************************************************************************************************
*/
void insertHexData(uint8_t *String, const uint8_t *hexData, uint8_t insertIndex, uint8_t length)
{
	memcpy(String + insertIndex, hexData, length);
}

/*
*********************************************************************************************************
*	函 数 名: uint8_t SlaveProtocolAnalysis(uint8_t *buff,uint16_t len)
*	形    参：uint8_t *buff等待解析的字符串数据，
*	返 回 值: 0:不是该节点的消息，数据没有进行任何处理。1:为该节点信息，接收到要进行的相应的切换工作
	解析这段数据时要先判断是否为该节点的消息，stuct B *p=malloc(sizeof(struct B);
*********************************************************************************************************
*/
#ifdef slave
#define LocalAddress 0x1F6E
uint8_t SlaveProtocolAnalysis(uint8_t *buff, uint16_t len)
{
	NODE_DEVICE_PARAMS *node_receive_params;
	node_receive_params = get_node_receive_params();
	uint16_t slaveAdress = buff[0] << 8 | buff[1];
	int protocol_location = 2; // 起始的协议所处位置
	uint8_t i = 0;
	while (1)
	{
		if (slaveAdress == LocalAddress) // 判断此消息是否为该节点的消息，如果不是则跳出
		{
			switch (buff[protocol_location]) // 读取接收到的数据属于什么协议
			{
			case protocol_modbus_read:
				protocol_location++;
				node_receive_params->params[i].protcol = MODBUS_READ;
				node_receive_params->params[i].dlt645_params = NULL;
				node_receive_params->params[i].modbus_read = malloc(sizeof(NODE_MODBUS_READ));
				node_receive_params->params[i].modbus_write = NULL;
				node_receive_params->params[i].modbus_read->functionCode = buff[protocol_location + 1];										   // 读出functionCode
				node_receive_params->params[i].modbus_read->dataType = buff[protocol_location + 2];											   // 读出数据格式
				node_receive_params->params[i].modbus_read->slaveAddress = buff[protocol_location + 3];										   // 读出从站地址
				node_receive_params->params[i].modbus_read->registerAddress = buff[protocol_location + 5] << 8 || buff[protocol_location + 4]; // 读出寄存器地址
				node_receive_params->params[i].modbus_read->registerLength = buff[protocol_location + 7] << 8 || buff[protocol_location + 6];  // 读出要读的寄存器长度
				node_receive_params->params[i].modbus_read->precision = buff[protocol_location + 8];										   // 读出小数点精度
				node_receive_params->params[i].modbus_read->bigLittleFormat = buff[protocol_location + 9];									   // 读出数据大小端格式
				protocol_location += protocol_modbus_read;
				break;
			case protocol_dlt645_07:
				protocol_location++;
				node_receive_params->params[i].protcol = DLT645_07;
				node_receive_params->params[i].dlt645_params = malloc(sizeof(NODE_DLT645_PARAMS));
				node_receive_params->params[i].modbus_read = NULL;
				node_receive_params->params[i].modbus_write = NULL;
				memcpy(node_receive_params->params[i].dlt645_params->deviceType645, buff + protocol_location, 6);
				memcpy((uint8_t *)&node_receive_params->params[i].dlt645_params->dataType645, buff + protocol_location + 6, 4);
				protocol_location += protocol_dlt645_07;
				break;
			case protocol_dlt645_97:
				protocol_location++;
				node_receive_params->params[i].protcol = DLT645_97;
				node_receive_params->params[i].dlt645_params = malloc(sizeof(NODE_DLT645_PARAMS));
				node_receive_params->params[i].modbus_read = NULL;
				node_receive_params->params[i].modbus_write = NULL;
				memcpy(node_receive_params->params[i].dlt645_params->deviceType645, buff + protocol_location, 6);
				memcpy((uint8_t *)&node_receive_params->params[i].dlt645_params->dataType645, buff + protocol_location + 6, 2);
				protocol_location += protocol_dlt645_97;
				break;
			default: // 解析没满20个属性
				return 1;
			}
		}
		else
		{
			node_receive_params->Index = i; // 记录本次有多少数据传输过来了
			return 0;
		}
		i++;
		if (protocol_location > len) // 判断数据解析是否越界了,越界则跳转出
		{
			return 1;
		}
	}
}
/*
*********************************************************************************************************
*	函 数 名: nodeSendReadValue(uint8_t *string)
*	形    参：组成node回传数据，传输数据为0x
*	返 回 值: 无
*********************************************************************************************************
*/
void nodeSendReadValue(uint8_t *string)
{
	NODE_DEVICE_PARAMS *node_receive_params;
	node_receive_params = get_node_receive_params();
	int i = 0;
	int len = 0;
	while (i == 20)
	{
		switch (node_receive_params->params[i].protcol)
		{
		case DLT645_07:
		case DLT645_97:
			if (node_receive_params->params[i].dlt645_params->rxLen <= 4)
			{
				string[len] = 0x04;
				len++;
				memcpy(string[len], node_receive_params->params[i].dlt645_params->value, 4);
				len += 4;
			}
			else if (node_receive_params->params[i].dlt645_params->rxLen == 5)
			{
				string[len] = 0x05;
				len++;
				memcpy(string[len], node_receive_params->params[i].dlt645_params->value, 5);
				len += 5;
			}
			else if (node_receive_params->params[i].dlt645_params->rxLen == 9)
			{
				string[len] = 0x09;
				len++;
				memcpy(string[len], node_receive_params->params[i].dlt645_params->value, 9);
				len += 9;
			}
			else
			{
				string[len] = 0x00;
				len++;
			}
			break;
		case MODBUS:
			if (node_receive_params->params[i].modbus_read->rxLen == 4)
			{
				string[len] = 0x04;
				len++;
				memcpy(string[len], node_receive_params->params[i].dlt645_params->value, 4);
				len += 4;
			}
			else
			{
				string[len] = 0x00;
				len++;
			}
			break;
		default:
			return;
		}
		i++;
	}
}
/*
*********************************************************************************************************
*	函 数 名: GatewayProtocolAnalysis(uint8_t *string)
*	形    参：将节点应答信息依次解析为json数据
*	返 回 值: 0未读到json数据，1读到了json数据
*********************************************************************************************************
*/
int GatewayProtocolAnalysis(uint8_t *string, uint16_t len)
{
	char json[1024];
	sprintf(json, "{\"data\":[");
	// 读取上次循环最终停止位置
	int nowDeviceNum = deviceNum;
	int nowparamsNum = paramsNum - 1;
	GATEWAY_PARAMS *gateway;
	gateway = get_gateway_config_params();
	uint16_t nodeId = string[0] << 8 | string[1];
	// 将当前的节点指针指到需要读取的节点位置
	NODE_PARAMS *currentNode = gateway->node_params;
	uint16_t currentNodeId = currentNode->node_address[0] << 8 | currentNode->node_address[1];
	while (currentNodeId != nodeId)
	{
		currentNode = currentNode->nextNode;
		if (currentNode == NULL)
		{
			// 没有找到对应该节点信息不是给本机
			return;
		}
		currentNodeId = currentNode->node_address[0] << 8 | currentNode->node_address[1];
	}
	// 找到该节点进行轮询
	DEVICE_PARAMS *currentDevice = currentNode->device_params;
	while (nowDeviceNum)
	{
		currentDevice = currentDevice->nextDevice;
		nowDeviceNum--;
	}
	// 移动位置到开始属性
	NODE_READ_MODBUS_COMMAND *currentModbusParams = currentDevice->params->node_read_modbus_command;
	NODE_READ_DLT645_COMMAND *currentDlt645Params = currentDevice->params->node_read_dlt645_command;
	switch (currentDevice->protocol)
	{
	case MODBUS:
		while (nowparamsNum)
		{
			currentModbusParams = currentModbusParams->nextParams;
			nowparamsNum--;
		}
		break;
	case DLT645_07:
	case DLT645_97:

		while (nowparamsNum)
		{
			currentDlt645Params = currentDlt645Params->nextParams;
			nowparamsNum--;
		}
		break;
	default:
		break;
	}
	int index = 2; // 子节点地址
	while (index >= len)
	{
		switch (currentDevice->protocol)
		{
		case MODBUS:
			// modbus协议
			switch (*(string + index))
			{
			case 0x00:
				// 没有数据
				index++;
				break;
			case 0x04:
				if (currentModbusParams->dataType == 0x01 && currentModbusParams->decimalPoint == 0x00) // modbus底层存储的数据类型 1INT 2float
				{
					uint32_t value;
					value = string[index + 1] + string[index + 2] >> 8 + string[index + 3] >> 16 + string[index + 4] >> 24;
					sprintf(json + strlen(json), "{\"deviceId\":\"%s\",\"%s\":%d},", currentDevice->deviceID, currentModbusParams->keyword, value);
				}
				else // 如果是int且有小数点，或者底层就是float按照float来计算
				{
					float value;
					memcmp(&value, string[index + 1], 4);
					sprintf(json + strlen(json), "{\"deviceId\":\"%s\",\"%s\":%d},", currentDevice->deviceID, value);
				}
				index += 4;
				break;
			default:
				break;
			}
			currentModbusParams = currentModbusParams->nextParams;
			if (currentModbusParams == NULL)
			{
				currentDevice = currentDevice->nextDevice;
				currentModbusParams = currentDevice->params;
			}
			break;

		case DLT645_07:
		case DLT645_97:
			switch (*(string + index))
			{
			case 0x00:
			index++;
			break;
			case 0x04:
			{
				float value;
				memcmp(&value, string[index + 1], 4);
				sprintf(json + strlen(json), "{\"deviceId\":\"%s\",\"%s\":%d},", currentDevice->deviceID, currentDlt645Params->keyword, value);
				index += 4;
			}
			break;
			case 0x05:
			{
				//%02依次为年月日时分
				sprintf(json + strlen(json), "{\"deviceId\":\"%s\",\"%s\": \"%02X%02X%02X%02X%02X\"},",
						currentDevice->deviceID, currentDlt645Params->keyword, string[index + 5], string[index + 4], string[index + 3], string[index + 2], string[index + 1]);
				index += 5;
			}
			break;
			case 9:
			{
				float value;
				memcpy(&value, string[index + 1], 4);
				sprintf(json + strlen(json), "{\"deviceId\":\"%s\",\"%s\":\"%02X%02X%02X%02X%02X%.2f\"},",
						currentDevice->deviceID, currentDlt645Params->keyword, string[index + 9], string[index + 8], string[index + 7], string[index + 6], string[index + 5], value);
				index+=9;
			}
			break;
			default:
				break;
			}
			currentDlt645Params = currentDlt645Params->nextParams;
			if (currentDlt645Params == NULL)
			{
				currentDevice = currentDevice->nextDevice;
				currentDlt645Params = currentDevice->params;
			}
			break;
		default:
			break;
		}
	}
	if(strlen(string)<10)
	{
		return 0;
	}
	sprintf(json+strlen(json)-1,"]}");
}
#endif
