2

I have a single-board computer connected to another device via RS485. The computer should send a request to the device and receive a response (using a device dependent protocol). I can send messages without any problems and the device receives them (e.g. I can change parameters of the device). The problem occurs when I want to read parameters from the device. In this case I'm getting wrong responses (wrong characters, shifted messaged, incomplete messages, ...).

Here is my initalization code:

Bool
SerialCommunicator::initPort()
{
if (isInitialized_)
    return true;

if (!paramSet())
    return false;

bzero( &termIO_, sizeof ( struct termios ));
termIO_.c_iflag    |= IGNBRK | IGNPAR;
termIO_.c_cflag    |= CREAD | CLOCAL;
termIO_.c_cflag    |= CS8;
termIO_.c_oflag    |= 0;
termIO_.c_lflag    |= 0;

termIO_.c_cc[VTIME]    = 0;
termIO_.c_cc[VMIN]     = 13; // number of frame characters

String path("/dev/tty" + portSuffix_);
serHandle_ = open(path.c_str(), O_RDWR /*| O_NOCTTY*/);
if (serHandle_ > -1)
{
    isInitialized_ = (cfsetispeed(&termIO_, B19200) == 0)
                        && (cfsetospeed(&termIO_, B19200) == 0);
    isInitialized_ = isInitialized_ && (tcsetattr(serHandle_, TCSANOW, &termIO_) == 0);


    return isInitialized_;
}
else
    return false;
}

Send code:

Bool
SerialCommunicator::sendFrame(UByte *_frame, UInt _size)
{
FD_ZERO( &wrFd_ );
FD_ZERO( &rdFd_ );
FD_SET( serHandle_, &wrFd_);
FD_SET( serHandle_, &rdFd_);

Int retVal;
aux_gpio_write_settings();
retVal = select(serHandle_+1, &rdFd_, &wrFd_, NULL, &timeval_);
if (retVal > 0)
{
  if( FD_ISSET(serHandle_, &wrFd_) )
  {

    UInt    bytesToSend     = _size;
    UInt    bytesSent       = 0;
    UInt    bytesSentTotal  = 0;
    while ( bytesToSend > 0 )
    {
        bytesSent   = write( serHandle_, _frame + bytesSentTotal, bytesToSend );
        if (bytesSent > 0)
        {
            bytesToSend     -= bytesSent;
            bytesSentTotal  += bytesSent;
        }

    }
    aux_gpio_read_settings();
    tcflush(serHandle_, TCIOFLUSH);
    return true;
  }
}
usleep(SLEEPTIME);
return false;
}

Receive code:

Bool
SerialCommunicator::receiveFrame(UByte *_frame, UInt _size)
{
FD_ZERO( &rdFd_ );
FD_ZERO( &wrFd_ );
FD_SET( serHandle_, &rdFd_ );
FD_SET( serHandle_, &wrFd_ );

Bool retVal;
aux_gpio_read_settings();
retVal = select(serHandle_+1, &rdFd_, &wrFd_, NULL, &timeval_);
if (retVal > 0)
{
  if( FD_ISSET(serHandle_, &rdFd_) )
  {

    UInt    bytesToReceive      = _size;
    UInt    bytesReceived       = 0;
    UInt    bytesReceivedTotal  = 0;
    while ( bytesToReceive > 0 )
    {
        bytesReceived   = read( serHandle_, _frame + bytesReceivedTotal, bytesToReceive );
        if (bytesReceived > 0)
        {
            bytesToReceive      -= bytesReceived;
            bytesReceivedTotal  += bytesReceived;
        }
    }
    return true;
  }
}
return false;
}

The functions aux_gpio_write_settings() and aux_gpio_read_settings() are used to set the UART(via GPIOs) s.t. the RS485 can send or receive data.

If I use the code on my linux desktop computer it works fine since the USB/RS485 adapter switches automatically between sending and receiving mode. On my single-board computer I have to do it manually. Because of that, I think that setting the GPIOs and receiving the response cause a timing problem. How can I handle this problem?

DBPST
  • 23
  • 1
  • 4

1 Answers1

1

It might be with a bug you have in the receiveFrame read-loop. When you receive less than the wanted amount of data, you decrease the amount of data to receive the next time in the loop, but then when using the same pointer as the previous loop you overwrite the first data you read. You need to increase the pointer as well as decrease the size:

bytesReceived   = read( serHandle_, _frame, bytesToReceive );
if (bytesReceived > 0)
{
    bytesToReceive -= bytesReceived;
    _frame += bytesReceived;
}

You have a similar problem when sending data, you send the same data over and over again, just less of it each time.

I also recommend you to actually check for errors (when bytesReceived < 0), and handle those cases appropriately.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thank you for the fast answer. I'll check it as soon as possible. – DBPST Aug 06 '13 at 14:04
  • Now the responses are much better. But still, sometimes I don't get any response, sometimes a shifted one (usually 1 or 2 bytes shifted) and sometimes the readiny blocks (thus there is no input). I think the later can be solved with a timeout. – DBPST Aug 06 '13 at 14:43
  • Sometimes also the first 1-3 bytes of the response are false. – DBPST Aug 06 '13 at 14:49