-1

I am testing my serial port library's write function.At first, I arranged serial port file descriptor as nonblocking file descriptor. Then I call tcdrain(fd) at the end of the my customized write function. But If I don't wait with sleep() after this customized write function and return from application immediately, bytes are not written over serial port actually.

So, I have two question.

  1. Does tcdrain() not guarantee that bytes are send ?
  2. How can I implement customized write function without calling sleep() function.

I try same function with blocking file descriptor. But nothing has changed.

First I initialize serial port with following code:

struct termios stermios;
tcgetattr ( fd, &stermios );
cfsetispeed ( &stermios, handle->baudrate );
cfsetospeed ( &stermios, handle->baudrate );

stermios.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS );
stermios.c_cflag |= ( CLOCAL | CREAD );
stermios.c_cflag &= ~CSIZE;
stermios.c_cflag |= CS8;

stermios.c_iflag &= (IXON | IXOFF );
stermios.c_oflag &= ~OPOST;
stermios.c_lflag &= ~(ICANON | ECHO | ECHOE );

tcflush ( fd, TCIOFLUSH );
tcsetattr ( fd, TCSANOW, termios_p );

And I here is my customized write function:


static int32_t surely_tcdrain ( SerialPortHandle_t const * handle_p )
{
    int32_t retval = -1;
    int32_t try_cnt = 0;

    while ( ( ++try_cnt < MAX_TCDRAIN_TRY_CNT ) &&\
            ( -1 == (retval = tcdrain ( fd ) ) ) )
    {
        if ( EINTR == errno )
        {
            usleep ( TCDRAIN_DELAY );
        }
        else
        {
            fprintf (stderr, "tcdrain() FAILED, %d, %s\n",\
                    errno, strerror ( errno ) );
            try_cnt = MAX_TCDRAIN_TRY_CNT; // Dont try again, break the loop. //
        }
    }

    return retval;
}
int32_t write_to_serial_port( int32_t fd, void * buff, size_t size )
{
  uint8_t try_cnt = 0;
  size_t total_write_size = 0;

  while ( ( total_write_size < size ) && ( ++try_cnt < 10 ) )
  {
    ssize_t w_size = -1;
    w_size = write (fd, ( ( uint8_t * ) buff + total_write_size ),\
        ( size - total_write_size ) );

    if ( w_size == -1 )
    {
      if ( ( errno != EINTR ) && ( errno != EAGAIN ) &&\
             ( errno != EWOULDBLOCK ) )
      {
         try_cnt = MAX_WRITE_TRY_CNT;
      }
      else
      {
        usleep ( WRITE_DELAY );
      }
    }
    else
    {
      total_write_size += ( ( size_t ) w_size );
    }
  }

    return ( ( surely_tcdrain ( fd ) == 0 ) &&\
            ( ( total_write_size == size ) ) ) ? 0 : -1;
}

And lastly, I closed my serial port file descriptor with following function.

static void deinit_fd ( int32_t fd )
{
    if ( FD_INVALID != fd )
    {
        if ( 1 == isatty ( fd ) )
        {
            tcdrain ( fd ); // Wait for write all output process. //
        }
        else
        {
            // fd not referring terminal. So no need to call tcdrain(). //
        }

        close ( fd );
    }
    else
    {
        // fd is invalid. //
    }
}

I am calling this write function in main and after that I am closing my file descriptor and return from application immediately.

I expect that, all bytes must written via serial port with my write function. But my function not working like that.

user3104363
  • 182
  • 1
  • 14
  • (1) You have not posted a minimal, reproducible example. (2) Your termios initialization is not POSIX compliant. See [Setting Terminal Modes Properly](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC237). (3) The only return code you seem to check is from **write()**. If you're having issues with the **tcdrain()** syscall, then why aren't you checking its return code? (4) How have you determined that *"bytes are not written over serial port actually"*? – sawdust Jun 21 '19 at 22:47
  • I changed my termios initialization and then I wrote code surely_tcdrain(), I added this code to my question and in this function, I checked the return value of tcdrain. With this new function, problem is not solved. tcdrain returns with success but nothing changed, still sleep is required. And lastly, I try to communicate with another microcontroller, so I check bytes written or not by using its debug property. Do you have any suggestion ? Thanks – user3104363 Jun 24 '19 at 05:55
  • (1) You still have not posted a minimal, reproducible example. (2) *"I check bytes written or not by using its debug property."* -- That doesn't really explain anything. This is beginning to sound like a **write()** problem, where you incorrectly assume "everything" has been transmitted, but it hasn't. Debug how many bytes are actually written. Have you bothered to check the return value of **write_to_serial_port()**? – sawdust Jun 24 '19 at 07:56

1 Answers1

0

It sounds like you are not closing the file before your process exits. I know you said that you do, but do not show that code. Is it possible that there is a bug in that part of your code?

Joshua DeWeese
  • 330
  • 1
  • 9
  • I added my close function in question. But also I have checked my code with valgrind, and there is no leak or no open file descriptor at the end of the application. – user3104363 Jun 21 '19 at 20:00