예제 #1
0
  public int write(int fd, byte[] buffer, int length) {
    Port port = getPort(fd);
    if (port == null) return -1;

    synchronized (port.m_WrBuffer) {
      try {
        if (port.m_WritePending > 0) {
          while (true) {
            int res = WaitForSingleObject(port.m_WrOVL.hEvent, INFINITE);
            if (res == WAIT_TIMEOUT) {
              clearCommErrors(port);
              log =
                  log
                      && log(
                          1,
                          "write pending, cbInQue %d cbOutQue %d\n",
                          port.m_COMSTAT.cbInQue,
                          port.m_COMSTAT.cbOutQue);
              continue;
            }
            if (!GetOverlappedResult(port.m_Comm, port.m_WrOVL, port.m_WrN, false)) port.fail();
            if (port.m_WrN[0]
                != port.m_WritePending) // I exptect this is never going to happen, if it does
            new RuntimeException(
                  "Windows OVERLAPPED WriteFile failed to write all, tried to write "
                      + port.m_WritePending
                      + " but got "
                      + port.m_WrN[0]);
            break;
          }
          port.m_WritePending = 0;
        }
        if ((port.m_OpenFlags & O_NONBLOCK) != 0) {
          if (!ClearCommError(port.m_Comm, port.m_WrErr, port.m_WrStat)) port.fail();
          int room = (int) port.m_WrBuffer.size() - port.m_WrStat.cbOutQue;
          if (length > room) length = room;
        }

        if (!ResetEvent(port.m_WrOVL.hEvent)) port.fail();

        if (length > port.m_WrBuffer.size()) length = (int) port.m_WrBuffer.size();
        port.m_WrBuffer.write(0, buffer, 0, length); // copy from buffer to Memory
        boolean ok = WriteFile(port.m_Comm, port.m_WrBuffer, length, port.m_WrN, port.m_WrOVL);

        if (!ok) {
          if (GetLastError() != ERROR_IO_PENDING) port.fail();
          port.m_WritePending = length;
        }
        //
        return length; // port.m_WrN[0];
      } catch (Fail f) {
        return -1;
      }
    }
  }
예제 #2
0
 public int tcsendbreak(int fd, int duration) {
   Port port = getPort(fd);
   if (port == null) return -1;
   try {
     if (!SetCommBreak(port.m_Comm)) port.fail();
     nanoSleep(duration * 250000000);
     if (!ClearCommBreak(port.m_Comm)) port.fail();
     return 0;
   } catch (Fail f) {
     return -1;
   }
 }
예제 #3
0
  public int open(String filename, int flags) {
    Port port = new Port();
    port.m_OpenFlags = flags;
    try {
      if (!filename.startsWith("\\\\")) filename = "\\\\.\\" + filename;

      port.m_Comm =
          CreateFileW(
              new WString(filename),
              GENERIC_READ | GENERIC_WRITE,
              0,
              null,
              OPEN_EXISTING,
              FILE_FLAG_OVERLAPPED,
              null);

      if (INVALID_HANDLE_VALUE == port.m_Comm) {
        if (GetLastError() == ERROR_FILE_NOT_FOUND) m_ErrNo = ENOENT;
        else m_ErrNo = EBUSY;
        port.fail();
      }

      if (!SetupComm(port.m_Comm, (int) port.m_RdBuffer.size(), (int) port.m_WrBuffer.size()))
        port.fail(); // FIXME what would be appropriate error code here

      cfmakeraw(port.m_Termios);
      cfsetispeed(port.m_Termios, B9600);
      cfsetospeed(port.m_Termios, B9600);
      port.m_Termios.c_cc[VTIME] = 0;
      port.m_Termios.c_cc[VMIN] = 0;
      updateFromTermios(port);

      port.m_RdOVL.writeField("hEvent", CreateEventA(null, true, false, null));
      if (port.m_RdOVL.hEvent == INVALID_HANDLE_VALUE) port.fail();

      port.m_WrOVL.writeField("hEvent", CreateEventA(null, true, false, null));
      if (port.m_WrOVL.hEvent == INVALID_HANDLE_VALUE) port.fail();

      port.m_SelOVL.writeField("hEvent", CreateEventA(null, true, false, null));
      if (port.m_SelOVL.hEvent == INVALID_HANDLE_VALUE) port.fail();

      return port.m_FD;
    } catch (Exception f) {
      if (port != null) port.close();
      return -1;
    }
  }
예제 #4
0
  public int tcflush(int fd, int queue) {
    Port port = getPort(fd);
    if (port == null) return -1;
    try {
      if (queue == TCIFLUSH) {
        if (!PurgeComm(port.m_Comm, PURGE_RXABORT)) port.fail();
      } else if (queue == TCOFLUSH) {
        if (!PurgeComm(port.m_Comm, PURGE_TXABORT)) port.fail();
      } else if (queue == TCIOFLUSH) {
        if (!PurgeComm(port.m_Comm, PURGE_TXABORT)) port.fail();
        if (!PurgeComm(port.m_Comm, PURGE_RXABORT)) port.fail();
      } else {
        m_ErrNo = ENOTSUP;
        return -1;
      }

      return 0;
    } catch (Fail f) {
      return -1;
    }
  }
예제 #5
0
 public int tcdrain(int fd) {
   Port port = getPort(fd);
   if (port == null) return -1;
   try {
     synchronized (port.m_WrBuffer) {
       if (!FlushFileBuffers(port.m_Comm)) port.fail();
       return 0;
     }
   } catch (Fail f) {
     return -1;
   }
 }
예제 #6
0
  public int ioctl(int fd, int cmd, int[] arg) {
    Port port = getPort(fd);
    if (port == null) return -1;
    try {
      if (cmd == FIONREAD) {
        clearCommErrors(port);
        arg[0] = port.m_COMSTAT.cbInQue;
        return 0;
      } else if (cmd == TIOCMSET) {
        int a = arg[0];
        if ((a & TIOCM_DTR) != 0) port.MSR |= TIOCM_DTR;
        else port.MSR &= ~TIOCM_DTR;

        if (!EscapeCommFunction(port.m_Comm, ((a & TIOCM_DTR) != 0) ? SETDTR : CLRDTR)) port.fail();

        if ((a & TIOCM_RTS) != 0) port.MSR |= TIOCM_RTS;
        else port.MSR &= ~TIOCM_RTS;
        if (!EscapeCommFunction(port.m_Comm, ((a & TIOCM_RTS) != 0) ? SETRTS : CLRRTS)) port.fail();
        return 0;
      } else if (cmd == TIOCMGET) {
        int[] stat = {0};
        if (!GetCommModemStatus(port.m_Comm, stat)) port.fail();
        int s = stat[0];
        int a = arg[0];
        if ((s & MS_RLSD_ON) != 0) a |= TIOCM_CAR;
        else a &= ~TIOCM_CAR;
        if ((s & MS_RING_ON) != 0) a |= TIOCM_RNG;
        else a &= ~TIOCM_RNG;
        if ((s & MS_DSR_ON) != 0) a |= TIOCM_DSR;
        else a &= ~TIOCM_DSR;
        if ((s & MS_CTS_ON) != 0) a |= TIOCM_CTS;
        else a &= ~TIOCM_CTS;

        if ((port.MSR & TIOCM_DTR) != 0) a |= TIOCM_DTR;
        else a &= ~TIOCM_DTR;
        if ((port.MSR & TIOCM_RTS) != 0) a |= TIOCM_RTS;
        else a &= ~TIOCM_RTS;
        arg[0] = a;

        return 0;
      } else {
        m_ErrNo = ENOTSUP;
        return -1;
      }
    } catch (Fail f) {
      return -1;
    }
  }
예제 #7
0
  public int select(int n, FDSet readfds, FDSet writefds, FDSet exceptfds, TimeVal timeout) {
    // long T0 = System.currentTimeMillis();
    int ready = 0;
    LinkedList<Port> locked = new LinkedList<Port>();
    try {
      try {
        LinkedList<Port> waiting = new LinkedList<Port>();
        for (int fd = 0; fd < n; fd++) {
          boolean rd = FD_ISSET(fd, readfds);
          boolean wr = FD_ISSET(fd, writefds);
          FD_CLR(fd, readfds);
          FD_CLR(fd, writefds);
          if (rd || wr) {
            Port port = getPort(fd);
            if (port == null) return -1;
            try {
              port.lock();
              locked.add(port);
              clearCommErrors(port);

              // check if there is data to be read, as WaitCommEvent
              // does check for only *new* data that and thus
              // might wait indefinitely if select() is called twice
              // without first reading away all data

              if (rd && port.m_COMSTAT.cbInQue > 0) {
                FD_SET(fd, readfds);
                ready++;
              }

              if (wr && port.m_COMSTAT.cbOutQue == 0) {
                FD_SET(fd, writefds);
                ready++;
              }

              if (!ResetEvent(port.m_SelOVL.hEvent)) port.fail();

              int flags = 0;
              if (rd) flags |= EV_RXCHAR;
              if (wr) flags |= EV_TXEMPTY;
              if (!SetCommMask(port.m_Comm, flags)) port.fail();
              if (WaitCommEvent(port.m_Comm, port.m_EventFlags, port.m_SelOVL)) {
                if (!GetOverlappedResult(port.m_Comm, port.m_SelOVL, port.m_SelN, false))
                  port.fail();
                // actually it seems that overlapped
                // WaitCommEvent never returns true so we never get here
                ready = maskToFDSets(port, readfds, writefds, exceptfds, ready);
              } else {
                // FIXME if the port dies on us what happens
                if (GetLastError() != ERROR_IO_PENDING) port.fail();
                waiting.add(port);
              }
            } catch (InterruptedException ie) {
              m_ErrNo = EINTR;
              return -1;
            }
          }
        }
        if (ready == 0) {
          int waitn = waiting.size();
          if (waitn > 0) {
            HANDLE[] wobj = new HANDLE[waiting.size() * 2];
            int i = 0;
            for (Port port : waiting) {
              wobj[i++] = port.m_SelOVL.hEvent;
              wobj[i++] = port.m_CancelWaitSema4;
            }
            int tout =
                timeout != null ? (int) (timeout.tv_sec * 1000 + timeout.tv_usec / 1000) : INFINITE;
            // int res = WaitForSingleObject(wobj[0], tout);
            int res = WaitForMultipleObjects(waitn * 2, wobj, false, tout);

            if (res == WAIT_TIMEOUT) {
              // work around the fact that sometimes we miss
              // events
              for (Port port : waiting) {
                clearCommErrors(port);
                int[] mask = {0};

                if (!GetCommMask(port.m_Comm, mask)) port.fail();
                if (port.m_COMSTAT.cbInQue > 0 && ((mask[0] & EV_RXCHAR) != 0)) {
                  FD_SET(port.m_FD, readfds);
                  log = log && log(1, "missed EV_RXCHAR event\n");
                  return 1;
                }
                if (port.m_COMSTAT.cbOutQue == 0 && ((mask[0] & EV_TXEMPTY) != 0)) {
                  FD_SET(port.m_FD, writefds);
                  log = log && log(1, "missed EV_TXEMPTY event\n");
                  return 1;
                }
              }
            }
            if (res != WAIT_TIMEOUT) {
              i = (res - WAIT_OBJECT_0) / 2;
              if (i < 0 || i >= waitn) throw new Fail();

              Port port = waiting.get(i);
              if (!GetOverlappedResult(port.m_Comm, port.m_SelOVL, port.m_SelN, false)) port.fail();

              ready = maskToFDSets(port, readfds, writefds, exceptfds, ready);
            }
          } else {
            if (timeout != null) nanoSleep(timeout.tv_sec * 1000000000L + timeout.tv_usec * 1000);
            else {
              m_ErrNo = EINVAL;
              return -1;
            }
            return 0;
          }
        }
      } catch (Fail f) {
        return -1;
      }
    } finally {
      for (Port port : locked) port.unlock();
    }
    // long T1 = System.currentTimeMillis();
    // System.err.println("select() " + (T1 - T0));

    return ready;
  }
예제 #8
0
 private void clearCommErrors(Port port) throws Fail {
   synchronized (port.m_COMSTAT) {
     if (!ClearCommError(port.m_Comm, port.m_ClearErr, port.m_COMSTAT)) port.fail();
   }
 }
예제 #9
0
  // FIXME this needs serious code review from people who know this stuff...
  public int updateFromTermios(Port port) throws Fail {
    Termios tios = port.m_Termios;
    int c_speed = tios.c_ospeed;
    int c_cflag = tios.c_cflag;
    int c_iflag = tios.c_iflag;
    int c_oflag = tios.c_oflag;

    if (c_speed != port.m_c_speed
        || c_cflag != port.m_c_cflag
        || c_iflag != port.m_c_iflag
        || c_oflag != port.m_c_oflag) {
      DCB dcb = port.m_DCB;
      if (!GetCommState(port.m_Comm, dcb)) port.fail();

      dcb.DCBlength = dcb.size();
      dcb.BaudRate = c_speed;
      if (tios.c_ospeed != tios.c_ispeed)
        log(0, "c_ospeed (%d) != c_ispeed (%d)\n", tios.c_ospeed, tios.c_ispeed);
      int flags = 0;
      // rxtx does: if ( s_termios->c_iflag & ISTRIP ) dcb.fBinary = FALSE;
      // but Winapi doc says fBinary always true
      flags |= fBinary;
      if ((c_cflag & PARENB) != 0) flags |= fParity;

      if ((c_iflag & IXON) != 0) flags |= fOutX;
      if ((c_iflag & IXOFF) != 0) flags |= fInX;
      if ((c_iflag & IXANY) != 0) flags |= fTXContinueOnXoff;

      if ((c_iflag & CRTSCTS) != 0) {
        flags |= fRtsControl;
        flags |= fOutxCtsFlow;
      }

      // Following have no corresponding functionality in unix termios
      // fOutxDsrFlow = 0x00000008;
      // fDtrControl = 0x00000030;
      // fDsrSensitivity = 0x00000040;
      // fErrorChar = 0x00000400;
      // fNull = 0x00000800;
      // fAbortOnError = 0x00004000;
      // fDummy2 = 0xFFFF8000;
      dcb.fFlags = flags;
      // Don't touch these, windows seems to use: XonLim 2048 XoffLim 512 and who am I to argue with
      // those
      // dcb.XonLim = 0;
      // dcb.XoffLim = 128;
      byte cs = 8;
      int csize = c_cflag & CSIZE;
      if (csize == CS5) cs = 5;
      if (csize == CS6) cs = 6;
      if (csize == CS7) cs = 7;
      if (csize == CS8) cs = 8;
      dcb.ByteSize = cs;

      if ((c_cflag & PARENB) != 0) {
        if ((c_cflag & PARODD) != 0 && (c_cflag & CMSPAR) != 0) dcb.Parity = MARKPARITY;
        else if ((c_cflag & PARODD) != 0) dcb.Parity = ODDPARITY;
        else if ((c_cflag & CMSPAR) != 0) dcb.Parity = SPACEPARITY;
        else dcb.Parity = EVENPARITY;
      } else dcb.Parity = NOPARITY;

      dcb.StopBits = (c_cflag & CSTOPB) != 0 ? TWOSTOPBITS : ONESTOPBIT;
      dcb.XonChar =
          tios.c_cc[
              VSTART]; // In theory these could change but they only get updated if the
                       // baudrate/char size changes so this could be a time bomb
      dcb.XoffChar =
          tios.c_cc[
              VSTOP]; // In practice in PJC these are never changed so updating on the first pass is
                      // enough
      dcb.ErrorChar = 0;

      // rxtx has some thing like
      // if ( EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_RING | ( EV_RLSD & EV_RXFLAG )
      // )
      // dcb.EvtChar = '\n';
      // else
      // dcb.EvtChar = '\0';
      // But those are all defines so there is something fishy there?

      dcb.EvtChar = '\n';
      dcb.EofChar = tios.c_cc[VEOF];

      if (!SetCommState(port.m_Comm, dcb)) port.fail();

      port.m_c_speed = c_speed;
      port.m_c_cflag = c_cflag;
      port.m_c_iflag = c_iflag;
      port.m_c_oflag = c_oflag;
    }

    int vmin = port.m_Termios.c_cc[VMIN] & 0xFF;
    int vtime = (port.m_Termios.c_cc[VTIME] & 0xFF) * 100;
    if (vmin != port.m_VMIN || vtime != port.m_VTIME) {
      COMMTIMEOUTS touts = port.m_Timeouts;
      // There are really no write timeouts in classic unix termios
      // FIXME test that we can still interrupt the tread
      touts.WriteTotalTimeoutConstant = 0;
      touts.WriteTotalTimeoutMultiplier = 0;
      if (vmin == 0 && vtime == 0) {
        // VMIN = 0 and VTIME = 0 => totally non blocking,if data is
        // available, return it, ie this is poll operation
        touts.ReadIntervalTimeout = MAXDWORD;
        touts.ReadTotalTimeoutConstant = 0;
        touts.ReadTotalTimeoutMultiplier = 0;
      }
      if (vmin == 0 && vtime > 0) {
        // VMIN = 0 and VTIME > 0 => timed read, return as soon as data is
        // available, VTIME = total time
        touts.ReadIntervalTimeout = 0;
        touts.ReadTotalTimeoutConstant = vtime;
        touts.ReadTotalTimeoutMultiplier = 0;
      }
      if (vmin > 0 && vtime > 0) {
        // VMIN > 0 and VTIME > 0 => blocks until VMIN chars has arrived or  between chars expired,
        // note that this will block if nothing arrives
        touts.ReadIntervalTimeout = vtime;
        touts.ReadTotalTimeoutConstant = 0;
        touts.ReadTotalTimeoutMultiplier = 0;
      }
      if (vmin > 0 && vtime == 0) {
        // VMIN > 0 and VTIME = 0 => blocks until VMIN characters have been
        // received
        touts.ReadIntervalTimeout = 0;
        touts.ReadTotalTimeoutConstant = 0;
        touts.ReadTotalTimeoutMultiplier = 0;
      }
      if (!SetCommTimeouts(port.m_Comm, port.m_Timeouts)) port.fail();
      port.m_VMIN = vmin;
      port.m_VTIME = vtime;
      log =
          log
              && log(
                  2,
                  "vmin %d vtime %d ReadIntervalTimeout %d ReadTotalTimeoutConstant %d ReadTotalTimeoutMultiplier %d\n",
                  vmin,
                  vtime,
                  touts.ReadIntervalTimeout,
                  touts.ReadTotalTimeoutConstant,
                  touts.ReadTotalTimeoutMultiplier);
    }

    return 0;
  }
예제 #10
0
  public int read(int fd, byte[] buffer, int length) {

    Port port = getPort(fd);
    if (port == null) return -1;
    synchronized (port.m_RdBuffer) {
      try {
        // limit reads to internal buffer size
        if (length > port.m_RdBuffer.size()) length = (int) port.m_RdBuffer.size();

        if (length == 0) return 0;

        if ((port.m_OpenFlags & O_NONBLOCK) != 0) {
          clearCommErrors(port);
          int available = port.m_COMSTAT.cbInQue;
          if (available == 0) {
            m_ErrNo = EAGAIN;
            return -1;
          }
          length = min(length, available);
        } else {
          clearCommErrors(port);
          int available = port.m_COMSTAT.cbInQue;
          int vtime = 0xff & port.m_Termios.c_cc[VTIME];
          int vmin = 0xff & port.m_Termios.c_cc[VMIN];

          if (vmin == 0 && vtime == 0) {
            // VMIN = 0 and VTIME = 0 => totally non blocking,if data is
            // available, return it, ie this is poll operation
            // For reference below commented out is how timeouts are set for this vtime/vmin combo
            // touts.ReadIntervalTimeout = MAXDWORD;
            // touts.ReadTotalTimeoutConstant = 0;
            // touts.ReadTotalTimeoutMultiplier = 0;
            if (available == 0) return 0;
            length = min(length, available);
          }
          if (vmin == 0 && vtime > 0) {
            // VMIN = 0 and VTIME > 0 => timed read, return as soon as data is
            // available, VTIME = total time
            // For reference below commented out is how timeouts are set for this vtime/vmin combo
            // touts.ReadIntervalTimeout = 0;
            // touts.ReadTotalTimeoutConstant = vtime;
            // touts.ReadTotalTimeoutMultiplier = 0;

            // NOTE to behave like unix we should probably wait until there is something available
            // and then try to do a read as many bytes as are available bytes at that point in time.
            // As this is coded now, this will attempt to read as many bytes as requested and this
            // may end up
            // spending vtime in the read when a unix would return less bytes but as soon as they
            // become
            // available.
          }
          if (vmin > 0 && vtime > 0) {
            // VMIN > 0 and VTIME > 0 => blocks until VMIN chars has arrived or  between chars
            // expired,
            // note that this will block if nothing arrives
            // For reference below commented out is how timeouts are set for this vtime/vmin combo
            // touts.ReadIntervalTimeout = vtime;
            // touts.ReadTotalTimeoutConstant = 0;
            // touts.ReadTotalTimeoutMultiplier = 0;
            length = min(max(vmin, available), length);
          }
          if (vmin > 0 && vtime == 0) {
            // VMIN > 0 and VTIME = 0 => blocks until VMIN characters have been
            // received
            // For reference below commented out is how timeouts are set for this vtime/vmin combo
            // touts.ReadIntervalTimeout = 0;
            // touts.ReadTotalTimeoutConstant = 0;
            // touts.ReadTotalTimeoutMultiplier = 0;
            length = min(max(vmin, available), length);
          }
        }

        if (!ResetEvent(port.m_RdOVL.hEvent)) port.fail();

        if (!ReadFile(port.m_Comm, port.m_RdBuffer, length, port.m_RdN, port.m_RdOVL)) {
          if (GetLastError() != ERROR_IO_PENDING) port.fail();
          if (WaitForSingleObject(port.m_RdOVL.hEvent, INFINITE) != WAIT_OBJECT_0) port.fail();
          if (!GetOverlappedResult(port.m_Comm, port.m_RdOVL, port.m_RdN, true)) port.fail();
        }

        port.m_RdBuffer.read(0, buffer, 0, port.m_RdN[0]);
        return port.m_RdN[0];
      } catch (Fail ie) {
        return -1;
      }
    }
  }