#include #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; }