Я попытался следовать статье Аллена Денвера , чтобы реализовать асинхронный последовательный порт ввода-вывода. В статье не упоминается, как или где можно вызывать функции в основной программе l oop полезным способом. После помещения их в al oop, который возвращается каждую секунду, стало ясно, что не нужно периодически вызывать ReadFile (). Я попытался поместить WaitCommEvent () в l oop, чтобы чтение происходило только при поступлении символов в порт. Это вызвало каскад ошибок. При попытке упростить код до того, что я мог бы опубликовать здесь, даже мои попытки открыть файл в режиме OVERLAPPED не увенчались успехом, поэтому я не могу опубликовать полезный пример. Тем не менее, я опубликую что-то похожее с базовым понятием c, что мне все равно, должны ли операции чтения и записи быть синхронными, если я могу просто инициировать их с помощью асинхронного события, такого как символы, появляющиеся на последовательном порту. Асинхронные функции из статьи Аллена Денвера довольно сложны, и мне не понятно из его примеров, как вызвать чтение символов, поступающих в порт.
В следующем коде пять строк, закомментированных в Тело того времени (1) l oop, где я пытался дождаться прибытия персонажей. Ошибки WaitCommEvent (), по-видимому, ссылаются на ожидающие операции ввода-вывода, даже если порт был открыт в режиме перекрытия (в исходном коде), а функции отправки и получения имели свои собственные структуры OVERLAPPED. Как правильно решить эту проблему?
/* WINSIO.c 2020-01-22 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int ConfigureSerialPort(HANDLE hPort)
{
int Status;
DCB dcb = {0};
COMMTIMEOUTS timeouts;
dcb.DCBlength = sizeof(dcb);
Status = GetCommTimeouts(hPort, &timeouts);
GetCommTimeouts(hPort, &timeouts);
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 50;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hPort, &timeouts)) {
printf("Error setting timeouts on port!\n");
}
Status = GetCommState(hPort, &dcb);
dcb.BaudRate = 19200;
dcb.Parity = NOPARITY;
dcb.fBinary = TRUE; // Binary mode; no EOF check
dcb.fParity = FALSE; // Enable parity checking
dcb.fOutxCtsFlow = FALSE; // No CTS output flow control
dcb.fOutxDsrFlow = FALSE; // No DSR output flow control
dcb.fDtrControl = DTR_CONTROL_DISABLE; // DTR flow control type
dcb.fDsrSensitivity = FALSE; // DSR sensitivity
dcb.fTXContinueOnXoff = FALSE; // XOFF continues Tx
dcb.fOutX = FALSE; // No XON/XOFF out flow control
dcb.fInX = FALSE; // No XON/XOFF in flow control
dcb.fErrorChar = FALSE; // Disable error replacement
dcb.fNull = FALSE; // Disable null stripping
dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS flow control
dcb.fAbortOnError = FALSE; // Do not abort reads/writes on err
dcb.ByteSize = 8; // Number of bits/byte, 4-8
dcb.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
dcb.EvtChar = 0x84; // 'T'
if (!SetCommState (hPort, &dcb)) {
printf("Unable to configure serial port!\n");
}
return 0;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sendpckt(HANDLE hComm, unsigned length, unsigned char * pckt)
{
unsigned long NbytesWritten = 0;
int result;
DWORD dwCommEvent;
OVERLAPPED oWrite;
oWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (oWrite.hEvent == NULL)
return FALSE; // Error creating overlapped event handle.
result = WriteFile(hComm, pckt, length, &NbytesWritten, NULL);
//result = WriteFile(hComm, pckt, length, &NbytesWritten, &oWrite);
if (!result) printf("Err: %d\n", GetLastError());
WaitCommEvent(hComm, &dwCommEvent, &oWrite);
// printf("Wrote? %d:%d\n", result, NbytesWritten);
CloseHandle(oWrite.hEvent);
return 0;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int recvpckt(HANDLE hComm, unsigned char * pckt)
{
int Status, idx = 0, len = 0;
unsigned long Nbytes;
unsigned char chRead;
OVERLAPPED oRead;
do {
//Status = ReadFile(hComm, &chRead, 1, &Nbytes, &oRead);
Status = ReadFile(hComm, &chRead, 1, &Nbytes, NULL);
if (Status) {
pckt[idx++] = chRead;
if(Nbytes > 0) len = idx;
}
}
while(Nbytes > 0);
return len;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int args(int argc, char * argv[], char * port)
{
static int i;
i = atoi(argv[1]);
sprintf(port, "\\\\.\\COM%d", i);
return i;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main(int argc, char *argv[]) {
HANDLE hPort;
int result, len, Status;
DWORD dwCommEvent;
OVERLAPPED o;
unsigned idx = 0;
unsigned char TXBUF[] = "T", RXBUF[2048], port[64];
if (argc > 1) result = args(argc, argv, port);
SetConsoleTitle(port); // To specify serial port number on open
hPort = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
//OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
OPEN_EXISTING, 0, NULL);
ConfigureSerialPort(hPort);
if (hPort == INVALID_HANDLE_VALUE) {
printf("Error in openning serial port\n");
exit(0); // No point in going on if serial port didn't open
}
else
printf("Serial Port Open\n");
Status = SetCommMask(hPort, EV_RXCHAR);
if (Status == FALSE) printf("Error! Setting CommMask\n");
o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (o.hEvent == NULL) printf("Error creating overlapped event; abort.\n");
while (1) {
sendpckt(hPort, 1, TXBUF);
printf("Sending 0x%.2X\n", TXBUF[0]);
// Status = WaitCommEvent(hPort, &dwCommEvent, &o); // Wait for chars
// if (Status == FALSE)
// printf("Error Setting WaitCommEvent()%d\n", GetLastError());
// else { // If WaitCommEvent() == TRUE then Read the received data
// printf("Chars Recveived\n");
len = recvpckt(hPort, RXBUF);
if (len > 0)
{
printf("RCVD(%d): ", len);
}
for (idx=0; idx<len; idx++)
{
printf("%d:0x%.2X ", idx+1, RXBUF[idx]);
}
// }
SleepEx(1000, TRUE); // How often to look for data in RX buffer
}
CloseHandle(o.hEvent); // Close the Event Handle
CloseHandle(hPort); // Close the serial port
}
Публикация дополнительного кода после высоко оцененной обратной связи от Риты Хан. Что было ясно из других постов, так это то, что мой Синхронный пример не понял сути. Поэтому я прилагаю асинхронную версию, которая в основном работает, но оставляет желать лучшего. Если бы это можно было упростить до продолжительности примера Риты Хан, это было бы фантастически c. Этот пример выполняет функцию, что означает, что он отправляет и получает. Проблема заключается в том, что, как было изначально заявлено, требуется периодически опрашивать порты на наличие символов, и это очень большое сопротивление. Следующий код представляет собой почти идентичное воссоздание кода Аллена Денвера, и он не предоставляет иск, основанный на событиях, который я ищу, но он отправляет и получает символы. В настоящее время я использую его через нуль-модемный кабель с двумя последовательными портами, поэтому поведение довольно легко наблюдать. Зависимость от опроса последовательного порта становится ясной, если изменить значение тайм-аута в операторе SleepEX (). Как бы ни была полезна обратная связь Риты Хан, код не демонстрирует поведение, которое я ищу. Если кто-то может взять следующий пример и заставить его реагировать на символы, поступающие на последовательный порт, а не в ожидании опроса, это то, что я ищу. Нужно ли использовать ReadFileEX ()? Есть ли какой-то другой способ зарегистрировать событие, которое нужно смешать здесь? В этой статье Джозеф М. Новичок отказывается от всякого использования последовательных событий, говоря, что они существуют только для 16-битной windows совместимости, а затем приводит к существенно более запутанному примеру программирования последовательного порта, чем Аллен Денвер сделал. Неужели это должно быть так сложно?
/* WINAIO.c 2020-01-22 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int ConfigureSerialPort(HANDLE hPort) {
int Status;
DCB dcb = {0};
COMMTIMEOUTS timeouts;
dcb.DCBlength = sizeof(dcb);
Status = GetCommTimeouts(hPort, & timeouts);
GetCommTimeouts(hPort, & timeouts);
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 50;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(hPort, & timeouts)) {
printf("Error setting timeouts on port!\n");
}
Status = GetCommState(hPort, & dcb);
dcb.BaudRate = 19200;
dcb.Parity = NOPARITY;
dcb.fBinary = TRUE; // Binary mode; no EOF check
dcb.fParity = FALSE; // Enable parity checking
dcb.fOutxCtsFlow = FALSE; // No CTS output flow control
dcb.fOutxDsrFlow = FALSE; // No DSR output flow control
dcb.fDtrControl = DTR_CONTROL_DISABLE; // DTR flow control type
dcb.fDsrSensitivity = FALSE; // DSR sensitivity
dcb.fTXContinueOnXoff = FALSE; // XOFF continues Tx
dcb.fOutX = FALSE; // No XON/XOFF out flow control
dcb.fInX = FALSE; // No XON/XOFF in flow control
dcb.fErrorChar = FALSE; // Disable error replacement
dcb.fNull = FALSE; // Disable null stripping
dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS flow control
dcb.fAbortOnError = FALSE; // Do not abort reads/writes on err
dcb.ByteSize = 8; // Number of bits/byte, 4-8
dcb.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
dcb.EvtChar = 0x84; // 'T'
if (!SetCommState(hPort, & dcb)) {
printf("Unable to configure serial port!\n");
}
return 0;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sendpckt(HANDLE hComm, unsigned length, unsigned char *pckt) {
unsigned long NbytesWritten = 0;
OVERLAPPED ovl = {0};
BOOL fRes;
ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ovl.hEvent == NULL)
return FALSE; // Error creating overlapped event handle.
//Issue Write.
if (!WriteFile(hComm, pckt, length, & NbytesWritten, & ovl)) {
if (GetLastError() != ERROR_IO_PENDING) {
fRes = FALSE; // WriteFile failed, but isn't delayed. Report error...
} else {
//Write is pending.
if (!GetOverlappedResult(hComm, & ovl, & NbytesWritten, TRUE))
fRes = FALSE;
else
fRes = TRUE;
}
} else // Write operation completed successfully.
fRes = TRUE;
// printf(" 0X%.2X ", chWrite);
CloseHandle(ovl.hEvent);
return fRes;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int recvpckt(HANDLE hComm, unsigned char *pckt) {
# define READ_TIMEOUT 500 // milliseconds
int len = 0;
unsigned long Nbytes;
unsigned char chRead, BUF[2048];
BOOL fWaitingOnRead = FALSE;
OVERLAPPED ovl = {0};
DWORD dwRes;
/*
Status = SetCommMask(hComm, EV_RXFLAG);
if (Status == FALSE) printf("Error! Setting CommMask\n");
// else printf("Setting CommMask Succesful\n");
// */
ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ovl.hEvent == NULL) printf("Error creating overlapped event; abort.\n");
if (!fWaitingOnRead) {
// Issue read operation
if (!ReadFile(hComm, & BUF, 2048, & Nbytes, & ovl))
//if(!ReadFile(hComm, &chRead, 1, &Nbytes, &ovl))
{
if (GetLastError() != ERROR_IO_PENDING) // read not delayed?
// Error in communications; report it
printf("Error in Communications...\n");
else {
fWaitingOnRead = TRUE;
// printf("l:%d ", len); // shows loop alive
}
} else {
if (Nbytes > 0) {
// read completed immediately
memcpy(pckt, BUF, Nbytes);
len = Nbytes;
printf("Immediate Read Completion\n");
//HandleASuccessfulRead(lpbuf, dwRead);
}
}
}
if (fWaitingOnRead) {
dwRes = WaitForSingleObject(ovl.hEvent, READ_TIMEOUT);
switch (dwRes) {
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, & ovl, & Nbytes, FALSE))
printf("Error in Communications Lower Portion\n");
// Error in communications; report it.
else {
if (Nbytes > 0) {
// Read completed successfully
// HandleASuccessfulRead(lpbuf, dwRead);
// Will run away and execute here every time
fWaitingOnRead = FALSE;
memcpy(pckt, BUF, Nbytes);
len = Nbytes;
printf("Read Completion After Wait\n");
}
}
case WAIT_TIMEOUT:
//printf("l:%d %d\n", len,rxstate);
// Operation isn't complete yet. fWaitingOnRead flag isn't changed
// since I'll loop back around, and I don't want to issue another read
// until the first one finishes.
// Good time to do some background work.
break;
default:
// Error in the WaitForSingleObject; abort.
// This indicates a problem with the OVERLAPPED structure's event handle
break;
}
}
CloseHandle(ovl.hEvent);
return Nbytes;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int args(int argc, char *argv[], char *port) {
static int i;
i = atoi(argv[1]);
sprintf(port, "\\\\.\\COM%d", i);
return i;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main(int argc, char *argv[]) {
HANDLE hPort;
int result, len, Status;
DWORD dwCommEvent;
OVERLAPPED o;
unsigned idx = 0;
unsigned char TXBUF[] = "T", RXBUF[2048], port[64];
if (argc > 1) result = args(argc, argv, port);
SetConsoleTitle(port); // To specify serial port number on open
hPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
//OPEN_EXISTING, 0, NULL);
ConfigureSerialPort(hPort);
if (hPort == INVALID_HANDLE_VALUE) {
printf("Error in openning serial port\n");
exit(0); // No point in going on if serial port didn't open
} else
printf("Serial Port Open\n");
Status = SetCommMask(hPort, EV_RXCHAR);
if (Status == FALSE) printf("Error! Setting CommMask\n");
o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (o.hEvent == NULL) printf("Error creating overlapped event; abort.\n");
while (1) { // This is the loop for getting work done.
sendpckt(hPort, 1, TXBUF);
printf("Sending 0x%.2X\n", TXBUF[0]);
// Status = WaitCommEvent(hPort, &dwCommEvent, &o); // Wait for chars
// if (Status == FALSE)
// printf("Error Setting WaitCommEvent()%d\n", GetLastError());
// else { // If WaitCommEvent() == TRUE then Read the received data
// printf("Chars Recveived\n");
len = recvpckt(hPort, RXBUF);
if (len > 0) {
printf("RCVD(%d): ", len);
}
for (idx = 0; idx < len; idx++) {
printf("%d:0x%.2X ", idx + 1, RXBUF[idx]);
}
// }
SleepEx(1000, TRUE); // How often to look for data in RX buffer
// And how often to send data to the other port
}
CloseHandle(o.hEvent); // Close the Event Handle
CloseHandle(hPort); // Close the serial port
}