为什么我无法在 C++ 中将字节数据包从单独的线程发送到 COM 端口?

问题描述 投票:0回答:1

我正在开发一个应用程序,我使用特定协议通过 COM 端口将数据包发送到硬件。我有可用的协议规范文档。我可以使用

WriteFile()
发送数据包。通过查看协议规范,我发现我必须每 50 毫秒发送一个特定的数据包。我认为我可以通过让另一个线程每 50 毫秒发送此数据包来实现此目的,以便我可以在主线程中执行其他读/写操作。但是,当我尝试此操作时,它不起作用(RS422 适配器上没有 TXD 并且没有打印任何内容,我添加了
cout
以查看该行是否执行)。我发送数据包的唯一方法是应用程序是单线程的。

这是代码:

void sendBootSignal(HANDLE h_Serial, byte packetArr[], DWORD size)
{
    DWORD dwWrite = 11;
    if (!WriteFile(h_Serial, packetArr, (DWORD)size, &dwWrite, NULL))
    {
        std::cout << "error while WriteFile" << std::endl;
    }
    else
    {
        std::cout << "succesfully send boot packet" << std::endl;
    }
}

void bootThread(HANDLE h_Serial, byte packetArr[], DWORD size)
{
    while (true)
    {
        sendBootSignal(h_Serial, packetArr, size);
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
}
int main()
{
    h_Serial = CreateFile(L"COM3", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (h_Serial == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() == ERROR_FILE_NOT_FOUND)
        {
            std::cout << "Serial Port not found" << std::endl;
        }
        std::cout << "error while establishing communication" << std::endl;
    }

    DCB dcbSerialParam = { 0 };
    dcbSerialParam.DCBlength = sizeof(dcbSerialParam);

    if (!GetCommState(h_Serial, &dcbSerialParam))
    {
        std::cout << "error when getting comm state" << std::endl;
    }

    dcbSerialParam.BaudRate = CBR_115200;
    dcbSerialParam.ByteSize = 8;
    dcbSerialParam.StopBits = ONESTOPBIT;
    dcbSerialParam.Parity = NOPARITY;
    dcbSerialParam.fDtrControl = DTR_CONTROL_DISABLE;

    if (!SetCommState(h_Serial, &dcbSerialParam))
    {
        std::cout << "error while setting comm state" << std::endl;
    }

    COMMTIMEOUTS timeout = { 0 };
    timeout.ReadIntervalTimeout = 60;
    timeout.ReadTotalTimeoutConstant = 60;
    timeout.ReadTotalTimeoutMultiplier = 15;
    timeout.WriteTotalTimeoutConstant = 60;
    timeout.WriteTotalTimeoutMultiplier = 8;

    if (!SetCommTimeouts(h_Serial, &timeout))
    {
        std::cout << "timeout " << std::endl;
    }

    byte bootPacket[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    bootPacket[0] = 0x10;
    bootPacket[1] = 0x00;
    bootPacket[2] = 0x80;
    bootPacket[3] = 0x00;
    bootPacket[4] = 0x48;
    bootPacket[5] = 0x00;
    bootPacket[6] = 255;
    bootPacket[7] = 0x00;
    bootPacket[8] = 0x00;
    bootPacket[9] = 0x10;
    bootPacket[10] = 0x03;

    DWORD size = 11;
    sizeCalculator(bootPacket, size);
    checksumCalculator(bootPacket, size);
    std::thread t1(bootThread, h_Serial, bootPacket, size);


    while (true)
    {
        // do other things here
    }

    CloseHandle(h_Serial);
}

这种做法不正确吗?如果是,解决这个问题的更好方法是什么?


编辑1

我发现卡住的原因不是因为

WriteFile()
,而是因为
std::cout
。最后的问题仍然有意义。如果有人可以评论为什么
sentBootSignal()
的 else 块中的 cout 只是停止应用程序,我将不胜感激。


编辑2

重新启动 Visual Studio 修复了

cout
问题,但我仍然想知道多线程这个问题。感谢您的回复。

c++ winapi serial-port
1个回答
0
投票

我希望您的代码至少使用互斥锁来保护发送数据。 该示例还展示了一些使用“C”样式数组发送数据的 C++ 样式替代方案

#include <array>
#include <iostream>
#include <mutex>
#include <span>
#include <Windows.h>


class YourDevice
{
public:
    YourDevice() 
    {
        // open serial port etc...
    }

    ~YourDevice()
    {
        // close serial port etc...
    }

    // send a packet of N bytes
    // Note I use std::uint8_t instead of char to avoid confusion with strings (and signedness)
    // used when size is know at compile time
    template<DWORD N>
    void sendPacket(const std::uint8_t(&packet)[N])
    {
        // ensure only one thread can send a packet at a time
        std::scoped_lock lock(m_mtx);
        
        DWORD dwWrite = N;
        if (!WriteFile(m_serial, packet, N, &dwWrite, NULL))
        {
            std::cout << "error while WriteFile" << std::endl;
        }
        else
        {
            std::cout << "succesfully send boot packet" << std::endl;
        }
    }
    
    // used when size is only known at runtime
    void SendPacket(std::span<int> packet)
    {
         // ensure only one thread can send a packet at a time
        std::scoped_lock lock(m_mtx);

        DWORD dwWrite = packet.size();
        if (!WriteFile(m_serial, packet.data(), packet.size(), &dwWrite, NULL))
        {
            std::cout << "error while WriteFile" << std::endl;
        }
        else
        {
            std::cout << "succesfully send boot packet" << std::endl;
        }
    }

    void sendBootSignal()
    {
        // the packed is a sequence of 11 bytes initialized with the values provided within the curly braces
        sendPacket({0x10, 0x00, 0x80, 0x00, 0x48, 0x00, 0xFF, 0x00, 0x00, 0x10, 0x03});
    }

private:
    std::mutex m_mtx;
    HANDLE m_serial;

};

int main()
{
    YourDevice device;
    device.sendBootSignal();
}
© www.soinside.com 2019 - 2024. All rights reserved.