Пассивный мониторинг последовательного порта в Windows с использованием C

Я новичок в серийном программировании. Я пытаюсь закодировать пассивный монитор на C, который отображает на экране все, что написано или прочитано из COM-порта. Большая часть кода, который я видел, на самом деле читает или записывает в COM-порт.

Я пытался читать данные с COM-порта, который передает и принимает трафик Modbus, но я не получаю показаний. Я использую эмулятор последовательного порта com0com. Код работает только тогда, когда я действительно читаю с другого порта, с которым связан COM-порт.

Я пытаюсь имитировать приложение Serial Port Monitor. Пока это не работает. Любезно помочь.

Спасибо.

Ниже приведен код для чтения 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");
    }

}

1 ответ

Решение

Ваш код должен работать нормально (РЕДАКТИРОВАТЬ: если вы собираетесь использовать его вместе с com0com). Как сказал Busybee в комментарии выше, я думаю, что вы путаете свои порты или неправильно понимаете, как должен работать com0com.

У вас может быть два разных сценария:

1) Вы используете свой ПК с Windows в качестве сниффера для отслеживания транзакций Modbus между двумя другими сторонами. Например, ПЛК и удаленный датчик Modbus. В этом сценарии вам понадобятся два реальных аппаратных последовательных порта и пара виртуальных портов, предоставляемых com0com.

2) Если что-то на вашем компьютере действует как одна из сторон в транзакции Modbus, вам понадобится только последовательный порт оборудования и пара виртуальных портов.

Поскольку вы упомянули пассивный, я предполагаю, что вы находитесь в сценарии № 1. Если это так, вам просто нужно правильно выбрать порты. Я написал полный пример того, как сделать то же самое, по совпадению, и для Modbus, используя Termite и com0com, посмотрите здесь. Вы также можете взглянуть на SerialPCAP, который в сочетании с Wireshark может даже декодировать ваши сообщения Modbus.

Если вы предпочитаете изобретать велосипед, я думаю, вы можете просто отказаться от com0com и поделиться портом, как кто-то предложил в комментариях. Есть несколько интересных вопросов, которые вы, возможно, захотите прочитать, если решите пойти по этому пути, см. Здесь.

РЕДАКТИРОВАТЬ: Вы говорите, что хотите изобрести велосипед. Это нормально, но я думаю, вам нужно подумать о некоторых вещах, прежде чем начинать писать код. Я не опытный разработчик последовательного порта; гораздо меньше в Windows и еще меньше в последних версиях Windows. Но я уже провел некоторое исследование по этой теме, чтобы высказать свое мнение:

-Большинство из нас, не изобретателей Wheelre, были бы более чем счастливы контролировать наши последовательные порты с помощью методов виртуального последовательного порта, описанных выше (я повторюсь еще раз: для мониторинга трафика Modbus RTU посмотрите Wireshark/SerialPCAP, и вы забудете о что-нибудь еще). Моим первым впечатлением было то, что вы хотели это сделать (вот почему вы говорили о com0com). Читая ваши комментарии, я думаю, что этого недостаточно для вас (я понимаю это, я предпочитаю чистые решения грязным трюкам).

-Теперь, имея это ясно, ты можешь что-нибудь сделать? Из пользовательского пространства я не думаю, что в настоящее время вы можете использовать общий последовательный порт. Уловка в комментарии к вашему вопросу, в котором упоминаетсяdwShareModeВозможно, это сработало еще в 90-е, но, боюсь, больше не будет. Подробнее см. Здесь.

-Если вы поедете в Driverland, у вас могут быть шансы. Прочтите здесь. Другие полезные ссылки: 1, 2.

Мой вывод таков: для вашего кода нет исправления, то, что вы хотите сделать, более сложное, чем то, что у вас есть.

Другие вопросы по тегам