|
- #include "common.h"
-
- /*******************************************************************************************
- * 功能 : 打开串口
- * port : 串口号, 如("COM1")
- * baud_rate: 波特率
- * date_bits: 数据位(有效范围4~8)
- * stop_bit : 停止位
- * parity : 奇偶校验。默认为无校验。NOPARITY 0; ODDPARITY 1;EVENPARITY 2
- ********************************************************************************************/
- HANDLE Init_COM(LPCTSTR port, int baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity)
- {
- HANDLE Handle_Com = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);//同步方式打开串口
- if (INVALID_HANDLE_VALUE == Handle_Com)
- {
- return INVALID_HANDLE_VALUE;
- }
- SetupComm(Handle_Com, 4096, 4096);//设置缓存
- DCB dcb;
- if (!GetCommState(Handle_Com, &dcb))
- {
- cout << "获取串口配置失败" << endl;
- }
- dcb.BaudRate = baud_rate; //波特率
- dcb.fBinary = TRUE; //二进制模式。必须为TRUE
- dcb.ByteSize = date_bits; //数据位。范围4-8
- if (stop_bit == 0)
- dcb.StopBits = ONESTOPBIT; //停止位
- if (stop_bit == 1)
- dcb.StopBits = ONE5STOPBITS; //停止位
- if (stop_bit == 2)
- dcb.StopBits = TWOSTOPBITS; //停止位
-
- if (parity == NOPARITY)
- {
- dcb.fParity = FALSE; //奇偶校验关闭
- dcb.Parity = parity; //校验模式
- }
- else
- {
- dcb.fParity = TRUE; //奇偶校验开启
- dcb.Parity = parity; //校验模式
- }
- if (!SetCommState(Handle_Com, &dcb))
- return INVALID_HANDLE_VALUE;
- PurgeComm(Handle_Com, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);//清除缓存
- //设置串口读写时间
- COMMTIMEOUTS CommTimeOuts;
- GetCommTimeouts(Handle_Com, &CommTimeOuts);
- CommTimeOuts.ReadIntervalTimeout = 5;
- CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
- CommTimeOuts.ReadTotalTimeoutConstant = 0;
- CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
- CommTimeOuts.WriteTotalTimeoutConstant = 1000;
- if (!SetCommTimeouts(Handle_Com, &CommTimeOuts)) {
- return INVALID_HANDLE_VALUE;
- }
- return Handle_Com;
- }
-
- /*********************************************************************************************
- * 功能 : 发送响应数据
- * 描述 : 向串口写入数据
- * 返回值 : true 发送成功 false 发送失败
- * m_hComm : 串口句柄
- * data : 要写入的数据
- * len : 写入数据的长度
- **********************************************************************************************/
- bool SendData(HANDLE m_hcomm, char* data, int len)
- {
- if (m_hcomm == INVALID_HANDLE_VALUE)
- return FALSE;
-
- PurgeComm(m_hcomm, PURGE_RXCLEAR | PURGE_TXCLEAR);
- DWORD dwWrite = 0;
- int count = 0;
- while (!WriteFile(m_hcomm, data, len, &dwWrite, NULL))
- {
- count++;
- if (count > 4)
- return false;
- }
- return true;
- }
-
- bool Abnormal_Connection(HANDLE *handle_com)
- {
- printf("设备端口异常,请检查设备连接状态\n");
- printf("**************************** Press Enter To Contioun ****************************\n");
- getchar();
- system("cls");
- printf("是否重新连接端口: 1 重新连接 0 关闭本软件\n");
- int flage = 0;
- do
- {
- cin >> flage;
- cin.clear();
- cin.sync();
- } while (!(flage == 0 || flage == 1));
- if (flage == 0)
- {
- return false;
- }
- CloseHandle(*handle_com);
- *handle_com = Input_Parameter();
- return true;
- }
-
- bool Recv_date(HANDLE *handle_com, UINT8 *Requst_Message, DWORD *read_len)
- {
- PurgeComm(*handle_com, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);//清除缓存
- BOOL read_flage = ReadFile(*handle_com, Requst_Message, 300, &(*read_len), NULL); //阻塞等待接收请求报文
- if (read_flage && (*read_len > 0))
- {
- return true;
- }
- if (!Abnormal_Connection(handle_com))
- return false;
- return true;
- }
- /*********************************************************************************************
- * 功能 : 检查端口名称
- * 描述 : 判断端口名称是否正确
- * 输入 : Comm 端口名
- * 返回值 : true 端口名正确
- * false 端口名错误
- **********************************************************************************************/
- bool Check_Input_COMM(string comm)
- {
- string compare1 = "com";
- string compare2 = "COM";
- for (unsigned int i = 0; i < 3; i++)
- {
- if (comm[i] != compare1[i] && comm[i] != compare2[i])
- return false;
- }
- if (comm[3] == 0x30)
- return false;
- for (unsigned int i = 4; i < comm.length(); i++)
- {
- if (comm[i] >= 0x30 && comm[i] <= 0x39)
- continue;
- }
- return true;
- }
-
- /*********************************************************************************************
- * 功能 : 输入端口名称
- * 描述 : 获取串口通信的端口名称
- * 输入 : 无
- * 返回值 : COMM 端口名
- **********************************************************************************************/
- string Input_COMM(void)
- {
- int flage = 1;
- string comm;
- do
- {
- if (flage == 1)
- {
- printf("请输入端口名称:");
- flage = 0;
- }
- else
- printf("请重新输入端口名称:");
- cin >> comm;
- cin.clear();
- cin.sync();
- } while (!Check_Input_COMM(comm));
- return comm;
- }
-
- /*********************************************************************************************
- * 功能 : 检查波特率
- * 描述 : 检查串口通信的波特率
- * 输入 : Baud_Rate 波特率
- * 返回值 : true 波特率正确
- * false 波特率错误
- **********************************************************************************************/
- bool Check_Input_Baud_Rate(unsigned int baud_rate)
- {
- unsigned int compare_baud_rate[9] = {300,600,1200,2400,4800,9600,14400,19200,38400};
- for (int i = 0; i < 9; i++)
- {
- if (baud_rate == compare_baud_rate[i])
- return true;
- }
- return false;
- }
-
- /*********************************************************************************************
- * 功能 : 输入波特率
- * 描述 : 获取串口通信的波特率
- * 输入 : 无
- * 返回值 : Baud_Rate 波特率
- **********************************************************************************************/
- unsigned int Input_Baud_Rate(void)
- {
- unsigned int baud_rate;
- int flage = 1;
- printf("支持的波特率有:300,600,1200,2400,4800,9600,14400,19200,38400 \n");
- do
- {
- if (flage == 1)
- {
- printf("请输入串口波特率:");
- flage = 0;
- }
- else
- printf("请重新输入串口波特率:");
- cin >> baud_rate;
- cin.clear();
- cin.sync();
- } while (!Check_Input_Baud_Rate(baud_rate));
- return baud_rate;
- }
-
-
- /*********************************************************************************************
- * 功能 : 输入数据位
- * 描述 : 获取串口通信的数据位个数
- * 输入 : 无
- * 返回值 : Date_Bits 数据位
- **********************************************************************************************/
- BYTE Input_Date_Bits(void)
- {
- BYTE date_bits;
- int flage = 1;
- unsigned int data_bits_temp = 0;
- printf("支持的数据位有:5,6,7,8 \n");
- do
- {
- if (flage == 1)
- {
- printf("请输入有效数据位:");
- flage = 0;
- }
- else
- printf("请重新输入有效数据位:");
- cin >> data_bits_temp;
- cin.clear();
- cin.sync();
- } while (!(data_bits_temp == 5 || data_bits_temp == 6 || data_bits_temp == 7 || data_bits_temp == 8));
- date_bits = (BYTE)data_bits_temp;
- return date_bits;
- }
-
- /*********************************************************************************************
- * 功能 : 检查停止位
- * 描述 : 检测停止位是否和数据位相符
- * 输入 : Date_Bits 数据位
- * Stop_Bits 停止位
- * 返回值 : true 停止位正确
- * false 停止位错误
- **********************************************************************************************/
- bool Check_Input_Stop_Bits(BYTE date_bits, BYTE stop_bits)
- {
- if (stop_bits == 0 || stop_bits == 1 || stop_bits == 2)
- {
- if (stop_bits == 1 && (date_bits == 6 || date_bits == 7 || date_bits == 8))
- return false;
- if (stop_bits == 2 && date_bits == 5)
- return false;
- }
- else
- return false;
- return true;
- }
-
- /*********************************************************************************************
- * 功能 : 输入停止位
- * 描述 : 获取串口通信的停止位
- * 输入 : Date_Bits 数据位
- * Stop_Bits= 0,1,2对应的是1bit,1.5bits,2bits.
- * Date_Bits=6,7,8时 Stop_Bits不能为1
- * Date_Bits=5时 Stop_Bits不能为2
- * 返回值 : Stop_Bits 数据位
- **********************************************************************************************/
- BYTE Input_Stop_Bits(BYTE date_bits)
- {
- BYTE stop_bits;
- int flage = 1;
- unsigned int temp = 0;
- printf("支持的停止位有:0,1,2 \n");
- do
- {
- if (flage == 1)
- {
- printf("请输入停止位:");
- flage = 0;
- }
- else
- printf("请重新输入停止位:");
- cin >> temp;
- cin.clear();
- cin.sync();
- } while (!Check_Input_Stop_Bits(date_bits, (BYTE)temp));
- stop_bits = (BYTE)temp;
- return stop_bits;
- }
-
- /*********************************************************************************************
- * 功能 : 选择校验位
- * 描述 : 获取串口通信的校验位
- * 输入 : 无
- * 返回值 : Parity 校验位
- **********************************************************************************************/
- BYTE Input_Parity(void)
- {
- BYTE parity;
- int flage = 1;
- unsigned int temp = 0;
- printf("支持的校验位有:0- 无校验 1- 奇校验 2- 偶校验 \n");
- do
- {
- if (flage == 1)
- {
- printf("请输入校验位:");
- flage = 0;
- }
- else
- printf("请重新输入校验位:");
- cin >> temp;
- cin.clear();
- cin.sync();
- } while (!(temp == 1 || temp == 0 || temp == 2));
- parity = (BYTE)temp;
- return parity;
- }
-
-
- /*********************************************************************************************
- * 功能 : 计算写入数据的字节数
- * 描述 : 通过对应的功能码和操作数量计算对应的数据字节数
- * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量
- * 输出 : Read_date_number 写入数据的字节数
- *********************************************************************************************/
- unsigned int Count_Read_date_number(int function_code, unsigned int operations_number)
- {
- unsigned int read_date_number = 0;
- if (function_code == 0x01 || function_code == 0x0F) //读线圈
- {
- read_date_number = operations_number / 8;
- if (operations_number % 8)
- read_date_number++;
- }
- if (function_code == 0x03 || function_code == 0x10)//读寄存器
- read_date_number = operations_number * 2;
- return read_date_number;
- }
-
-
- /*********************************************************************************************
- * 功能 : 计算CRC校验
- * 描述 : 获取Modbus—CRC-16的校验数据
- * 输入 : *Data 计算校验数据 CRC_Len 数据长度
- * 返回值 : Ret_CRC_date CRC校验结果
- **********************************************************************************************/
- UINT16 CRC_16(UINT8 *data, unsigned int crc_len)
- {
- UINT16 crc_date = 0XFFFF;//16位crc寄存器预置
- UINT16 temp;
- unsigned int i = 0, j = 0;
- for (i = 0; i < crc_len; i++)
- {
- temp = *data & 0X00FF;//将八位数据与CRC寄存器亦或
- data++;
- crc_date ^= temp;
- for (j = 0; j < 8; j++)
- {
- if (crc_date & 0X0001)//判断右移出的是不是1,如果是1则与多项式进行异或。
- {
- crc_date >>= 1;
- crc_date ^= 0XA001;
- }
- else
- {
- crc_date >>= 1;
- }
- }
- }
- UINT16 ret_crc_date = crc_date >> 8;
- ret_crc_date = ret_crc_date | crc_date << 8;
- return ret_crc_date;
- }
-
- /*********************************************************************************************
- * 功能 : 日志记录
- * 描述 : 记录每次通信的请求和响应报文
- * 输入 : *Message 消息帧存放的数组 flage = 1 请求报文 flage = 其他 响应报文
- * Message_len 报文数据长度
- * 输出 : 无
- *********************************************************************************************/
- void Log_Note(UINT8 *Message, int flage, int message_len)
- {
- FILE *fp = NULL;
- time_t timep;
- struct tm *p;
- time(&timep);
- p = gmtime(&timep);
- string recv_str = to_string(1900 + p->tm_year) + "-" + to_string(1 + p->tm_mon) + "-" + to_string(p->tm_mday)
- + " " + to_string(8 + p->tm_hour) + ":" + to_string(p->tm_min) + ":" + to_string(p->tm_sec) + " Recv:";
- string send_str = to_string(1900 + p->tm_year) + "-" + to_string(1 + p->tm_mon) + "-" + to_string(p->tm_mday)
- + " " + to_string(8 + p->tm_hour) + ":" + to_string(p->tm_min) + ":" + to_string(p->tm_sec) + " Send:";
-
- /* 打开文件用于读写 */
- if ((fp = fopen("Modbus_TCP_log.txt", "a+")) == NULL)
- {
- printf("打开文件失败");
- return;
- }
-
-
- if (flage == 1)
- {
- fwrite(send_str.c_str(), send_str.length(), 1, fp);
- for (int i = 0; i < message_len; i++)
- {
- fprintf(fp, "%02X ", Message[i]);
- }
- fprintf(fp, "\n");
- }
- else
- {
- fwrite(recv_str.c_str(), recv_str.length(), 1, fp);
- for (int i = 0; i < message_len; i++)
- {
- fprintf(fp, "%02X ", Message[i]);
- }
- fprintf(fp, "\n");
- }
- fclose(fp);
- fp = NULL;
- }
-
-
- bool cmp(string s1, string s2)
- {
- if (atoi(s1.substr(3).c_str()) < atoi(s2.substr(3).c_str()))//升序
- return true;
- else
- return false;
- }
-
- void GetComList_Reg(std::vector<string>& comList)
- {
- HKEY hkey;
- int result;
- int i = 0;
-
- result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- _T("Hardware\\DeviceMap\\SerialComm"),
- NULL,
- KEY_READ,
- &hkey);
-
- if (ERROR_SUCCESS == result) // 打开串口注册表
- {
- TCHAR portName[0x100], commName[0x100];
- DWORD dwLong, dwSize;
- do
- {
- dwSize = sizeof(portName) / sizeof(TCHAR);
- dwLong = dwSize;
- result = RegEnumValue(hkey, i, portName, &dwLong, NULL, NULL, (LPBYTE)commName, &dwSize);
- if (ERROR_NO_MORE_ITEMS == result)
- {
- // 枚举串口
- break; // commName就是串口名字"COM4"
- }
-
- comList.push_back(commName);
- i++;
- } while (1);
-
- RegCloseKey(hkey);
- }
- }
-
- void GetComm_Name(void)
- {
- vector<string> comList;
- GetComList_Reg(comList);
- sort(comList.begin(), comList.end(), cmp);
- printf("当前可用端口:");
- for (unsigned int i = 0; i < comList.size(); i++)
- {
- cout << comList[i] << " ";
- }
- printf("\n");
- }
-
- HANDLE Input_Parameter(void)
- {
- HANDLE handle_com;
- while (true)
- {
- GetComm_Name();
- string COMM = Input_COMM();
- unsigned int baud_rate = Input_Baud_Rate();
- BYTE date_bits = Input_Date_Bits();
- BYTE stop_bits = Input_Stop_Bits(date_bits);
- BYTE parity = Input_Parity();
- handle_com = Init_COM((LPCTSTR)COMM.c_str(), baud_rate, date_bits, stop_bits, parity);
- if (handle_com == INVALID_HANDLE_VALUE)
- {
- cout << "初始化串口失败,请重新输入设备信息\n" << endl;
- }
- else
- {
- printf("初始化串口成功\n");
- break;
- }
- }
- return handle_com;
- }
-
- void Printf_Message(UINT8 *Message, int flage, int message_len)
- {
- if (flage == 1)
- printf("主站请求 :");
- else
- printf("从站响应 :");
- for (int i = 0; i < message_len; i++)
- {
- printf("%02X ", Message[i]);
- }
- printf("\n");
- if (LOG_NOTE_SWITCH)
- Log_Note(Message, flage, message_len);
- }
-
|