Serial::Serial(const char * device_name, unsigned long baud_rate) { struct termios options; std::cout << ">> starting Serial::Serial(.)" << std::endl; fd = open(device_name, O_RDWR | O_NOCTTY | O_NDELAY); if(fd == -1) throw SerialException("Could not open serial device.\n", errno); std::cout << " -- serial device is open, fd: " << fd << std::endl; fcntl(fd, F_SETFL, 0); // blocking std::cout << " -- blocking" << std::endl; tcgetattr(fd, &options); // get the current options // TODO: restore on destruction of the object std::cout << " -- got the current options" << std::endl; tcgetattr(fd, &options); options.c_cflag=B57600; tcsetattr(fd, TCSANOW, &options); std::cout << " -- set baud rate uart0_filestream" << std::endl; #ifndef __APPLE__ if(cfsetispeed(&options, B57600) != 0) throw SerialException("Could not set baud rate for input", errno); std::cout << " -- set baud rate for input" << std::endl; if(cfsetospeed(&options, B57600) != 0) throw SerialException("Could not set baud rate for output", errno); std::cout << " -- set baud rate for output" << std::endl; #endif options.c_cflag |= (CS8 | CLOCAL | CREAD); options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 1; // tenth of seconds allowed between bytes of serial data // but since VMIN = 0 we will wait at most 1/10 s for data then return tcflush(fd, TCIOFLUSH); tcsetattr(fd, TCSANOW, &options); // set the options #ifdef __APPLE__ cfmakeraw(&options); // necessary for ioctl to function; must come after setattr const speed_t TGTBAUD = baud_rate; int ret = ioctl(fd, IOSSIOSPEED, &TGTBAUD); // sets also non-standard baud rates if (ret) throw SerialException("Could not set baud rate", errno); std::cout << " -- set baud rate for output" << std::endl; #endif }
size_t Serial::read(char* data, size_t length) { waitForData(); logger.debug(MODULE, "Reading data"); ssize_t br = ::read(fd, data, length); logger.debug(MODULE, "Read %u bytes", br); if (br == -1) { throw SerialException("Could not read data"); } return br; }
void Serial::waitToWrite() { fd_set writeset; int result; logger.debug(MODULE, "Waiting to write"); do { FD_ZERO(&writeset); FD_SET(fd, &writeset); timeval timeout = {0, 100}; result = select(fd + 1, nullptr, &writeset, nullptr, &timeout); } while (result == 0 && !abortFlag); if (abortFlag) { throw SerialException("Aborted by client request"); } if (result < 0) { throw SerialException("Lost serial connection during select"); } }
Serial::Serial(const std::string& device, Logger& logger) : logger(logger), abortFlag(false) { fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd) { throw SerialException("Could not open device"); } if (!isatty(fd)) { close(fd); throw SerialException("Specified device is not a TTY"); } termios termAttr; if (-1 == tcgetattr(fd, &termAttr)) { close(fd); throw SerialException("Could not get device attributes"); } termAttr.c_cc[VTIME] = 0; termAttr.c_cc[VMIN] = 0; termAttr.c_iflag = 0; termAttr.c_oflag = 0; termAttr.c_cflag = CS8 | CREAD | CLOCAL; termAttr.c_lflag = 0; if (0 > cfsetispeed(&termAttr, B115200) || 0 > cfsetospeed(&termAttr, B115200)) { close(fd); throw SerialException("Could not set device baud rate"); } if (-1 == tcsetattr(fd, TCSAFLUSH, &termAttr)) { close(fd); throw SerialException("Could not set device attributes"); } }
void Serial::write(const char* data, size_t length) { ssize_t bw = 0; logger.debug(MODULE, "Writing %u bytes", length); while (length > 0) { waitToWrite(); bw = ::write(fd, data, length); if (-1 == bw) { throw SerialException("Could not write data"); } length -= bw; data += bw; } }
void Serial::waitForData() { fd_set readset; int result; logger.debug(MODULE, "Waiting for data"); do { FD_ZERO(&readset); FD_SET(fd, &readset); timeval timeout = {0, 100}; result = select(fd + 1, &readset, nullptr, nullptr, &timeout); } while (result == 0 && !abortFlag); logger.debug(MODULE, "Got some data? %d %d %s", result, errno, abortFlag ? "true" : "false"); if (abortFlag) { throw SerialException("Aborted by client request"); } if (result < 0) { throw SerialException("Lost serial connection during select"); } }