jtermios.JTermios Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of filo-firmata Show documentation
Show all versions of filo-firmata Show documentation
FiloFirmata is a client library for the Firmata protocol used with hardware project boards.
/*
* Copyright (c) 2011, Kustaa Nyholm / SpareTimeLabs
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
* contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
package jtermios;
import static jtermios.JTermios.JTermiosLogging.*;
import java.util.List;
import java.util.regex.Pattern;
import com.sun.jna.Platform;
import com.sun.jna.Structure;
import com.sun.jna.IntegerType;
import com.sun.jna.Native;
import java.util.*;
/**
* JTermios provides a limited cross platform unix termios type interface to
* serial ports.
*
* @author nyholku
*
*/
public class JTermios {
// Note About the read/write methods and the buffers
//
// This library provides read/write(byte[] buffer,int length) without an offset
// to the buffer. This is because it appears that there is a bug in JNA's use of
// ByteBuffer.wrap(byte[] buffer,int offset,int length) in that the offset gets
// ignored. So this needs to be handled in the JTermiosImpl classes
// or somewhere else. Handling the offset requires a buffer to hold
// temporarily the bytes. I deemed that it is better to pass the buck ie burden
// to the clients of JTermios as they know better what size of buffer (if any)
// is best and because then the implementation of that buffer is in one place,
// not in each of the JTermiosImpl classes. In this way Mac OS X (and presumably
// Linux/Unix) does need not a buffer at all in JTermiosImpl. Windows needs a
// JNA Memory buffer anyway because of the limitations inherent in using
// Overlapped I/O with JNA.
// The 'constants' here, which are equivalent to the corresponding #defines in C
// come from Mac OS X 10.6.6 / x86_64 architecture
// Every implementing class for each architecture needs to initialize them in
// their JTermiosImpl constructor. For Windows the termios functionality is
// totally emulated so jtermios.windows.JTermiosImpl can just use these default values as
// can obviously jtermios.macosx.JTermiosImpl (at least for x86_64 architecture).
// Much as we liked these cannot be defined 'final' but should be treated immutable all the same.
// sys/filio.h stuff
public static int FIONREAD = 0x4004667F;
// fcntl.h stuff
public static int O_RDWR = 0x00000002;
public static int O_NONBLOCK = 0x00000004;
public static int O_NOCTTY = 0x00020000;
public static int O_NDELAY = 0x00000004;
public static int O_CREAT = 0x00000200;
public static int F_GETFL = 0x00000003;
public static int F_SETFL = 0x00000004;
// errno.h stuff
public static int EAGAIN = 35;
public static int EBADF = 9;
public static int EACCES = 22;
public static int EEXIST = 17;
public static int EINTR = 4;
public static int EINVAL = 22;
public static int EIO = 5;
public static int EISDIR = 21;
public static int ELOOP = 62;
public static int EMFILE = 24;
public static int ENAMETOOLONG = 63;
public static int ENFILE = 23;
public static int ENOENT = 2;
public static int ENOSR = 98;
public static int ENOSPC = 28;
public static int ENOTDIR = 20;
public static int ENXIO = 6;
public static int EOVERFLOW = 84;
public static int EROFS = 30;
public static int ENOTSUP = 45;
public static int EBUSY = 16;
public static int ENOTTY = 25;
// termios.h stuff
public static int TIOCM_RNG = 0x00000080;
public static int TIOCM_CAR = 0x00000040;
public static int IGNBRK = 0x00000001;
public static int BRKINT = 0x00000002;
public static int IGNPAR = 0x00000004;
public static int PARMRK = 0x00000008;
public static int INLCR = 0x00000040;
public static int IGNCR = 0x00000080;
public static int ICRNL = 0x00000100;
public static int ECHONL = 0x00000010;
public static int IEXTEN = 0x00000400;
public static int CLOCAL = 0x00008000;
public static int OPOST = 0x00000001;
public static int VSTART = 0x0000000C;
public static int TCSANOW = 0x00000000;
public static int VSTOP = 0x0000000D;
public static int VMIN = 0x00000010;
public static int VTIME = 0x00000011;
public static int VEOF = 0x00000000;
public static int TIOCMGET = 0x4004746A;
public static int TIOCM_CTS = 0x00000020;
public static int TIOCM_DSR = 0x00000100;
public static int TIOCM_RI = 0x00000080;
public static int TIOCM_CD = 0x00000040;
public static int TIOCM_DTR = 0x00000002;
public static int TIOCM_RTS = 0x00000004;
public static int ICANON = 0x00000100;
public static int ECHO = 0x00000008;
public static int ECHOE = 0x00000002;
public static int ISIG = 0x00000080;
public static int TIOCMSET = 0x8004746D;
public static int IXON = 0x00000200;
public static int IXOFF = 0x00000400;
public static int IXANY = 0x00000800;
public static int CRTSCTS = 0x00030000;
public static int TCSADRAIN = 0x00000001;
public static int INPCK = 0x00000010;
public static int ISTRIP = 0x00000020;
public static int CSIZE = 0x00000300;
public static int TCIFLUSH = 0x00000001;
public static int TCOFLUSH = 0x00000002;
public static int TCIOFLUSH = 0x00000003;
public static int CS5 = 0x00000000;
public static int CS6 = 0x00000100;
public static int CS7 = 0x00000200;
public static int CS8 = 0x00000300;
public static int CSTOPB = 0x00000400;
public static int CREAD = 0x00000800;
public static int PARENB = 0x00001000;
public static int PARODD = 0x00002000;
public static int CMSPAR = 010000000000; // Is this standard ? Not available on Mac OS X
//public static int CCTS_OFLOW = 0x00010000; // Not linux
//public static int CRTS_IFLOW = 0x00020000; // Not linux
//public static int CDTR_IFLOW = 0x00040000; // Not linux
//public static int CDSR_OFLOW = 0x00080000; // Not linux
//public static int CCAR_OFLOW = 0x00100000; // Not linux
public static int B0 = 0;
public static int B50 = 50;
public static int B75 = 75;
public static int B110 = 110;
public static int B134 = 134;
public static int B150 = 150;
public static int B200 = 200;
public static int B300 = 300;
public static int B600 = 600;
public static int B1200 = 1200;
public static int B1800 = 1800;
public static int B2400 = 2400;
public static int B4800 = 4800;
public static int B9600 = 9600;
public static int B19200 = 19200;
public static int B38400 = 38400;
public static int B7200 = 7200; // Not Linux
public static int B14400 = 14400;// Not Linux
public static int B28800 = 28800;// Not Linux
public static int B57600 = 57600;
public static int B76800 = 76800; // Not Linux
public static int B115200 = 115200;
public static int B230400 = 230400;
// poll.h stuff
public static short POLLIN = 0x0001;
//public static short POLLRDNORM = 0x0040; // Not Linux
//public static short POLLRDBAND = 0x0080; // Not Linux
public static short POLLPRI = 0x0002;
public static short POLLOUT = 0x0004;
//public static short POLLWRNORM = 0x0004; // Not Linux
//public static short POLLWRBAND = 0x0100; // Not Linux
public static short POLLERR = 0x0008;
public static short POLLERR_OUT = 0x0008;
public static short POLLNVAL = 0x0020;
public static int POLLNVAL_OUT = 0x0020;
// misc stuff
public static int DC1 = 0x11; // Ctrl-Q;
public static int DC3 = 0x13; // Ctrl-S;
// reference to single arc/os specific implementation
private static JTermiosInterface m_Termios;
public interface FDSet {
public void FD_SET(int fd);
public void FD_CLR(int fd);
public boolean FD_ISSET(int fd);
public void FD_ZERO();
}
public interface JTermiosInterface {
public static class NativeSize extends IntegerType {
/**
*
*/
private static final long serialVersionUID = 2398288011955445078L;
/**
* Size of a size_t integer, in bytes.
*/
public static int SIZE = Native.SIZE_T_SIZE;//Platform.is64Bit() ? 8 : 4;
/**
* Create a zero-valued Size.
*/
public NativeSize() {
this(0);
}
/**
* Create a Size with the given value.
*/
public NativeSize(long value) {
super(SIZE, value);
}
}
public FDSet newFDSet();
int pipe(int[] fds);
void shutDown();
int errno();
int fcntl(int fd, int cmd, int arg);
int setspeed(int fd, Termios termios, int speed);
int cfgetispeed(Termios termios);
int cfgetospeed(Termios termios);
int cfsetispeed(Termios termios, int speed);
int cfsetospeed(Termios termios, int speed);
int tcflush(int fd, int b);
int tcdrain(int fd);
void cfmakeraw(Termios termios);
int tcgetattr(int fd, Termios termios);
int tcsetattr(int fd, int cmd, Termios termios);
int tcsendbreak(int fd, int duration);
int open(String s, int t);
int close(int fd);
int write(int fd, byte[] buffer, int len);
int read(int fd, byte[] buffer, int len);
int ioctl(int fd, int cmd, int... data);
int select(int n, FDSet read, FDSet write, FDSet error, TimeVal timeout);
int poll(Pollfd[] fds, int nfds, int timeout);
/**
* poll() on Windows has not been implemented and while implemented on
* Mac OS X, does not work for devices.
*/
boolean canPoll();
void perror(String msg);
List getPortList();
public String getPortNamePattern();
}
public void shutdown() {
if (m_Termios != null)
m_Termios.shutDown();
}
static { // INSTANTIATION
if (Platform.isMac()) {
m_Termios = new jtermios.macosx.JTermiosImpl();
} else if (Platform.isWindows()) {
m_Termios = new jtermios.windows.JTermiosImpl();
} else if (Platform.isLinux()) {
m_Termios = new jtermios.linux.JTermiosImpl();
} else if (Platform.isSolaris()) {
m_Termios = new jtermios.solaris.JTermiosImpl();
} else if (Platform.isFreeBSD()) {
m_Termios = new jtermios.freebsd.JTermiosImpl();
} else {
log(0, "JTermios has no support for OS %s\n", System.getProperty("os.name"));
}
}
static public int errno() {
log = log && log(5, "> errno()\n");
int ret = m_Termios.errno();
log = log && log(3, "< errno() => %d\n", ret);
return ret;
}
static public int fcntl(int fd, int cmd, int arg) {
log = log && log(5, "> fcntl(%d, %d, %d)\n", fd, cmd, arg);
int ret = m_Termios.fcntl(fd, cmd, arg);
log = log && log(3, "< fcntl(%d, %d, %d) => %d\n", fd, cmd, arg, ret);
return ret;
}
static public int cfgetispeed(Termios termios) {
log = log && log(5, "> cfgetispeed(%s)\n", termios);
int ret = m_Termios.cfgetispeed(termios);
log = log && log(3, "< cfgetispeed(%s) => %d\n", termios, ret);
return ret;
}
static public int cfgetospeed(Termios termios) {
log = log && log(5, "> cfgetospeed(%s)\n", termios);
int ret = m_Termios.cfgetospeed(termios);
log = log && log(3, "< cfgetospeed(%s) => %d\n", termios, ret);
return ret;
}
static public int cfsetispeed(Termios termios, int speed) {
log = log && log(5, "> cfgetospeed(%s,%d)\n", termios, speed);
int ret = m_Termios.cfsetispeed(termios, speed);
log = log && log(3, "< cfgetospeed(%s,%d) => %d\n", termios, speed, ret);
return ret;
}
static public int cfsetospeed(Termios termios, int speed) {
log = log && log(5, "> cfgetospeed(%s,%d)\n", termios, speed);
int ret = m_Termios.cfsetospeed(termios, speed);
log = log && log(3, "< cfgetospeed(%s,%d) => %d\n", termios, speed, ret);
return ret;
}
static public int setspeed(int fd, Termios termios, int speed) {
log = log && log(5, "> setspeed(%d,%s,%d)\n", fd, termios, speed);
int ret = m_Termios.setspeed(fd, termios, speed);
log = log && log(3, "< setspeed(%d,%s,%d) => %d\n", fd, termios, speed, ret);
return ret;
}
static public int tcflush(int a, int b) {
log = log && log(5, "> tcflush(%d,%d)\n", a, b);
int ret = m_Termios.tcflush(a, b);
log = log && log(3, "< tcflush(%d,%d) => %d\n", a, b, ret);
return ret;
}
static public int tcdrain(int fd) {
log = log && log(5, "> tcdrain(%d)\n", fd);
int ret = m_Termios.tcdrain(fd);
log = log && log(3, "< tcdrain(%d) => %d\n", fd, ret);
return ret;
}
static public void cfmakeraw(int fd, Termios termios) {
log = log && log(5, "> cfmakeraw(%d,%s)\n", fd, termios);
m_Termios.cfmakeraw(termios);
log = log && log(3, "< cfmakeraw(%d,%s)\n", fd, termios);
}
static public int tcgetattr(int fd, Termios termios) {
log = log && log(5, "> tcgetattr(%d,%s)\n", fd, termios);
int ret = m_Termios.tcgetattr(fd, termios);
log = log && log(3, "< tcgetattr(%d,%s) => %d\n", fd, termios, ret);
return ret;
}
static public int tcsetattr(int fd, int cmd, Termios termios) {
log = log && log(5, "> tcsetattr(%d,%d,%s)\n", fd, cmd, termios);
int ret = m_Termios.tcsetattr(fd, cmd, termios);
log = log && log(3, "< tcsetattr(%d,%d,%s) => %d\n", fd, cmd, termios, ret);
return ret;
}
static public int tcsendbreak(int fd, int duration) {
log = log && log(5, "> tcsendbreak(%d,%d,%s)\n", fd, duration);
int ret = m_Termios.tcsendbreak(fd, duration);
log = log && log(3, "< tcsendbreak(%d,%d,%s) => %d\n", fd, duration, ret);
return ret;
}
static public int open(String s, int t) {
log = log && log(5, "> open('%s',%08X)\n", s, t);
int ret = m_Termios.open(s, t);
log = log && log(3, "< open('%s',%08X) => %d\n", s, t, ret);
return ret;
}
static public int close(int fd) {
log = log && log(5, "> close(%d)\n", fd);
int ret = m_Termios.close(fd);
log = log && log(3, "< close(%d) => %d\n", fd, ret);
return ret;
}
static public int write(int fd, byte[] buffer, int len) {
log = log && log(5, "> write(%d,%s,%d)\n", fd, log(buffer, 8), len);
int ret = m_Termios.write(fd, buffer, len);
log = log && log(3, "< write(%d,%s,%d) => %d\n", fd, log(buffer, 8), len, ret);
return ret;
}
static public int read(int fd, byte[] buffer, int len) {
log = log && log(5, "> read(%d,%s,%d)\n", fd, log(buffer, 8), len);
int ret = m_Termios.read(fd, buffer, len);
log = log && log(3, "< read(%d,%s,%d) => %d\n", fd, log(buffer, 8), len, ret);
return ret;
}
static public int ioctl(int fd, int cmd, int... data) {
log = log && log(5, "> ioctl(%d,%d,[%s])\n", fd, cmd, Arrays.toString(data));
int ret = m_Termios.ioctl(fd, cmd, data);
log = log && log(3, "< ioctl(%d,%d,[%s]) => %d\n", fd, cmd, Arrays.toString(data), ret);
return ret;
}
private static String toString(int n, FDSet fdset) {
StringBuffer s = new StringBuffer("[");
for (int fd = 0; fd < n; fd++) {
if (fd > 0)
s.append(",");
if (FD_ISSET(fd, fdset))
s.append(Integer.toString(fd));
}
s.append("]");
return s.toString();
}
/**
* Unlike Linux select this does not modify 'timeout' so it can be re-used.
*
*/
static public int select(int n, FDSet read, FDSet write, FDSet error, TimeVal timeout) {
log = log && log(5, "> select(%d,%s,%s,%s,%s)\n", n, toString(n, read), toString(n, write), toString(n, error), timeout);
int ret = m_Termios.select(n, read, write, error, timeout);
log = log && log(3, "< select(%d,%s,%s,%s,%s) => %d\n", n, toString(n, read), toString(n, write), toString(n, error), timeout, ret);
return ret;
}
static public int poll(Pollfd[] fds, int nfds, int timeout) {
log = log && log(5, "> poll(%s,%d,%d)\n", log(fds, 8), nfds, timeout);
int ret = m_Termios.poll(fds, nfds, timeout);
log = log && log(3, "< poll(%s,%d,%d) => %d\n", log(fds, 8), nfds, timeout, ret);
return ret;
}
static public boolean canPoll() {
return m_Termios.canPoll();
}
static public int pipe(int[] fds) {
log = log && log(5, "> pipe([%d,%d,%d])\n", fds.length, fds[0], fds[1]);
int ret = m_Termios.pipe(fds);
log = log && log(3, "< pipe([%d,%d,%d]) => %d\n", fds.length, fds[0], fds[1], ret);
return ret;
}
static public void perror(String msg) {
m_Termios.perror(msg);
}
static public FDSet newFDSet() {
return m_Termios.newFDSet();
}
static public void FD_SET(int fd, FDSet set) {
if (set != null)
set.FD_SET(fd);
}
static public void FD_CLR(int fd, FDSet set) {
if (set != null)
set.FD_CLR(fd);
}
static public boolean FD_ISSET(int fd, FDSet set) {
if (set == null)
return false;
return set.FD_ISSET(fd);
}
static public void FD_ZERO(FDSet set) {
if (set != null)
set.FD_ZERO();
}
static public List getPortList() {
return m_Termios.getPortList();
}
static public Pattern getPortNamePattern(jtermios.JTermios.JTermiosInterface jtermios) {
String ps = System.getProperty("purejavacomm.portnamepattern." + jtermios.getClass().getName());
if (ps == null)
ps = System.getProperty("purejavacomm.portnamepattern");
if (ps == null)
ps = jtermios.getPortNamePattern();
return Pattern.compile(ps);
}
public static class JTermiosLogging {
private static int LOG_MASK = 1;
public static boolean log = false;
static { // initialization
String loglevel = System.getProperty("purejavacomm.loglevel");
if (loglevel != null)
setLogLevel(Integer.parseInt(loglevel));
}
public static String lineno() {
return lineno(0);
}
public static String lineno(int n) {
StackTraceElement e = Thread.currentThread().getStackTrace()[2 + n];
return String.format("class %s line% d", e.getClassName(), e.getLineNumber());
}
public static String ref(Structure struct) {
if (struct == null)
return "null";
else
return struct.getPointer().toString();
}
public static String log(byte[] bts, int n) {
StringBuffer b = new StringBuffer();
if (n < 0 || n > bts.length)
n = bts.length;
b.append(String.format("[%d", bts.length));
for (int i = 0; i < n; i++)
b.append(String.format(",0x%02X", bts[i]));
if (n < bts.length)
b.append("...");
b.append("]");
return b.toString();
}
public static String log(int[] ints, int n) {
StringBuffer b = new StringBuffer();
if (n < 0 || n > ints.length)
n = ints.length;
b.append(String.format("[%d", ints.length));
for (int i = 0; i < n; i++)
b.append(String.format(",0x%08X", ints[i]));
if (n < ints.length)
b.append("...");
b.append("]");
return b.toString();
}
public static String log(char[] bts, int n) {
StringBuffer b = new StringBuffer();
if (n < 0 || n > bts.length)
n = bts.length;
b.append(String.format("[%d", bts.length));
for (int i = 0; i < n; i++)
b.append(String.format(",%c", bts[i]));
if (n < bts.length)
b.append("...");
b.append("]");
return b.toString();
}
public static String log(Object[] bts, int n) {
StringBuffer b = new StringBuffer();
if (n < 0 || n > bts.length)
n = bts.length;
b.append(String.format("[%d", bts.length));
for (int i = 0; i < n; i++) {
b.append(",");
b.append(bts[i] != null ? bts[i].toString() : "null");
}
if (n < bts.length)
b.append("...");
b.append("]");
return b.toString();
}
static private StringBuffer buffer = new StringBuffer();
static public boolean log(int l, String format, Object... args) {
if (l == 0 || LOG_MASK != 0) {
synchronized (buffer) {
buffer.setLength(0);
if ((LOG_MASK & (1 << (5))) != 0)
buffer.append(String.format("%06d,", System.currentTimeMillis() % 1000000));
if ((LOG_MASK & (1 << (6))) != 0) {
buffer.append(lineno(2));
buffer.append(", ");
}
if ((LOG_MASK & (1 << (7))) != 0) {
buffer.append("thread id ");
buffer.append(Thread.currentThread().getId());
buffer.append(", ");
buffer.append(Thread.currentThread().getName());
buffer.append(", ");
}
if (l == 0 || (LOG_MASK & (1 << (l - 1))) != 0)
buffer.append(String.format(format, args));
if (buffer.length() > 0) {
System.err.printf("log: " + buffer.toString());
}
}
}
return true;
}
public static void setLogLevel(int l) {
LOG_MASK = 0;
for (int i = 0; i < l; i++) {
LOG_MASK = (LOG_MASK << 1) + 1;
}
log = LOG_MASK != 0;
}
public static void setLogMask(int mask) {
LOG_MASK = mask;
log = LOG_MASK != 0;
}
}
}