/** \fn bool Serial::validate_baud_rate(int pbaud_rate) * \brief Validates pbaud_rate. * * Description: Sets data members baud_rate, bspeed to valid values. * * \param[in] pbaud_rate baud rate * * \return When pbaud_rate is a valid baud rate, data member baud_rate is set to * pbaud_rate. bspeed is set to match the baud rate. Returns true. * * When pbaud_rate is not valid, data member baud_rate is set to 57600, * bspeed is set to B57600. Returns false. * */ void Serial::validate_baud_rate(int pbaud_rate){ // set the input/output baud rates switch(pbaud_rate) { case 2400: case 9600: case 19200: case 38400: case 57600: case 115200: baud_rate = pbaud_rate; break; default: baud_rate = DEFAULT_BAUD_RATE; LOG_WARN("invalid baud rate: %d, using default: %d", pbaud_rate, DEFAULT_BAUD_RATE); } // end switch baud bspeed = set_baud_speed(baud_rate); }
/** \fn int Serial::initialize(void); * \brief Opens and configures a serial port connection. * * The function opens a connection to the pathname stored in the Serial class * data member, serial_device_name_. Returns the file descriptor to that port location. * * Configuration: * 8 data bits per character * No parity bit * 2 stop bits * No hardware flow control * No software flow control * * * \return success: file descriptor * \return failure: -1 */ int Serial::initialize_port(void) { struct termios oldtio,newtio; int serial_speed = set_baud_speed(baud_rate); fprintf(stderr, "device name: %s\n", serial_device_name.c_str()); /** open() system call is used to convert a pathname into a file descriptor * (a small, non-negative integer for use in subsequent I/O). * * on success, the file descriptor returned will be the lowest file descriptor * not currently open for the process. * * on failure, returns -1 * * O_RDWR open for read and write access * * O_NDELAY program doesn't care what state the DCD signal line is at - whether the * other end of the port is up and running. If you do not specify this flag, * your process will be put to sleep until the DCD signal line is set to the * space voltage. */ if( (serial_file_descriptor = open(serial_device_name.c_str(), O_RDWR | O_NDELAY)) == -1 ) { fprintf(stderr, "[ERROR] (%s: %s: %d) errno: %s\n", __FILE__, __FUNCTION__, __LINE__ , strerror(errno)); return serial_file_descriptor; } // Get current serial port settings if( tcgetattr(serial_file_descriptor, &oldtio) < 0) { fprintf(stderr, "[ERROR] (%s: %s: %d) errno: %s\n", __FILE__, __FUNCTION__, __LINE__ , strerror(errno)); close_port(); return serial_file_descriptor; } // New port settings memset(&newtio, 0, sizeof(newtio)); // set all struct values to zero /* Set Control mode * CS8 - 8 data bits, no parity, 1 stop bit * CLOCAL - local connnection, no modem control * CREAD - enable receiving characters * IGNBRK - ignore break condition */ newtio.c_cflag = serial_speed | CS8 | CLOCAL | CREAD | IGNBRK; /* IGNPAR - ignore bytes with parity errors * ICRNL - map CR to NL (otherwise a CR input on the other computer will not terminate input) * */ newtio.c_iflag = IGNPAR | ICRNL; newtio.c_oflag = 0; // raw output /* * ICANON : enable canonical input * disable all echo functionality, and don't send signals to calling program */ newtio.c_lflag = ICANON; // Empty serial port buffers tcflush(serial_file_descriptor, TCIFLUSH); // Load new settings if( tcsetattr(serial_file_descriptor, TCSANOW, &newtio) , 0) { fprintf(stderr, "[ERROR] (%s: %s: %d) errno: %s\n", __FILE__, __FUNCTION__, __LINE__ , strerror(errno)); close(serial_file_descriptor); serial_file_descriptor = -1; return serial_file_descriptor; } return serial_file_descriptor; }
/** * NAME : int serial_init(const char *serial_device_name, int baud_rate) * * DESCRIPTION: opens serial port * * INPUTS: * Parameters: * const char* serial_device_name serial device path name example: "/dev/ttyUSB0" * int baud_rate baud rate * Globals: * none * * OUTPUTS: * Return: * Type: int * Values: * success serial port file descriptor. * failure -1 * * PROCESS: * [1] open serial port connection * [2] sets speed to specified baud rate * If baud rate is not valid, sets to default rate 9600 * [3] 8 data bits, No parity, 1 stop bit * [4] Raw mode, so binary data can be sent * [5] minimum characters to read: 0 * [6] time to wait for data: 0 * [7] flushes data from input & output lines * [8] returns valid file descriptor or -1 on error * * NOTES: * Error messages are sent to stderr stream * */ int serial_init(const char *serial_device_name, int baud_rate) { int serial_port_fd; int bspeed; struct termios terminalSettings; // Open the serial port nonblocking (read returns immediately) serial_port_fd = open(serial_device_name, O_RDWR | O_NOCTTY | O_NONBLOCK); if(serial_port_fd < 0) // open returns -1 on error { fprintf(stderr, "error: %s, serial port not open, errno -%s\n", __FUNCTION__, strerror(errno)); fprintf(stderr, "serial device name: %s\n", serial_device_name); return -1; } else fprintf(stderr, "serial port fd = %d\n", serial_port_fd); // Get current serial port settings if(tcgetattr(serial_port_fd, &terminalSettings) < 0){ perror("initialize_serial: could not get current serial port settings"); return -1; } // set baud rate bspeed = set_baud_speed(baud_rate); if(bspeed != -1){ cfsetispeed(&terminalSettings, bspeed); cfsetospeed(&terminalSettings, bspeed); } else{ return -1; } // set control flags terminalSettings.c_cflag &= ~PARENB; // no parity terminalSettings.c_cflag &= ~CSTOPB; // 1 stop bit terminalSettings.c_cflag &= ~CSIZE; // reset character size bits terminalSettings.c_cflag |= CS8; // data size 8 bit terminalSettings.c_cflag &= ~CRTSCTS; // no flow control /* CREAD - enable receiver CLOCAL should be enabled to ensure that your program does not become the 'owner' of the port subject to sporatic job control and hangup signals */ terminalSettings.c_cflag |= CREAD | CLOCAL; // enable receiver, ignore ctrl lines /** turn off software flow control (outgoing, incoming) allow any character to start flow again */ terminalSettings.c_iflag &= ~(IXON | IXOFF | IXANY); // configure for raw input terminalSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // configure for raw output terminalSettings.c_oflag &= ~OPOST; // VMIN sets minimum characters to read terminalSettings.c_cc[VMIN] = 0; // time to wait for data (tenths of seconds) terminalSettings.c_cc[VTIME] = 0; // Load new settings if( tcsetattr(serial_port_fd, TCSAFLUSH, &terminalSettings) < 0){ perror("init_serialport: Couldn't set term attributes"); return -1; } // clear data from both input/output buffers /* When using a usb serial port, the USB driver does not know if there is data in the internal shift register, FIFO or USB subsystem. As a workaround, to ensure the data is flushed, add a sleep delay here to suspend program execution. This allows time for data to arrive and be stored in the buffers. A call to flush will then work. May need to experiment with sleep time. */ usleep(10000); // 10 ms tcflush(serial_port_fd, TCIOFLUSH); return serial_port_fd; }