Асинхронный последовательный ввод / вывод на Win32 - Как создать событие оповещения - PullRequest
0 голосов
/ 22 января 2020

Я попытался следовать статье Аллена Денвера , чтобы реализовать асинхронный последовательный порт ввода-вывода. В статье не упоминается, как или где можно вызывать функции в основной программе 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
}

Ответы [ 2 ]

1 голос
/ 23 января 2020
  • Открыть последовательный порт с FILE_FLAG_OVERLAPPED в CreateFile, если вы хотите писать и читать асинхронно.
  • Для параметра lpNumberOfBytesRead в ReadFile: Использовать NULL для этого параметра, если это асинхронная операция, чтобы избежать потенциально ошибочных результатов. Вы можете проверить длину чтения с помощью InternalHigh из OVERLAPPED .
  • ReadFile и WriteFile может привести к коду ошибки ERROR_IO_PENDING, это не отказ; он обозначает, что операция записи ожидает завершения асинхронно.

Ниже приведен пример, к которому можно обратиться:

int sendpckt(HANDLE hComm, unsigned length, unsigned char * pckt)
{
    BOOL result;
    DWORD dwCommEvent;
    OVERLAPPED oWrite = { 0 };
    DWORD errCode;

    result = SetCommMask(hComm, EV_TXEMPTY);
    if (!result) printf("Err: %d\n", GetLastError());

    result = WriteFile(hComm, pckt, length, NULL, &oWrite);
    if (result == FALSE)
    {
        errCode = GetLastError();

        if (errCode != ERROR_IO_PENDING)
            printf("Error! Setting CommMask\n");
    }

    OVERLAPPED commOverlapped = { 0 };

    commOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (commOverlapped.hEvent == NULL)
        return FALSE; // Error creating overlapped event handle.

    assert(commOverlapped.hEvent);

    result = WaitCommEvent(hComm, &dwCommEvent, &commOverlapped);
    if (!dwCommEvent)
        printf("Error Setting WaitCommEvent()%d\n", GetLastError());
    else
    {
        // If WaitCommEvent() == TRUE then Read the received data 
        if (dwCommEvent & EV_TXEMPTY)
        {
            printf("Send complete.\n");
        }

    }

    CloseHandle(oWrite.hEvent);
    CloseHandle(commOverlapped.hEvent);

    return 0;
};
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int recvpckt(HANDLE hComm, unsigned char * pckt)
{
    BOOL result;
    int len = 0;
    OVERLAPPED oRead = { 0 };
    DWORD errCode;
    DWORD dwCommEvent;

    result = SetCommMask(hComm, EV_RXCHAR);
    if (!result) printf("Err: %d\n", GetLastError());

    result = ReadFile(hComm, pckt, 2048, NULL, &oRead);
    if (result == FALSE)
    {
        errCode = GetLastError();

        if (errCode != ERROR_IO_PENDING)
            printf("nError! Setting CommMask\n");
    }

    OVERLAPPED commOverlapped = { 0 };

    commOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (commOverlapped.hEvent == NULL)
        return FALSE; // Error creating overlapped event handle.

    assert(commOverlapped.hEvent);

    result = WaitCommEvent(hComm, &dwCommEvent, &commOverlapped);
    if (!dwCommEvent)
        printf("Error Setting WaitCommEvent()%d\n", GetLastError());
    else
    {
        if (dwCommEvent & EV_TXEMPTY)
        {
            printf("Chars Recveived\n");
            len = oRead.InternalHigh;
        }

    }

    CloseHandle(oRead.hEvent);
    CloseHandle(commOverlapped.hEvent);

    return len;
};

void main(int argc, char *argv[]) {

    HANDLE hPort;
    int len;
    unsigned idx = 0;
    unsigned char TXBUF[] = "T", RXBUF[2048], port[64] = "COM8";

    SetConsoleTitle(port); // To specify serial port number on open 
    hPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 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");

    while (1) {

        sendpckt(hPort, 1, TXBUF);
        printf("Sending 0x%.2X\n", TXBUF[0]);

        len = recvpckt(hPort, RXBUF);
        if (len > 0)
        {
            printf("RCVD(%d): \n", len);
        }

        for (idx = 0; idx < len; idx++)
        {
            printf("%d:0x%.2X \n", idx + 1, RXBUF[idx]);
        }

        SleepEx(1000, TRUE); // How often to look for data in RX buffer
    }

    CloseHandle(hPort); // Close the serial port
}

Обновление:

Другой способ - использовать WaitForSingleObject без SetCommMask и WaitCommEvent. В качестве примера возьмем операцию чтения:

int recvpckt(HANDLE hComm, unsigned char * pckt)
{
    BOOL result;
    int len = 0;
    OVERLAPPED oRead = { 0 };
    DWORD errCode;
    DWORD dwCommEvent;

    oRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (oRead.hEvent == NULL)
        return FALSE; // Error creating overlapped event handle.

    assert(oRead.hEvent);

    result = ReadFile(hComm, pckt, 2048, NULL, &oRead);
    if (result == FALSE)
    {
        errCode = GetLastError();

        if (errCode != ERROR_IO_PENDING)
            printf("nError! Setting CommMask\n");
    }

    DWORD dwWaitResult = WaitForSingleObject(oRead.hEvent, INFINITE);
    switch (dwWaitResult)
    {
    case WAIT_OBJECT_0:
        printf("Received.\n");
        break;
    case WAIT_TIMEOUT:
        printf("Timeout.\n");
        break;
    case WAIT_FAILED:
        printf("Failed.\n");
        break;
    case WAIT_ABANDONED:
        printf("Abandoned.\n");
        return FALSE;
    }

    CloseHandle(oRead.hEvent);

    return len;
};
0 голосов
/ 20 февраля 2020

Размещение полного и функционального решения на примере Риты Хан:

/* ExAIO.c                                                         2020-02-20 */
#include <stdio.h>
#include <assert.h>
#include <windows.h>

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int ConfigureSerialPort(HANDLE hComm)
{
  int Status;
  DCB dcb = {0};
  COMMTIMEOUTS timeouts;

  dcb.DCBlength = sizeof(dcb);

  Status = GetCommTimeouts(hComm, & timeouts);
  GetCommTimeouts(hComm, & timeouts); 
  timeouts.ReadIntervalTimeout          = MAXDWORD;
  timeouts.ReadTotalTimeoutMultiplier   = 0;
  timeouts.ReadTotalTimeoutConstant     = 0;
  timeouts.WriteTotalTimeoutMultiplier  = 0;
  timeouts.WriteTotalTimeoutConstant    = 0; 
  if (!SetCommTimeouts(hComm, & timeouts)) {
    printf("Error setting timeouts on port!\n");
  }

  Status = GetCommState(hComm, & 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 error
  dcb.ByteSize          = 8;            // Number of bits/byte, 4-8 
  dcb.StopBits          = ONESTOPBIT;   // 0,1,2 = 1, 1.5, 2
  dcb.EvtChar           = 0x7E;         // Flag

  if (!SetCommState(hComm, & dcb)) {
    printf("Unable to configure serial port!\n");
  }
  return 0;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sendpckt(HANDLE hComm, unsigned length, unsigned char * pckt)
{
    BOOL result;
    DWORD dwWaitResult, errCode;
    OVERLAPPED oWrite = { 0 };

    oWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (oWrite.hEvent == NULL) return FALSE; // Error creating OL event handle.

    // Initialize the rest of the OVERLAPPED structure to zero.
    oWrite.Internal     = 0;
    oWrite.InternalHigh = 0;
    oWrite.Offset       = 0;
    oWrite.OffsetHigh   = 0;

    assert(oWrite.hEvent);

    result = WriteFile(hComm, pckt, length, NULL, &oWrite);
    if (result == FALSE) {
       errCode = GetLastError();
     if (errCode != ERROR_IO_PENDING) printf("Error! Setting CommMask\n");
    }

    dwWaitResult = WaitForSingleObject(oWrite.hEvent, INFINITE);

    switch(dwWaitResult) {
      case WAIT_OBJECT_0:
        printf("No Wait. Send complete.\n");
        break;
      case WAIT_TIMEOUT:
        printf("Wait Timeout.\n");
        break;
      case WAIT_FAILED:
        printf("Wait Failed.\n");
        break;
      case WAIT_ABANDONED:
        printf("Wait Abandoned.\n");
        break;
      default:
        break;
    }

    CloseHandle(oWrite.hEvent);
    return 0;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int recvpckt(HANDLE hComm, unsigned char * pckt)
{
    BOOL result;
    DWORD dwWaitResult, errCode, BytesRead = 0;
    OVERLAPPED oRead = { 0 };

    oRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (oRead.hEvent == NULL) return FALSE; // Error creating OL event handle.

    // Initialize the rest of the OVERLAPPED structure to zero.
    oRead.Internal     = 0;
    oRead.InternalHigh = 0;
    oRead.Offset       = 0;
    oRead.OffsetHigh   = 0;

    assert(oRead.hEvent);

    result = ReadFile(hComm, pckt, 2048, &BytesRead, &oRead);
    if (result == FALSE) {
        errCode = GetLastError();
      if (errCode != ERROR_IO_PENDING) printf("nError! Setting CommMask\n");
    }

    dwWaitResult = WaitForSingleObject(oRead.hEvent, INFINITE);

    switch (dwWaitResult) {
    case WAIT_OBJECT_0:
        printf("Received: ");
        if (BytesRead > 0) {
          printf("%d byte(s) -- ", BytesRead);
        }
        else printf("Nothing\n");
        break;
    case WAIT_TIMEOUT:
        printf("RX Timeout.\n");
        break;
    case WAIT_FAILED:
        printf("RX Wait Failed: \n");
        if (BytesRead > 0) {
          printf("%d byte(s) -- ", BytesRead);
        }
        else printf("Nothing\n");
        break;
    case WAIT_ABANDONED:
        printf("RX Abandoned.\n");
        return FALSE;
    default:
        break;
    }

    CloseHandle(oRead.hEvent);
    return BytesRead;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int args(int argc, char * argv[], char * port) 
{
  static int i;
  i = atoi(argv[1]);
  sprintf(port, "\\\\.\\COM%d", i);
  return i;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *TimeNow(char * TimeString)
{
  SYSTEMTIME st;
  GetSystemTime(&st);
  sprintf(TimeString, "%.2d:%.2d:%.2d.%.3d",
    st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
  return TimeString;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main(int argc, char *argv[]) 
{
    HANDLE hPort;
    int len;
    unsigned idx=0, portNum;
    unsigned char TXBUF[2048], RXBUF[2048], port[64], timeString[14], SendMe=0;

    if (argc > 1) portNum = args(argc, argv, port);
    else 
    {
      printf("Please identify the serial port number to open.\n");
      exit(0);
    }
    SetConsoleTitle(port); // To specify serial port number on open 

    hPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 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 %d Open at %s\n", portNum, TimeNow(timeString));
    }

    while (1) {
        TXBUF[0] = (SendMe++)%256;
        printf("Sending 0x%.2X at %s ", TXBUF[0], TimeNow(timeString));
        sendpckt(hPort, 1, TXBUF);

        len = recvpckt(hPort, RXBUF);
        if (len > 0) {
           printf("%s RCVD[%d byte(s)]: ", TimeNow(timeString), len);
         for (idx = 0; idx < len; idx++)
         {
            printf("%d:0x%.2X ", idx+1, RXBUF[idx]);
         }
          printf("\n");
        }

        SleepEx(1000, TRUE); // How often to send data out TX buffer
    }
    printf("Error: %d", GetLastError());
    CloseHandle(hPort); // Close the serial port
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...