void EIO_Open(uv_work_t* req) { OpenBaton* data = static_cast<OpenBaton*>(req->data); UnixPlatformOptions* platformOptions = static_cast<UnixPlatformOptions*>(data->platformOptions); int baudRate = ToBaudConstant(data->baudRate); // #if not ( defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) ) // if(baudRate == -1) { // snprintf(data->errorString, sizeof(data->errorString), "Invalid baud rate setting %d", data->baudRate); // return; // } // #endif int dataBits = ToDataBitsConstant(data->dataBits); if(dataBits == -1) { snprintf(data->errorString, sizeof(data->errorString), "Invalid data bits setting %d", data->dataBits); return; } int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC | O_SYNC); int fd = open(data->path, flags); if (fd == -1) { snprintf(data->errorString, sizeof(data->errorString), "Cannot open %s", data->path); return; } // struct sigaction saio; // saio.sa_handler = sigio_handler; // sigemptyset(&saio.sa_mask); // saio.sa_flags = 0; // sigaction(SIGIO, &saio, NULL); // //all process to receive SIGIO // fcntl(fd, F_SETOWN, getpid()); // int flflags = fcntl(fd, F_GETFL); // fcntl(fd, F_SETFL, flflags | FNONBLOCK); struct termios options; // Set baud and other configuration. tcgetattr(fd, &options); // Removing check for valid BaudRates due to ticket: #140 // #if not ( defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) ) // Specify the baud rate // On linux you can alter the meaning of B38400 to mean a custom baudrate... #if defined(__linux__) && defined(ASYNC_SPD_CUST) if (baudRate == -1) { struct serial_struct serinfo; serinfo.reserved_char[0] = 0; if (ioctl(fd, TIOCGSERIAL, &serinfo) != -1) { serinfo.flags &= ~ASYNC_SPD_MASK; serinfo.flags |= ASYNC_SPD_CUST; serinfo.custom_divisor = (serinfo.baud_base + (data->baudRate / 2)) / data->baudRate; if (serinfo.custom_divisor < 1) serinfo.custom_divisor = 1; ioctl(fd, TIOCSSERIAL, &serinfo); ioctl(fd, TIOCGSERIAL, &serinfo); // if (serinfo.custom_divisor * rate != serinfo.baud_base) { // warnx("actual baudrate is %d / %d = %f", // serinfo.baud_base, serinfo.custom_divisor, // (float)serinfo.baud_base / serinfo.custom_divisor); // } } // Now we use "B38400" to trigger the special baud rate. baudRate = B38400; } #endif if (baudRate != -1) { cfsetispeed(&options, baudRate); cfsetospeed(&options, baudRate); } // Removing check for valid BaudRates due to ticket: #140 // #endif /* IGNPAR : ignore bytes with parity errors */ options.c_iflag = IGNPAR; /* ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) */ // Pulling this for now. It should be an option, however. -Giseburt //options.c_iflag = ICRNL; // otherwise make device raw (no other input processing) // Specify data bits options.c_cflag &= ~CSIZE; options.c_cflag |= dataBits; options.c_cflag &= ~(CRTSCTS); if (data->rtscts) { options.c_cflag |= CRTSCTS; // evaluate specific flow control options } options.c_iflag &= ~(IXON | IXOFF | IXANY); if (data->xon) { options.c_iflag |= IXON; } if (data->xoff) { options.c_iflag |= IXOFF; } if (data->xany) { options.c_iflag |= IXANY; } switch (data->parity) { case SERIALPORT_PARITY_NONE: options.c_cflag &= ~PARENB; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS8; break; case SERIALPORT_PARITY_ODD: options.c_cflag |= PARENB; options.c_cflag |= PARODD; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS7; break; case SERIALPORT_PARITY_EVEN: options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS7; break; default: snprintf(data->errorString, sizeof(data->errorString), "Invalid parity setting %d", data->parity); close(fd); return; } switch(data->stopBits) { case SERIALPORT_STOPBITS_ONE: options.c_cflag &= ~CSTOPB; break; case SERIALPORT_STOPBITS_TWO: options.c_cflag |= CSTOPB; break; default: snprintf(data->errorString, sizeof(data->errorString), "Invalid stop bits setting %d", data->stopBits); close(fd); return; } options.c_cflag |= CLOCAL; //ignore status lines options.c_cflag |= CREAD; //enable receiver options.c_cflag |= HUPCL; //drop DTR (i.e. hangup) on close // Raw output options.c_oflag = 0; // ICANON makes partial lines not readable. It should be otional. // It works with ICRNL. -Giseburt options.c_lflag = 0; //ICANON; options.c_cc[VMIN]= platformOptions->vmin; options.c_cc[VTIME]= platformOptions->vtime; // removed this unneeded sleep. // sleep(1); tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &options); // On OS X, starting in Tiger, we can set a custom baud rate, as follows: #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) if (baudRate == -1) { speed_t speed = data->baudRate; if (ioctl(fd, IOSSIOSPEED, &speed) == -1) { snprintf(data->errorString, sizeof(data->errorString), "Error %s calling ioctl( ..., IOSSIOSPEED, %ld )", strerror(errno), speed ); } } #endif data->result = fd; }
void EIO_Open(uv_work_t* req) { OpenBaton* data = static_cast<OpenBaton*>(req->data); #if not ( defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) ) int baudRate = ToBaudConstant(data->baudRate); if(baudRate == -1) { sprintf(data->errorString, "Invalid baud rate setting %d", data->baudRate); return; } #endif int dataBits = ToDataBitsConstant(data->dataBits); if(dataBits == -1) { sprintf(data->errorString, "Invalid data bits setting %d", data->dataBits); return; } int flowControl = ToFlowControlConstant(data->flowControl); if(flowControl == -1) { sprintf(data->errorString, "Invalid flow control setting %d", data->flowControl); return; } int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY); int fd = open(data->path, flags); if (fd == -1) { sprintf(data->errorString, "Cannot open %s", data->path); return; } struct termios options; struct sigaction saio; saio.sa_handler = SIG_IGN; sigemptyset(&saio.sa_mask); saio.sa_flags = 0; sigaction(SIGIO, &saio, NULL); //all process to receive SIGIO fcntl(fd, F_SETOWN, getpid()); fcntl(fd, F_SETFL, FASYNC); // Set baud and other configuration. tcgetattr(fd, &options); #if not ( defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) ) // Specify the baud rate cfsetispeed(&options, baudRate); cfsetospeed(&options, baudRate); #endif // Specify data bits options.c_cflag &= ~CSIZE; options.c_cflag |= dataBits; // Specify flow control options.c_cflag &= ~flowControl; options.c_cflag |= flowControl; switch (data->parity) { case SERIALPORT_PARITY_NONE: options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; break; case SERIALPORT_PARITY_ODD: options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS7; break; case SERIALPORT_PARITY_EVEN: options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS7; break; default: sprintf(data->errorString, "Invalid parity setting %d", data->parity); close(fd); return; } switch(data->stopBits) { case SERIALPORT_STOPBITS_ONE: options.c_cflag &= ~CSTOPB; break; case SERIALPORT_STOPBITS_TWO: options.c_cflag |= CSTOPB; break; default: sprintf(data->errorString, "Invalid stop bits setting %d", data->stopBits); close(fd); return; } options.c_cflag |= CLOCAL; //ignore status lines options.c_cflag |= CREAD; //enable receiver options.c_cflag |= HUPCL; //drop DTR (i.e. hangup) on close options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; //ICANON; options.c_cc[VMIN]=1; options.c_cc[VTIME]=0; sleep(1); tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &options); #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) speed_t speed = data->baudRate; if ( ioctl( fd, IOSSIOSPEED, &speed ) == -1 ) { printf( "Error %d calling ioctl( ..., IOSSIOSPEED, ... )\n", errno ); } #endif data->result = fd; }
int setup(int fd, OpenBaton *data) { int dataBits = ToDataBitsConstant(data->dataBits); if (-1 == dataBits) { snprintf(data->errorString, sizeof(data->errorString), "Invalid data bits setting %d", data->dataBits); return -1; } // Snow Leopard doesn't have O_CLOEXEC if (-1 == fcntl(fd, F_SETFD, FD_CLOEXEC)) { snprintf(data->errorString, sizeof(data->errorString), "Error %s Cannot open %s", strerror(errno), data->path); return -1; } // Get port configuration for modification struct termios options; tcgetattr(fd, &options); // IGNPAR: ignore bytes with parity errors options.c_iflag = IGNPAR; // ICRNL: map CR to NL (otherwise a CR input on the other computer will not terminate input) // Future potential option // options.c_iflag = ICRNL; // otherwise make device raw (no other input processing) // Specify data bits options.c_cflag &= ~CSIZE; options.c_cflag |= dataBits; options.c_cflag &= ~(CRTSCTS); if (data->rtscts) { options.c_cflag |= CRTSCTS; // evaluate specific flow control options } options.c_iflag &= ~(IXON | IXOFF | IXANY); if (data->xon) { options.c_iflag |= IXON; } if (data->xoff) { options.c_iflag |= IXOFF; } if (data->xany) { options.c_iflag |= IXANY; } switch (data->parity) { case SERIALPORT_PARITY_NONE: options.c_cflag &= ~PARENB; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS8; break; case SERIALPORT_PARITY_ODD: options.c_cflag |= PARENB; options.c_cflag |= PARODD; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS7; break; case SERIALPORT_PARITY_EVEN: options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; // options.c_cflag &= ~CSTOPB; // options.c_cflag &= ~CSIZE; // options.c_cflag |= CS7; break; default: snprintf(data->errorString, sizeof(data->errorString), "Invalid parity setting %d", data->parity); return -1; } switch (data->stopBits) { case SERIALPORT_STOPBITS_ONE: options.c_cflag &= ~CSTOPB; break; case SERIALPORT_STOPBITS_TWO: options.c_cflag |= CSTOPB; break; default: snprintf(data->errorString, sizeof(data->errorString), "Invalid stop bits setting %d", data->stopBits); return -1; } options.c_cflag |= CLOCAL; // ignore status lines options.c_cflag |= CREAD; // enable receiver if (data->hupcl) { options.c_cflag |= HUPCL; // drop DTR (i.e. hangup) on close } // Raw output options.c_oflag = 0; // ICANON makes partial lines not readable. It should be optional. // It works with ICRNL. options.c_lflag = 0; // ICANON; options.c_cc[VMIN]= data->vmin; options.c_cc[VTIME]= data->vtime; // Note that tcsetattr() returns success if any of the requested changes could be successfully carried out. // Therefore, when making multiple changes it may be necessary to follow this call with a further call to // tcgetattr() to check that all changes have been performed successfully. // This also fails on OSX tcsetattr(fd, TCSANOW, &options); if (data->lock) { if (-1 == flock(fd, LOCK_EX | LOCK_NB)) { snprintf(data->errorString, sizeof(data->errorString), "Error %s Cannot lock port", strerror(errno)); return -1; } } // Copy the connection options into the ConnectionOptionsBaton to set the baud rate ConnectionOptionsBaton* connectionOptions = new ConnectionOptionsBaton(); connectionOptions->fd = fd; connectionOptions->baudRate = data->baudRate; if (-1 == setBaudRate(connectionOptions)) { strncpy(data->errorString, connectionOptions->errorString, sizeof(data->errorString)); delete(connectionOptions); return -1; } delete(connectionOptions); // flush all unread and wrote data up to this point because it could have been received or sent with bad settings // Not needed since setBaudRate does this for us // tcflush(fd, TCIOFLUSH); return 1; }