UART serial port timeout on /dev/ttyTHS1

Hello!

I am running the serial communication lib (under isaac/sdk/packages/coms/gems/serial.cpp) on a Jetson AGX Xavier. I am opening a port on /dev/ttyTHS1 for UART communication. It is my understanding from this chart that the /dev/ttyTHS1 port is located on GPIO pins 8 and 10 on the 40 pin header on the AGX. However, when shorting the pins (having the port TX write to it’s own RX) with the following piece of code I get a timeout error on the port in case eg: 2021-06-16 17:28:22.286 WARN packages/coms/gems/serial.cpp@109: Timeout on port /dev/ttyTHS1

#include "packages/coms/gems/serial.hpp"

void isaac::UART_test(){
    int baudrate = 115200;
    std::string port_name = "/dev/ttyTHS1";
    isaac::Serial serial = isaac::Serial(port_name, baudrate);
    serial.setDTR(true);
    // create a message and write to port
    unsigned char msg[5] = {0xFF, 0xAA, 0x63, 0x5c, 0x30};
    unsigned char buffer[128];
    serial.writeChars(msg, 5);
    // port is wired in loopback TX->RX (pin 8 -> pin 10)so expecting to read 
    // back the message sent to buffer
    serial.readChars(buffer, 128 * sizeof(char)); // this yields timeout error 
                                                  //on port /dev/ttyTHS1

}

This confuses me somewhat I do not understand why the data is not read back on the RX. Anyone who knows why?

For convenience, this is the code in serial.cpp :

Copyright (c) 2018, 2019, NVIDIA CORPORATION. All rights reserved.

NVIDIA CORPORATION and its licensors retain all intellectual property
and proprietary rights in and to this software, related documentation
and any modifications thereto. Any use, reproduction, disclosure or
distribution of this software and related documentation without an express
license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
#include "serial.hpp"

#include <errno.h>  // Error number definitions
#include <fcntl.h>  // File control definitions
#include <stdio.h>  // standard input / output functions
#include <stdlib.h>
#include <string.h>  // memset
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <termios.h>  // POSIX terminal control definitions
#include <unistd.h>   // UNIX standard function definitions

#include <string>

#include "engine/core/logger.hpp"
#include "packages/coms/gems/serial_baudrate.hpp"

namespace isaac {

Serial::Serial(const std::string& dev_port, int baudrate) : port_name_(dev_port) {
  fd_ = open(port_name_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK | O_APPEND | O_NDELAY);
  if (fd_ == -1) {
    LOG_ERROR("Cannot open %s: %s [errno %d]", port_name_.c_str(), strerror(errno), errno);
  }
  LOG_INFO("opening fd");

  // Set baud rate
  // Must be set before any termios operations
  isaac::SetSerialBaudrate(fd_, baudrate);

  // set no delay
  if (fcntl(fd_, F_SETFL, FNDELAY)) {
    LOG_ERROR("Error configuring %s: %s [errno %d]", port_name_.c_str(), strerror(errno), errno);
  }

  // begin termios operations
  // see http://man7.org/linux/man-pages/man3/tcflow.3.html

  struct termios tty;
  memset(&tty, 0, sizeof(tty));

  if (tcgetattr(fd_, &tty) < 0) {
    LOG_ERROR("Error configuring %s: %s [errno %d]", port_name_.c_str(), strerror(errno), errno);
  }

  // Make raw
  cfmakeraw(&tty);

  // control flags
  tty.c_cflag &= ~CSTOPB;         // Single stop bit
  tty.c_cflag &= ~CRTSCTS;        // No hardware flow control
  tty.c_cflag |= CREAD | CLOCAL;  // Enable receiver, ignore modem control lines

  // input flags
  tty.c_iflag |= IGNPAR;  // ignore framing and parity errors

  // special terminal characters
  tty.c_cc[VMIN] = 0;   // minimum number of characters for non-conical read
  tty.c_cc[VTIME] = 0;  // timeout (in deciseconds)

  // Flush Port, then applies attributes
  if (tcflush(fd_, TCIFLUSH) < 0) {
    LOG_ERROR("Error configuring %s: %s [errno %d]", port_name_.c_str(), strerror(errno), errno);
  }

  if (tcsetattr(fd_, TCSANOW, &tty) < 0) {
    LOG_ERROR("Error configuring %s: %s [errno %d]", port_name_.c_str(), strerror(errno), errno);
  }
}

void Serial::writeChars(const unsigned char* c, size_t size) {
  if (write(fd_, c, size) != static_cast<int>(size)) {
    LOG_ERROR("Enable to write to serial port %s", port_name_.c_str());
  }
}

int Serial::readChars(unsigned char* buffer, size_t buffer_size) {
  LOG_INFO("readChars");
  if (buffer_size == 0) {
    LOG_WARNING("You are reading 0 bytes, are you sure this is the deisred behavior?");
  }
  struct pollfd poll_fd[1];
  poll_fd[0].fd = fd_;
  poll_fd[0].events = POLLIN;
  int poll_status = poll(poll_fd, 1, 1000);
  LOG_INFO("poll_status = %i", poll_status);
  if (poll_status < 0) {
    LOG_ERROR("Error %d while polling on serial port %s", poll_status, port_name_.c_str());
    return -1;
  } else if (poll_status >= 0) {
    LOG_INFO("executing poll  ");
    if ((poll_fd[0].revents & POLLIN) || true) {
      ssize_t rc = read(fd_, buffer, buffer_size);
      LOG_INFO("executing read, rc = %i", (int)rc);
      if (rc > 0) {
        return rc;
      }
    }
  }
  LOG_WARNING("Timeout on port %s", port_name_.c_str());
  return 0;
}

void Serial::setDTR(bool level) {
  int command = TIOCM_DTR;
  if (level) {
    if (-1 == ioctl(fd_, TIOCMBIS, &command)) {
      return;
    }
  } else {
    if (-1 == ioctl(fd_, TIOCMBIC, &command)) {
      return;
    }
  }
}

Serial::~Serial() {
  close(fd_);
}

}  // namespace isaac

hello arvid1,

could you please have a try to have getty service running on background,
for example,
$ sudo /sbin/getty -a ubuntu -L 115200 ttyTHS<port> &

hello JerryChang, thank you for replying.

I have tried running the getty service you suggested, it still gives the same timeout error. I also tried with altering the port with sudo chmod 666 /dev/ttyTHS1

There was a new release where serial.cpp was updated with a readLine() function:

int Serial::readLine(unsigned char* buffer, size_t max_buffer_size, unsigned char delimiter) {
  ASSERT(max_buffer_size > 0, "Max buffer size should be a positive value");
  size_t index = 0;
  buffer[0] = '\0';

  struct pollfd poll_fd[1];
  poll_fd[0].fd = fd_;
  poll_fd[0].events = POLLIN;

  int poll_status = poll(poll_fd, 1, timeout_ms_);
  if (poll_status < 0) {
    LOG_ERROR("Error %d while polling on serial port %s", poll_status, port_name_.c_str());
    return -1;
  }

  while (index < max_buffer_size) {
    
    if (poll_fd[0].revents & POLLIN) {
      ssize_t rc = read(fd_, (buffer+index), 1);
      if (rc == 0) {
        LOG_WARNING("Error while reading from %s", port_name_.c_str());
        return 0;
      }
      if (buffer[index] == delimiter) {
        buffer[index] = '\0';
        return (index+1);
      }
      ++index;
    } else {
      LOG_WARNING("Can not read from %s", port_name_.c_str());
      return -1;
    }
  }
  LOG_WARNING("Serial recieved line longer than allowable");
  return max_buffer_size;
}

this statement if (poll_fd[0].revents & POLLIN) {returns false and the function returns -1 and prints cannot read from /dev/ttyTHS1
There is no problem with opening the port and writing seems to work OK as far as I can tell.

If it is of any interest, poll_fd[0] is 9 and poll_fd[0].revents is 10

Cheers!

it seems you only shorting just TX/RX pins, could you please short RTS/CTS pins as well and run the experiment again. (i.e. PIN-11 <-> PIN-36).

I have shorted RTS to CTS and no luck. Still the same timeout error. Any more suggestions?