#include <iostream>
#include "modbus_lib/modbus-tcp.h"
#include "ysp_modbus_slave.h"
#include "database/database.h"

using namespace std;
#define REG_ADDR (header_length+1)
#define REG_NUM (header_length+3)
#define REG_VAL (header_length+3)

#define IP_LOCAL_ADDR "192.168.1.21"
#define TCP_PORT 1502
#define MODBUS_UART "COM3" //爱尔兰项目用不到 uart modbus
#define SERVER_ID 0x00000001	//默认从机地址
#define SLAVE_REG_ADDR 0x008E	//从机modbus 地址的寄存器地址

char slave_ip_addr[20] = { 0 }; //modbus slave tcp ip地址
unsigned short slave_tcp_port = TCP_PORT; //modbus slave tcp port端口号



ysp_modbus_regs_t ysp_modbus_data;
slave_add_t salve_addr = {0};

enum {
	TCP,
	TCP_PI,
	RTU
};

int xSlave_info_init()
{
	salve_addr.slave_addr = SERVER_ID;
	memset(&ysp_modbus_data, 0, sizeof(ysp_modbus_data));
	memcpy(slave_ip_addr, IP_LOCAL_ADDR, strlen(IP_LOCAL_ADDR));

	return 0;
}

//modbus 从机tcp ipaddr
void xSet_slave_ip_addr(const char* ip_addr)
{
	if (ip_addr) {
		memcpy(slave_ip_addr, ip_addr, strlen(ip_addr));
		printf("slave_ip_addr=%s\n", slave_ip_addr);
	}

	else {
		memcpy(slave_ip_addr, IP_LOCAL_ADDR, strlen(IP_LOCAL_ADDR));
		printf("SLAVE_IP_ADDR is null,use default\n");
	}
}

//modbus从机tcp port
void xSet_slave_port(const char* tcp_port)
{
	if (tcp_port) {
		slave_tcp_port = atoi(tcp_port);
		printf("tcp_port=%s\n", tcp_port);
		printf("slave_tcp_port=%d\n", slave_tcp_port);
	}
	else {
		slave_tcp_port = TCP_PORT;
		printf("SLAVE_PORT is null,use default\n");
	}
}
DWORD WINAPI xModbus_msg_ThreadProc(LPVOID lp) {
	char* com = (char*)lp;
	CHAR rcv_buf[1024] = { 0 };
	int s = -1;
	int i = 0;
	int rc = 0;
	modbus_t* ctx = NULL;
	uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];//接收缓冲区
	int header_length;
	uint16_t* ptr,*ptr1;
	int use_backend=TCP;
	uint16_t reg_addr, reg_val, reg_num;
	uint16_t tmp = 0;
	modbus_mapping_t* mb_mapping;


		/*
			一次只接受一个主机master连接
			即 accept 只接受一个客户端连接，该连接错误退出后，重新走到这里来accept
		*/

		if (use_backend == TCP) {
			ctx = modbus_new_tcp(slave_ip_addr, slave_tcp_port);
			//modbus_set_slave(ctx, SERVER_ID); 
		}
		else if (use_backend == TCP_PI) {
			ctx = modbus_new_tcp_pi(slave_ip_addr, "1502");
		}
		else {
			ctx = modbus_new_rtu(MODBUS_UART, 115200, 'N', 8, 1);
			modbus_set_slave(ctx, SERVER_ID);
		}

		//modbus_set_indication_timeout(ctx, 4, 0);
		header_length = modbus_get_header_length(ctx);
		modbus_set_debug(ctx, TRUE);
		printf("modbus set debug true\n");

		mb_mapping = modbus_mapping_new(0, 0, sizeof(ysp_modbus_regs_t) / 2 + sizeof(slave_add_t) / 2, 0);
		printf("total regs nums = %d\n", sizeof(ysp_modbus_regs_t) / 2 + sizeof(slave_add_t) / 2);
		if (mb_mapping == NULL) {
			fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));
			modbus_free(ctx);
			return -1;
		}
		if (use_backend == TCP) {
			std::cout << "modbus start listen\n" << std::endl;
			s = modbus_tcp_listen(ctx, 1);
			if (-1 == s) {
				std::cout << "modbus tcp listen fial,check ip or port,exit thread\n" << std::endl;
				return -1;
			}
		}
		else if (use_backend == TCP_PI) {
			s = modbus_tcp_pi_listen(ctx, 1);
		}
		else {
#if 0
			rc = modbus_connect(ctx);
			if (rc == -1) {
				fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
				modbus_free(ctx);
				return -1;
			}
#endif 
		}

		for (;;) {
			if (use_backend == TCP) {
				std::cout << std::endl << "modbus accept wait connect (hold)\n" << std::endl;
				modbus_tcp_accept(ctx, &s);
				std::cout << "modbus accept new connect\n" << std::endl;
			}
			else if (use_backend == TCP_PI) {
				modbus_tcp_pi_accept(ctx, &s);
			}
			else {
				rc = modbus_connect(ctx);
				if (rc == -1) {
					fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
					modbus_free(ctx);
					return -1;
				}
			}
			std::cout << "modbus receive loop\n" << std::endl;
			for (;;) {//循环接受消息
				do {
					rc = modbus_receive(ctx, query);
					/* Filtered queries return 0 */
				} while (rc == 0);//地址错误会返回0,CRC错误会返回-1和errno=EMBBADCRC,正常会返回接收到的字节数

				/* The connection is not closed on errors which require on reply such as
				   bad CRC in RTU. */
				if (rc == -1 && errno != EMBBADCRC) {
					/* Quit */
					std::cout << "error once connect over 1" << std::endl;
					break;
				}
				if (rc == -1)
				{
					if (errno == EMBBADCRC)
					{
						std::cout << "bad crc in query" << std::endl;
						continue;
					}
					else
					{
						std::cout << "parse modbus frame error: %s\n" << std::endl;
						std::cout << "error once connect over 2" << std::endl;
						break;
					}
				}
				std::cout << "modbus new msg\n" << std::endl;
				switch (query[header_length])
				{
				case MODBUS_FC_READ_COILS://0x01 Read Coils in mb_mapping->tab_bits：IO输出状态
					printf("unsurported function 2\n");
					//否定应答,暂不做数据映射
					modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_ILLEGAL_FUNCTION);
					break;
				case MODBUS_FC_READ_DISCRETE_INPUTS://0x02 Read Discrete Inputs in mb_mapping->tab_input_bits：IO输入状态
					printf("unsurported function 2\n");
					//否定应答,暂不做数据映射
					modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_ILLEGAL_FUNCTION);
					continue;
					break;
				case MODBUS_FC_READ_HOLDING_REGISTERS://0x03 Read Holding Registers in mb_mapping->tab_registers:REG输出
					//读寄存器 
					std::cout << "modbus function 0x03\n" << std::endl;
					if (MODBUS_GET_INT16_FROM_INT8(query, REG_ADDR) < (sizeof(ysp_modbus_regs_t) / 2 + sizeof(slave_add_t) / 2))
					{
						printf("reg vaild\n");
						//读取实时数据
						if ((MODBUS_GET_INT16_FROM_INT8(query, REG_ADDR) + MODBUS_GET_INT16_FROM_INT8(query, REG_NUM)) > (sizeof(ysp_modbus_regs_t) / 2)+ (sizeof(slave_add_t) / 2))
						{
							printf("reply to this special register address by an exception\n");
							//否定应答
							modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
							continue;
						}
						printf("update data\n");
						//气体数据
						if (fill_ysp_data(&ysp_modbus_data)) {
							printf("get data from database fail, erase regs\n");
							//memset(&ysp_modbus_data, 0, sizeof(&ysp_modbus_data)); 不擦除，回复上次结果
						}
						printf("time h32:%d\n", ysp_modbus_data.time_H32);
						printf("time l32:%d\n", ysp_modbus_data.time_L32);
						ptr = (uint16_t*)&ysp_modbus_data;
						for (i = 0; i < (sizeof(ysp_modbus_regs_t) / 2); i++)
						{
							mb_mapping->tab_registers[i] = ptr[i];
						}
						ptr1 = (uint16_t*)&salve_addr;
						mb_mapping->tab_registers[i] = ptr1[1];//i越小，越先传输
						mb_mapping->tab_registers[i+1] = ptr1[0];//ptr1[0] 里存的是低地址数据
						//mb_mapping->tab_registers[i] =0x3344;
						//mb_mapping->tab_registers[i+1] = 0x5566;
					}
					break;
				case MODBUS_FC_READ_INPUT_REGISTERS://0x04 Read Input Registers in mb_mapping->tab_input_registers:REG输入
					//可用于读取测量值等不可上位机修改的量,暂不做数据映射
					break;
				case MODBUS_FC_WRITE_SINGLE_COIL://0x05 Write Single Coil:slave_addr+cmd+reg_addr+[FF 00 or 00 00]+crc corresponding to mb_mapping->tab_bits
					//写单个继电器
					break;
				case MODBUS_FC_WRITE_SINGLE_REGISTER://0x06 Write Single Register:slave_addr+cmd+reg_addr+reg_val+crc corresponding to mb_mapping->tab_registers
					//写单个寄存器,暂不做数据映射
					printf("function code 0x06\n");
					reg_addr = MODBUS_GET_INT16_FROM_INT8(query, REG_ADDR);
					reg_val = MODBUS_GET_INT16_FROM_INT8(query, REG_VAL);
					printf( "reg_addr=%d reg_val=0x%04x\n", reg_addr, reg_val);
					if (reg_addr == SLAVE_REG_ADDR)
					{
						printf("modify slave address succ\n");
						salve_addr.slave_addr = reg_val;
					}
					break;
				case MODBUS_FC_WRITE_MULTIPLE_COILS://0x0F Write Multiple Coils:slave_addr+cmd+reg_addr+coil_num+bit_arr+crc corresponding to mb_mapping->tab_bits
					//写多个继电器,暂不做数据映射
					break;
				case MODBUS_FC_WRITE_MULTIPLE_REGISTERS://0x10 Write Multiple Registers:slave_addr+cmd+reg_addr+reg_num+reg_val_arr+crc corresponding to mb_mapping->tab_registers
					//写多个寄存器
					break;
				default://
					break;
				}

				//正常应答
				rc = modbus_reply(ctx, query, rc, mb_mapping);
				if (rc == -1) {
					printf("reply modbus frame error:%s\n", modbus_strerror(errno));
					break;
				}
		}

	}

	return 0;
}
int xModbus_task_init()
{
	// 创建线程，返回句柄
	int a = 0;

	xSlave_info_init();
	Sleep(10);
	HANDLE h = CreateThread(NULL, 0, xModbus_msg_ThreadProc, NULL, 0, 0);
	printf("start Modbus thread\n");
	//WaitForSingleObject(h, INFINITE);


	//CloseHandle(h);
	return 0;
}