/** * Configures serial port to use raw 8-bit mode and given baud * rate. This function also supports non-standard baud rates if the * underlying hardware is capable. If it fails, -1 is returned and * errno is set. Otherwise, zero is returned. */ int init_serial_port(int fd, int speed) { // Check if speed preset is found or do we need to set a custom speed tcflag_t speed_preset = to_speed(speed); if (speed_preset == B0) { // Find current configuration struct serial_struct serial; if(ioctl(fd, TIOCGSERIAL, &serial) == -1) return -1; serial.flags = (serial.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST; serial.custom_divisor = (serial.baud_base + (speed / 2)) / speed; // Check that the serial timing error is no more than 2% int real_speed = serial.baud_base / serial.custom_divisor; if (real_speed < speed * 98 / 100 || real_speed > speed * 102 / 100) { errno = ENOTSUP; return -1; } // Activate if(ioctl(fd, TIOCSSERIAL, &serial) == -1) return -1; // Custom baudrate only works with this magic value speed_preset = B38400; } // Start with raw values struct termios term; term.c_cflag = speed_preset | CS8 | CLOCAL | CREAD; cfmakeraw(&term); if (tcsetattr(fd,TCSANOW,&term) == -1) return -1; return 0; }
static int set_com_state(int fd, uart_com_state_t* com) { struct termios tio; // read current state if (tcgetattr(fd, &tio) < 0) { DEBUGF("unable to read com state: %s", strerror(errno)); return -1; } // On Mac os X IOSSIOSPEED can be used to set "non-traditional baud rate" // From "IOKit/serial/ioss.h" cfsetispeed(&tio, to_speed(com->ibaud)); cfsetospeed(&tio, to_speed(com->obaud)); // update from state switch(com->parity) { case UART_PARITY_NONE: tio.c_iflag &= ~PARMRK; tio.c_cflag &= ~PARENB; break; case UART_PARITY_ODD: // odd tio.c_iflag &= ~PARMRK; tio.c_cflag |= PARODD; tio.c_cflag |= PARENB; break; case UART_PARITY_EVEN: // even tio.c_iflag &= ~PARMRK; tio.c_cflag &= ~PARODD; tio.c_cflag |= PARENB; break; case UART_PARITY_MARK: // mark (FIXME) tio.c_iflag |= PARMRK; tio.c_cflag |= PARENB; break; case UART_PARITY_SPACE: // space (FIXME) tio.c_iflag &= ~PARMRK; tio.c_cflag &= ~PARENB; break; default: break; } if (com->stopb == 1) tio.c_cflag &= ~CSTOPB; else if (com->stopb == 2) tio.c_cflag |= CSTOPB; tio.c_cflag &= ~CSIZE; switch(com->csize) { case 5: tio.c_cflag |= CS5; break; case 6: tio.c_cflag |= CS6; break; case 7: tio.c_cflag |= CS7; break; case 8: tio.c_cflag |= CS8; break; default: break; } // Set the buffer number of bytes buffered before interrupt if (com->bufsz > 255) tio.c_cc[VMIN] = 255; else tio.c_cc[VMIN] = com->bufsz; // Set the max time to buffer bytes if (com->buftm > 25500) // 25500 ms = 25.5 sec tio.c_cc[VTIME] = 255; else tio.c_cc[VTIME] = com->buftm / 100; tio.c_cc[VSTART] = com->xonchar; tio.c_cc[VSTOP] = com->xoffchar; // input flow control UPD_BIT(tio.c_iflag, IXOFF, (com->iflow & UART_SW)); #if defined(CRTS_IFLOW) UPD_BIT(tio.c_cflag, CRTS_IFLOW, (com->iflow & UART_RTS)); #endif #if defined(CDTR_IFLOW) UPD_BIT(tio.c_cflag, CDTR_IFLOW, (com->iflow & UART_DTR)); #endif // output flow control UPD_BIT(tio.c_iflag, IXON, (com->oflow & UART_SW)); #if defined(CCTS_OFLOW) UPD_BIT(tio.c_cflag, CCTS_OFLOW, (com->oflow & UART_CTS)); #endif #if defined(CDSR_OFLOW) UPD_BIT(tio.c_cflag, CDSR_OFLOW, (com->oflow & UART_DSR)); #endif #if defined(CCAR_OFLOW) UPD_BIT(tio.c_cflag, CCAR_OFLOW, (com->oflow & UART_CD)); #endif #if defined(CRTSCTS) if ((com->iflow & UART_RTS) && (com->oflow & UART_CTS)) tio.c_cflag |= CRTSCTS; else if (!(com->iflow & UART_RTS) && !(com->oflow & UART_CTS)) tio.c_cflag &= ~CRTSCTS; #endif // ignore break condition tio.c_iflag |= IGNBRK; // local line + enable receiver tio.c_cflag |= (CLOCAL | CREAD); // raw input processing tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN); // no output processing tio.c_oflag &= ~(OPOST); // do NOT hangup-on-close, need? we keep one slave open tio.c_cflag &= ~HUPCL; tcflush(fd, TCIFLUSH); return tcsetattr(fd, TCSANOW, &tio); }
static int set_com_state(HANDLE fh, uart_com_state_t* com) { DCB dcb; COMMTIMEOUTS tmo; int baud; memset(&dcb, 0, sizeof(dcb)); if (!GetCommState(fh, &dcb)) { DEBUG_ERROR("GetCommState: error %d", GetLastError()); return -1; } baud = (com->ibaud > com->obaud) ? com->ibaud : com->obaud; dcb.BaudRate = to_speed(baud); switch(com->parity) { case UART_PARITY_NONE: dcb.fParity = FALSE; dcb.Parity = NOPARITY; break; case UART_PARITY_ODD: dcb.fParity = TRUE; dcb.Parity = ODDPARITY; break; case UART_PARITY_EVEN: dcb.fParity = TRUE; dcb.Parity = EVENPARITY; break; case UART_PARITY_MARK: dcb.fParity = TRUE; dcb.Parity = MARKPARITY; break; case UART_PARITY_SPACE: dcb.fParity = TRUE; dcb.Parity = SPACEPARITY; break; default: dcb.fParity = FALSE; dcb.Parity = NOPARITY; break; } if (com->stopb == 1) dcb.StopBits = ONESTOPBIT; else if (com->stopb == 2) dcb.StopBits = TWOSTOPBITS; else if (com->stopb == 3) dcb.StopBits = ONE5STOPBITS; dcb.ByteSize = com->csize; dcb.XonChar = com->xonchar; dcb.XoffChar = com->xoffchar; // FIXME better flow handling! // {flow,[xoff|dtr|rts],[xoff|cts|dsr]} ? // dcb.fInX = (com->iflow & UART_SW) != 0; dcb.fDtrControl = (com->iflow & UART_DTR) != 0; dcb.fRtsControl = (com->iflow & UART_RTS) != 0; dcb.fOutX = (com->oflow & UART_SW) != 0; dcb.fOutxCtsFlow = (com->oflow & UART_CTS) != 0; dcb.fOutxDsrFlow = (com->oflow & UART_DSR) != 0; dcb.fNull = FALSE; dcb.DCBlength = sizeof(DCB); if (!SetCommState(fh, &dcb)) { DEBUG_ERROR("SetCommState: error %d", GetLastError()); return -1; } // Setup harware buffer and timers if (com->bufsz > 255) SetupComm(fh, 255, DEFAULT_OUT_QUEUE); else SetupComm(fh, com->bufsz, DEFAULT_OUT_QUEUE); tmo.ReadIntervalTimeout = com->buftm; tmo.ReadTotalTimeoutMultiplier = 0; tmo.ReadTotalTimeoutConstant = 0; tmo.WriteTotalTimeoutMultiplier = 0; tmo.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(fh, &tmo)) { DEBUG_ERROR("GetCommTimeouts: error %d", GetLastError()); return -1; } return 0; }