I’m working on an application where I use specific protocol to send packet over COM port to a hardware. I have the protocol specifications document available. I’m able to send the packets using WriteFile()
. Going through the protocol specs, I see that I must sent a specific packet every 50ms. I thought I could do this by having another thread sending this packet every 50ms so that I can do other read/write operations in the main thread. However when I try this it did not work (no TXD on RS422 adapter and not printing anything, I added cout
to see if line is executed). Only way I could send packets was if the application was singlethreaded.
Here is the code:
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);
}
Is this approach incorrect? If yes, what would be a better approach to this problem?
EDIT 1
I found out that the reason why it was getting stuck was not because of WriteFile()
rather the std::cout
. The question at the end is still relevant. I’d appreciate if someone can comment on why cout in the else block of sentBootSignal()
just stops the application.
EDIT 2
Restarting Visual Studio fixed the cout
issue however I’m still wondering about the multithreading this problem. Appreciate the responses.
2
Answers
I would expect your code to protect sending the data at least using a mutex.
The example also shows some C++ style alternatives to using "C" style arrays for sending the data
The multithreading method is as follows: