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