Jayden
Jayden

Reputation: 1038

Serial port ReadFile reads 0 bytes and returns true

I'm trying to read in data from a serial port in Windows 7 using the Windows API. When I try to read in data, the WaitCommEvent() fires just fine and the ReadFile() call returns 1 as the status, but no data is read in. In the the ReadFile documentation it says that:

When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero.

However, I'm sure there are no EOT characters in the data being sent over the serial port.

I currently have two USB cables plugged into my computer and connected to each other. I know that they can send and receive data as I have tested them with Putty.

Why won't ReadFile() read in any data?

My code is below.

Header:

typedef struct uart_handle
{
   uint8_t port_num;
   char port_name[10];
   uint32_t baud_rate;
   uint8_t byte_size;
   uint8_t stop;
   uint8_t parity;
   int32_t error;
   HANDLE handle;
} uart_handle;

Main file:

uart_handle* serial_comm_init(uint8_t port_num, uint32_t baud_rate, uint8_t byte_size, uint8_t stop, uint8_t parity)
{
   uart_handle*  uart;
   DCB           uart_params = { 0 };
   COMMTIMEOUTS  timeouts    = { 0 };
   int           status;

   uart         = (uart_handle*) malloc(1 * sizeof(uart_handle));
   status       = 0;

   // Set port name
   if (port_num > 9)
   {
      sprintf(uart->port_name, "\\\\.\\COM%d", port_num);
   }
   else
   {
      sprintf(uart->port_name, "COM%d", port_num);
   }

   // Set baud rate
   uart->baud_rate = baud_rate;

   // Set byte size
   uart->byte_size = byte_size;

   // Set stop bit
   uart->stop = stop;

   // Set parity
   uart->parity = parity;

   // Set up comm state
   uart_params.DCBlength = sizeof(uart_params);
   status = GetCommState(uart->handle, &uart_params);
   uart_params.BaudRate = uart->baud_rate;
   uart_params.ByteSize = uart->byte_size;
   uart_params.StopBits = uart->stop;
   uart_params.Parity   = uart->parity;
   SetCommState(uart->handle, &uart_params);

   // Setup actual file handle
   uart->handle = CreateFile(uart->port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
   if (uart->handle == INVALID_HANDLE_VALUE) {
      printf("Error opening serial port %s.\n", uart->port_name);
      free(uart);
      return NULL;
   }
   else {
      printf("Serial port %s opened successfully.\n", uart->port_name);
   }

   // Set timeouts
   status = GetCommTimeouts(uart->handle, &timeouts);
   timeouts.ReadIntervalTimeout         = 50;
   timeouts.ReadTotalTimeoutConstant    = 50;
   timeouts.ReadTotalTimeoutMultiplier  = 10;
   timeouts.WriteTotalTimeoutConstant   = 50;
   timeouts.WriteTotalTimeoutMultiplier = 10;
   status = SetCommTimeouts(uart->handle, &timeouts);
   if (status == 0) {
      printf("Error setting comm timeouts: %d", GetLastError());
   }

   return uart;
}

int32_t serial_comm_read(void* handle, uint8_t* msg, uint32_t msg_size, uint32_t timeout_ms, uint32_t flag)
{
   uart_handle*  uart;
   uint32_t      num_bytes_read;
   uint32_t      event_mask;
   int32_t       status;

   uart            = (uart_handle*) handle;
   num_bytes_read  = 0;
   event_mask      = 0;
   status          = 0;

   memset(msg, 0, msg_size);

   // Register Event
   status = SetCommMask(uart->handle, EV_RXCHAR);

   // Wait for event
   status = WaitCommEvent(uart->handle, &event_mask, NULL);

   printf("Recieved characters.\n");

   do {
      status = ReadFile(uart->handle, msg, msg_size, &num_bytes_read, NULL);
      printf("Status: %d\n", status);
      printf("Num bytes read: %d\n", num_bytes_read);
      printf("Message: %s\n", msg);

   } while (num_bytes_read > 0);

   printf("Read finished.\n");

   return 0;
}

Output:

Serial port COM9 opened successfully.
Recieved characters.
Status: 1
Num bytes read: 0
Message:
Read finished.

Upvotes: 3

Views: 2676

Answers (1)

alk
alk

Reputation: 70931

The code shown calls GetCommState() on an uninitialised handle:

status = GetCommState(uart->handle, &uart_params); 

provoking UB doing so. Its returned status is not tested.

Due to this uart_params probably contains BS no useful data.


Do yourself a favour: Always and ever check the return value on all relevant function calls (and let the code act accordingly)! Consider as "relevant" all those functions returning or changing data used afterwards.

Upvotes: 3

Related Questions