简体   繁体   English

Windows 中的被动监控串口使用 C

[英]Passive Monitoring Serial Port in Windows using C

I am a noob at serial programming.我是串行编程的菜鸟。 I am trying to code a passive monitor in C that displays to screen whatever is written to or read from a COM port.我正在尝试在 C 中编写一个无源监视器,该监视器显示在屏幕上写入或读取 COM 端口的任何内容。 Most of the code, that I have seen actually reads from or writes to the COM Port.我见过的大部分代码实际上是从 COM 端口读取或写入。

I have tried to read from a COM port that is transmitting and receive Modbus traffic but I get no readings.我试图从正在传输和接收 Modbus 流量的 COM 端口读取数据,但我没有得到任何读数。 I am using a com0com serial port emulator.我正在使用 com0com 串口模拟器。 Only time the code works is if I actually read from the other port that the COM port is paired with.只有当我真正从与 COM 端口配对的另一个端口读取时,代码才起作用。

I am trying to mimic the Serial Port Monitor application.我正在尝试模仿串行端口监视器应用程序。 So far it is not working.到目前为止,它不起作用。 Kindly assist.请协助。

Thanks.谢谢。

Below is the code for the COM read:下面是 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");
    }

}

Your code should work fine ( EDIT: as long as you intend to use it together with com0com).您的代码应该可以正常工作(编辑:只要您打算将它与 com0com 一起使用)。 As the busybee suggested in the comment above I think you are mixing up your ports or misunderstanding how com0com is supposed to work.正如上面评论中的busybee所建议的那样,我认为您正在混淆您的端口或误解 com0com 应该如何工作。

You might have two different scenarios:您可能有两种不同的情况:

1)You are using your Windows PC as a sniffer to monitor the Modbus transactions in between two other parties. 1)您正在使用 Windows PC 作为嗅探器来监控其他两方之间的 Modbus 事务。 For instance a PLC and remote Modbus sensor.例如 PLC 和远程 Modbus 传感器。 In this scenario, you need two real hardware serial ports and a couple of virtual ports provided by com0com.在这种情况下,您需要两个真实的硬件串行端口和 com0com 提供的几个虚拟端口。

2)If something in your computer is acting as one of the parties in the Modbus transaction then you only need a hardware serial port and a couple of virtual ports. 2)如果您的计算机中的某些东西充当 Modbus 事务中的一方,那么您只需要一个硬件串行端口和几个虚拟端口。

Since you mention passive I guess you are on scenario number 1. If so you just need to choose your ports correctly.既然你提到了被动,我猜你是在第 1 种情况下。如果是这样,你只需要正确选择你的端口。 I wrote a complete example on how to do this very same, coincidentally for Modbus too using Termite and com0com, take a look here .我写了一个关于如何做到这一点的完整示例,巧合的是,Modbus 也使用 Termite 和 com0com,看看这里 You might also want to take a look to SerialPCAP , which in combination with Wireshark can even decode your Modbus messages.您可能还想看看SerialPCAP ,它与 Wireshark 结合使用甚至可以解码您的 Modbus 消息。

If you prefer to reinvent the wheel, I guess you can just drop com0com and share the port as somebody else suggested in the comments.如果您更喜欢重新发明轮子,我想您可以放弃 com0com 并按照评论中其他人的建议共享端口。 There are some interesting questions you might want to read if you decide to follow on this road, see here .如果您决定走这条路,您可能想阅读一些有趣的问题,请参阅此处

EDIT: You say you do want to reinvent the wheel.编辑:你说你确实想重新发明轮子。 That's fine but I think you need to consider some things before you jump into writing code.这很好,但我认为你需要在开始编写代码之前考虑一些事情。 I'm no expert serial port developer;我不是专业的串口开发人员; much less on Windows, and even much less on recent Windows versions.在 Windows 上要少得多,在最近的 Windows 版本上要少得多。 But I did some research on this topic way back so I can give you my view:但是我早在很久以前就对这个话题做了一些研究,所以我可以给你我的看法:

-Most of us non-wheelreinventors would be more than happy to monitor our serial ports with the virtual serial port techniques explained above (I will repeat myself once more: for Modbus RTU traffic monitoring, look at Wireshark/SerialPCAP and you'll forget about anything else). - 我们大多数非轮式发明者都非常乐意使用上面解释的虚拟串行端口技术监控我们的串行端口(我将再重复一次:对于 Modbus RTU 流量监控,看看 Wireshark/SerialPCAP,你会忘记的还要别的吗)。 My first impression was you wanted to do that (that's why you were talking about com0com).我的第一印象是您想这样做(这就是您谈论 com0com 的原因)。 Reading your comments, I guess that's not good enough for you (I can understand that, I tend to prefer clean solutions to dirty tricks).阅读您的评论,我想这对您来说还不够好(我可以理解,我更喜欢干净的解决方案而不是肮脏的技巧)。

-Now, having that clear, is there something you can do? -现在,清楚了,有什么可以做的吗? From userspace, I don't think you can share a serial port nowadays.从用户空间来看,我认为您现在无法共享串行端口。 The trick on the comment to your question that mentions dwShareMode might have worked back in the 90s, but I'm afraid it won't work anymore.对您的问题的评论中提到dwShareMode的技巧可能在 90 年代就起作用了,但恐怕它不再起作用了。 For more details see here .有关更多详细信息,请参见此处

-If you go to driverland, you might have some chances. - 如果你 go 到 driverland,你可能会有一些机会。 Read here . 在这里阅读。 Other useful links: 1 , 2 .其他有用的链接:1、2

My conclusion is: there is no fix for your code, what you want to do is more involved than what you have.我的结论是:你的代码没有修复,你想做的比你拥有的更复杂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM