[英]Passive Monitoring Serial Port in Windows using C
我是串行编程的菜鸟。 我正在尝试在 C 中编写一个无源监视器,该监视器显示在屏幕上写入或读取 COM 端口的任何内容。 我见过的大部分代码实际上是从 COM 端口读取或写入。
我试图从正在传输和接收 Modbus 流量的 COM 端口读取数据,但我没有得到任何读数。 我正在使用 com0com 串口模拟器。 只有当我真正从与 COM 端口配对的另一个端口读取时,代码才起作用。
我正在尝试模仿串行端口监视器应用程序。 到目前为止,它不起作用。 请协助。
谢谢。
下面是 COM 的代码:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void setupPort(HANDLE * handle, char * portName);
void readFromPort(HANDLE * handle);
int main()
{
HANDLE first_port;
char * first_port_name = "COM3";
setupPort(&first_port, first_port_name);
readFromPort(&first_port);
return 0;
}
void setupPort(HANDLE * handle, char * portName)
{
BOOL status;
*handle = CreateFile(portName, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (handle == INVALID_HANDLE_VALUE)
{
printf("\n%s could not be opened\n", portName);
}
else
{
printf("\n%s successfully opened.\n", portName);
}
DCB dcbSerialParams = { 0 }; // Initializing DCB structure
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
status = GetCommState(*handle, &dcbSerialParams); //retreives the current settings
if (status == FALSE)
printf("\n Error! in GetCommState()");
dcbSerialParams.BaudRate = CBR_9600; // Setting BaudRate = 9600
dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY; // Setting Parity = None
status = SetCommState(*handle, &dcbSerialParams); //Configuring the port according to settings in DCB
if (status == FALSE)
{
printf("\n Error! in Setting DCB Structure");
}
else //If Successful display the contents of the DCB Structure
{
printf("\n\n Setting DCB Structure Successful\n");
printf("\n Baudrate = %d", dcbSerialParams.BaudRate);
printf("\n ByteSize = %d", dcbSerialParams.ByteSize);
printf("\n StopBits = %d", dcbSerialParams.StopBits);
printf("\n Parity = %d", dcbSerialParams.Parity);
}
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(*handle, &timeouts) == FALSE)
printf("\n\n Error! in Setting Time Outs");
else
printf("\n\n Setting Serial Port Timeouts Successful");
/*------------------------------------ Setting Receive Mask ----------------------------------------------*/
status = SetCommMask(*handle, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
if (status == FALSE)
printf("\n\n Error! in Setting CommMask");
else
printf("\n\n Setting CommMask successful");
}
void readFromPort(HANDLE * handle)
{
BOOL status;
DWORD dwEventMask; // Event mask to trigger
char TempChar; // Temporary Character
char SerialBuffer[256]; // Buffer Containing Rxed Data
DWORD NoBytesRead; // Bytes read by ReadFile()
int i = 0;
/*------------------------------------ Setting WaitComm() Event ----------------------------------------*/
while(TRUE)
{
printf("\n\n Waiting for Data Reception");
status = TRUE; //Wait for the character to be received
/*-------------------------- Program will Wait here till a Character is received ------------------------*/
if (status == FALSE)
{
printf("\n Error! in Setting WaitCommEvent()");
}
else //If WaitCommEvent()==True Read the RXed data using ReadFile();
{
printf("\n\n Characters Received\n");
do
{
status = ReadFile(*handle, &TempChar, sizeof(TempChar), &NoBytesRead, NULL);
SerialBuffer[i] = TempChar;
i++;
}
while (NoBytesRead > 0);
/*------------Printing the RXed String to Console----------------------*/
printf("\n\n ");
int j =0;
for (j = 0; j < i-1; j++) // j < i-1 to remove the dupliated last character
{
printf("%02X", (unsigned int)(unsigned char)SerialBuffer[j]);
}
i=0;
}
//CloseHandle(*handle);//Closing the Serial Port
printf("\n +==========================================+\n");
}
}
您的代码应该可以正常工作(编辑:只要您打算将它与 com0com 一起使用)。 正如上面评论中的busybee所建议的那样,我认为您正在混淆您的端口或误解 com0com 应该如何工作。
您可能有两种不同的情况:
1)您正在使用 Windows PC 作为嗅探器来监控其他两方之间的 Modbus 事务。 例如 PLC 和远程 Modbus 传感器。 在这种情况下,您需要两个真实的硬件串行端口和 com0com 提供的几个虚拟端口。
2)如果您的计算机中的某些东西充当 Modbus 事务中的一方,那么您只需要一个硬件串行端口和几个虚拟端口。
既然你提到了被动,我猜你是在第 1 种情况下。如果是这样,你只需要正确选择你的端口。 我写了一个关于如何做到这一点的完整示例,巧合的是,Modbus 也使用 Termite 和 com0com,看看这里。 您可能还想看看SerialPCAP ,它与 Wireshark 结合使用甚至可以解码您的 Modbus 消息。
如果您更喜欢重新发明轮子,我想您可以放弃 com0com 并按照评论中其他人的建议共享端口。 如果您决定走这条路,您可能想阅读一些有趣的问题,请参阅此处。
编辑:你说你确实想重新发明轮子。 这很好,但我认为你需要在开始编写代码之前考虑一些事情。 我不是专业的串口开发人员; 在 Windows 上要少得多,在最近的 Windows 版本上要少得多。 但是我早在很久以前就对这个话题做了一些研究,所以我可以给你我的看法:
- 我们大多数非轮式发明者都非常乐意使用上面解释的虚拟串行端口技术监控我们的串行端口(我将再重复一次:对于 Modbus RTU 流量监控,看看 Wireshark/SerialPCAP,你会忘记的还要别的吗)。 我的第一印象是您想这样做(这就是您谈论 com0com 的原因)。 阅读您的评论,我想这对您来说还不够好(我可以理解,我更喜欢干净的解决方案而不是肮脏的技巧)。
-现在,清楚了,有什么可以做的吗? 从用户空间来看,我认为您现在无法共享串行端口。 对您的问题的评论中提到dwShareMode
的技巧可能在 90 年代就起作用了,但恐怕它不再起作用了。 有关更多详细信息,请参见此处。
- 如果你 go 到 driverland,你可能会有一些机会。 在这里阅读。 其他有用的链接:1、2 。
我的结论是:你的代码没有修复,你想做的比你拥有的更复杂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.