Witam serdecznie,
Ostatnim razem gdy miałem problem otrzymałem tu super pomoc. Mam nadzieję, że i tym razem się uda.
Potrzebuję pomocy w napisaniu funkcji wysyłającej i odbierającej dane po porcie COM w trybie asynchronicznym. Posiadam urządzenie które nadaje i odbiera małe paczki danych (kilka bajtów). Chciałbym jednak, żeby ta transmisja była obsługiwana możliwie szybko.
Przeszukałem już chyba cały internet i nie mogę zrozumieć obsługi portu. U mnie, w momencie kiedy czekam na przychodzącą wiadomość, nie mogę nic wysłać pomimo, że nadawanie wykonywane jest w innym wątku.
Próbowałem również ustawić timeout ale przestaje on działać po wysłaniu pierwszego pakietu.
Jak mogę to rozwiązać?
static DCB dcb;
static char lpBuffor_read[33], lpBuffor_write[33];
static DWORD RS_ile;
static DWORD dwEventMask;
static COMMTIMEOUTS cto;
bool TXFlag = 0;
char TXBuf[16] = "/SPEED50/\n";
HANDLE hComm;
static std::atomic<bool> KEEP_GOING; //zmienna do utrzymania wątku
void serial_init(HANDLE hComm)
{
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = CBR_115200;
dcb.fParity = TRUE;
dcb.Parity = EVENPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.ByteSize = 8;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDsrSensitivity = FALSE;
dcb.fAbortOnError = FALSE;
dcb.fOutX = TRUE;// FALSE;
dcb.fInX = TRUE;// FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.EofChar = '\n';
dcb.EvtChar = '\n';
if (!SetCommMask(hComm, EV_RXFLAG)) {
printf("SetCommMask Error");
}
SetCommState(hComm, &dcb);
GetCommTimeouts(hComm, &cto);
cto.ReadIntervalTimeout = 100;
cto.ReadTotalTimeoutMultiplier = 1;
cto.ReadTotalTimeoutConstant = 2000;
cto.WriteTotalTimeoutMultiplier = 2;
cto.WriteTotalTimeoutConstant = 2000;
SetCommTimeouts(hComm, &cto);
if (hComm == INVALID_HANDLE_VALUE)
printf("Error in opening serial port");
else
printf("opening serial port successful");
}
void wyslijCOM(HANDLE hcom, const char* dane) {
strcpy_s(lpBuffor_write, dane);
WriteFile(hcom, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0);
}
char *odbierzDane(HANDLE hcom){
DWORD dwCommEvent;
SetCommMask(hcom, EV_RXFLAG || EV_RXCHAR); //EV_RXCHAR
if (WaitCommEvent(hcom, &dwCommEvent, NULL)) {
std::fill(lpBuffor_read, lpBuffor_read+sizeof(lpBuffor_read), 0);
ReadFile(hcom, lpBuffor_read, 15, &RS_ile, 0);
std::cout << "-> " << lpBuffor_read;
}
return lpBuffor_read;
}
void RX_Thread()
{
char buf[50];
while (true) {
if (!KEEP_GOING.load())
break;
sprintf_s(buf, "%s \n", odbierzDane(hComm));
std::cout << "!\n";
if (TXFlag == 1) {
wyslijCOM(hComm, TXBuf);
}
}
}
void TX_Thread()
{
DWORD dwCommEvent;
while (true) {
if (!KEEP_GOING.load())
break;
std::cout << "...\n";
sleep_until(system_clock::now() + seconds(2));
wyslijCOM(hComm, TXBuf);
}
}
int main()
{
hComm = CreateFileA("\\\\.\\COM4", //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
1, // Non Overlapped I/O
NULL); // Null for Comm Devices
serial_init(hComm);
wyslijCOM(hComm, "?");
KEEP_GOING.store(true);
std::thread t1(&RX_Thread);
std::thread t2(&TX_Thread);
t1.join();
t2.join();
while(1) {
sleep_until(system_clock::now() + seconds(1));
}
CloseHandle(hComm);//Closing the Serial Port
return 0;
}
main
, skoro masz 2xjoin
? Dostęp docout
powinieneś synchronizować.wyslijCOM
używasz w dwóch wątkach, a w niej globalnej tablicylpBuffor_write
(po co?). Ta funkcja powinna być synchronizowana. IMO odczyt/wysyłka może być realizowana w jednym wątku.