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;
}