/* * Copyright (c) 2012 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. * * This FreeBSD backend contributed by Denver Hull * * Many thanks for his persistence and efforts to make it happen! * */ package jtermios.freebsd; import com.sun.jna.*; import com.sun.jna.ptr.IntByReference; import java.io.File; import java.util.*; import jtermios.Pollfd; import jtermios.Termios; import jtermios.TimeVal; import static jtermios.JTermios.*; import static jtermios.JTermios.JTermiosLogging.log; public class JTermiosImpl implements jtermios.JTermios.JTermiosInterface { private static String DEVICE_DIR_PATH = "/dev/"; static C_lib_DirectMapping m_ClibDM; static C_lib m_Clib; static NonDirectCLib m_ClibND; static { Native.setPreserveLastError(true); m_ClibND = (NonDirectCLib) Native.loadLibrary(Platform.C_LIBRARY_NAME, NonDirectCLib.class); Native.register(C_lib_DirectMapping.class, NativeLibrary.getInstance(Platform.C_LIBRARY_NAME)); m_ClibDM = new C_lib_DirectMapping(); m_Clib = m_ClibDM; } public static class C_lib_DirectMapping implements C_lib { native public int pipe(int[] fds); native public int tcdrain(int fd); native public void cfmakeraw(termios termios); native public int fcntl(int fd, int cmd, int arg); native public int ioctl(int fd, int cmd, int[] arg); native public int open(String path, int flags); native public int close(int fd); native public int tcgetattr(int fd, termios termios); native public int tcsetattr(int fd, int cmd, termios termios); native public int cfsetispeed(termios termios, NativeLong i); native public int cfsetospeed(termios termios, NativeLong i); native public NativeLong cfgetispeed(termios termios); native public NativeLong cfgetospeed(termios termios); native public NativeSize write(int fd, byte[] buffer, NativeSize count); native public NativeSize read(int fd, byte[] buffer, NativeSize count); native public int tcflush(int fd, int qs); native public void perror(String msg); native public int tcsendbreak(int fd, int duration); native public int select(int n, fd_set read, fd_set write, fd_set error, timeval timeout); } public interface C_lib extends com.sun.jna.Library { public int pipe(int[] fds); public int tcdrain(int fd); public void cfmakeraw(termios termios); public int fcntl(int fd, int cmd, int arg); public int ioctl(int fd, int cmd, int[] arg); public int open(String path, int flags); public int close(int fd); public int tcgetattr(int fd, termios termios); public int tcsetattr(int fd, int cmd, termios termios); public int cfsetispeed(termios termios, NativeLong i); public int cfsetospeed(termios termios, NativeLong i); public NativeLong cfgetispeed(termios termios); public NativeLong cfgetospeed(termios termios); public NativeSize write(int fd, byte[] buffer, NativeSize count); public NativeSize read(int fd, byte[] buffer, NativeSize count); public int tcflush(int fd, int qs); public void perror(String msg); public int tcsendbreak(int fd, int duration); public int select(int n, fd_set read, fd_set write, fd_set error, timeval timeout); } public interface NonDirectCLib extends com.sun.jna.Library { public int poll(pollfd.ByReference pfds, int nfds, int timeout); } static public class timeval extends Structure { public NativeLong tv_sec; public NativeLong tv_usec; @Override protected List getFieldOrder() { return Arrays.asList(// "tv_sec",// "tv_usec"// ); } public timeval(jtermios.TimeVal timeout) { tv_sec = new NativeLong(timeout.tv_sec); tv_usec = new NativeLong(timeout.tv_usec); } } static public class pollfd extends Structure { public static class ByReference extends pollfd implements Structure.ByReference { } public int fd; public short events; public short revents; @Override protected List getFieldOrder() { return Arrays.asList(// "fd",// "events",// "revents"// ); } public pollfd() { } public pollfd(Pollfd pfd) { fd = pfd.fd; events = pfd.events; revents = pfd.revents; } } static public class fd_set extends Structure implements FDSet { private final static int NFBBITS = 32; private final static int fd_count = 1024; public int[] fd_array = new int[(fd_count + NFBBITS - 1) / NFBBITS]; @Override protected List getFieldOrder() { return Arrays.asList(// "fd_array"// ); } public void FD_SET(int fd) { fd_array[fd / NFBBITS] |= (1 << (fd % NFBBITS)); } public boolean FD_ISSET(int fd) { return (fd_array[fd / NFBBITS] & (1 << (fd % NFBBITS))) != 0; } public void FD_ZERO() { Arrays.fill(fd_array, 0); } public void FD_CLR(int fd) { fd_array[fd / NFBBITS] &= ~(1 << (fd % NFBBITS)); } } static public class termios extends Structure { public int c_iflag; public int c_oflag; public int c_cflag; public int c_lflag; public byte[] c_cc = new byte[20]; public int c_ispeed; public int c_ospeed; @Override protected List getFieldOrder() { return Arrays.asList(// "c_iflag",// "c_oflag",// "c_cflag",// "c_lflag",// "c_cc",// "c_ispeed",// "c_ospeed"// ); } public termios() { } public termios(jtermios.Termios t) { c_iflag = t.c_iflag; c_oflag = t.c_oflag; c_cflag = t.c_cflag; System.arraycopy(t.c_cc, 0, c_cc, 0, Math.min(t.c_cc.length, c_cc.length)); c_ispeed = t.c_ispeed; c_ospeed = t.c_ospeed; } public void update(jtermios.Termios t) { t.c_iflag = c_iflag; t.c_oflag = c_oflag; t.c_cflag = c_cflag; System.arraycopy(c_cc, 0, t.c_cc, 0, Math.min(t.c_cc.length, c_cc.length)); t.c_ispeed = c_ispeed; t.c_ospeed = c_ospeed; } } public JTermiosImpl() { log = log && log(1, "instantiating %s\n", getClass().getCanonicalName()); // sys/filio.h stuff FIONREAD = 0x4004667F; // fcntl.h stuff O_RDWR = 0x00000002; O_NONBLOCK = 0x00000004; O_NOCTTY = 0x00008000; O_NDELAY = 0x00000004; F_GETFL = 0x00000003; F_SETFL = 0x00000004; // errno.h stuff EAGAIN = 35; EBADF = 9; EACCES = 22; EEXIST = 17; EINTR = 4; EINVAL = 22; EIO = 5; EISDIR = 21; ELOOP = 62; EMFILE = 24; ENAMETOOLONG = 63; ENFILE = 23; ENOENT = 2; ENOSPC = 28; ENOTDIR = 20; ENXIO = 6; EOVERFLOW = 84; EROFS = 30; ENOTSUP = 45; // termios.h stuff TIOCM_RNG = 0x00000080; TIOCM_CAR = 0x00000040; IGNBRK = 0x00000001; BRKINT = 0x00000002; PARMRK = 0x00000008; INLCR = 0x00000040; IGNCR = 0x00000080; ICRNL = 0x00000100; ECHONL = 0x00000010; IEXTEN = 0x00000400; CLOCAL = 0x00008000; OPOST = 0x00000001; VSTART = 0x0000000C; TCSANOW = 0x00000000; VSTOP = 0x0000000D; VMIN = 0x00000010; VTIME = 0x00000011; VEOF = 0x00000000; TIOCMGET = 0x4004746A; TIOCM_CTS = 0x00000020; TIOCM_DSR = 0x00000100; TIOCM_RI = 0x00000080; TIOCM_CD = 0x00000040; TIOCM_DTR = 0x00000002; TIOCM_RTS = 0x00000004; ICANON = 0x00000100; ECHO = 0x00000008; ECHOE = 0x00000002; ISIG = 0x00000080; TIOCMSET = 0x8004746D; IXON = 0x00000200; IXOFF = 0x00000400; IXANY = 0x00000800; CRTSCTS = 0x00030000; TCSADRAIN = 0x00000001; INPCK = 0x00000010; ISTRIP = 0x00000020; CSIZE = 0x00000300; TCIFLUSH = 0x00000001; TCOFLUSH = 0x00000002; TCIOFLUSH = 0x00000003; CS5 = 0x00000000; CS6 = 0x00000100; CS7 = 0x00000200; CS8 = 0x00000300; CSTOPB = 0x00000400; CREAD = 0x00000800; PARENB = 0x00001000; PARODD = 0x00002000; B0 = 0; B50 = 50; B75 = 75; B110 = 110; B134 = 134; B150 = 150; B200 = 200; B300 = 300; B600 = 600; B1200 = 600; B1800 = 1800; B2400 = 2400; B4800 = 4800; B9600 = 9600; B19200 = 19200; B38400 = 38400; B7200 = 7200; B14400 = 14400; B28800 = 28800; B57600 = 57600; B76800 = 76800; B115200 = 115200; B230400 = 230400; // poll.h stuff POLLIN = 0x0001; POLLPRI = 0x0002; POLLOUT = 0x0004; POLLERR = 0x0008; POLLNVAL = 0x0020; // select.h stuff } public int errno() { return Native.getLastError(); } public void cfmakeraw(Termios termios) { termios t = new termios(termios); m_Clib.cfmakeraw(t); t.update(termios); } public int fcntl(int fd, int cmd, int arg) { return m_Clib.fcntl(fd, cmd, arg); } public int tcdrain(int fd) { return m_Clib.tcdrain(fd); } public int cfgetispeed(Termios termios) { return m_Clib.cfgetispeed(new termios(termios)).intValue(); } public int cfgetospeed(Termios termios) { return m_Clib.cfgetospeed(new termios(termios)).intValue(); } public int cfsetispeed(Termios termios, int speed) { termios t = new termios(termios); int ret = m_Clib.cfsetispeed(t, new NativeLong(speed)); t.update(termios); return ret; } public int cfsetospeed(Termios termios, int speed) { termios t = new termios(termios); int ret = m_Clib.cfsetospeed(t, new NativeLong(speed)); t.update(termios); return ret; } public int open(String s, int t) { if (s != null && !s.startsWith("/")) { s = DEVICE_DIR_PATH + s; } return m_Clib.open(s, t); } public int read(int fd, byte[] buffer, int len) { return m_Clib.read(fd, buffer, new NativeSize(len)).intValue(); } public int write(int fd, byte[] buffer, int len) { return m_Clib.write(fd, buffer, new NativeSize(len)).intValue(); } public int close(int fd) { return m_Clib.close(fd); } public int tcflush(int fd, int b) { return m_Clib.tcflush(fd, b); } public int tcgetattr(int fd, Termios termios) { termios t = new termios(); int ret = m_Clib.tcgetattr(fd, t); t.update(termios); return ret; } public void perror(String msg) { m_Clib.perror(msg); } public int tcsendbreak(int fd, int duration) { // If duration is not zero, it sends zero-valued bits for duration*N seconds, // where N is at least 0.25, and not more than 0.5. return m_Clib.tcsendbreak(fd, duration / 250); } public int tcsetattr(int fd, int cmd, Termios termios) { return m_Clib.tcsetattr(fd, cmd, new termios(termios)); } public int select(int nfds, FDSet rfds, FDSet wfds, FDSet efds, TimeVal timeout) { timeval tout = null; if (timeout != null) { tout = new timeval(timeout); } return m_Clib.select(nfds, (fd_set) rfds, (fd_set) wfds, (fd_set) efds, tout); } public int poll(Pollfd fds[], int nfds, int timeout) { if (nfds <= 0 || nfds > fds.length) { throw new java.lang.IllegalArgumentException("nfds " + nfds + " must be <= fds.length " + fds.length); } pollfd.ByReference parampfds = new pollfd.ByReference(); pollfd[] pfds = (pollfd[]) parampfds.toArray(nfds); for (int i = 0; i < nfds; i++) { pfds[i].fd = fds[i].fd; pfds[i].events = fds[i].events; } int ret = m_ClibND.poll(parampfds, nfds, timeout); for (int i = 0; i < nfds; i++) { fds[i].revents = pfds[i].revents; } return ret; } public boolean canPoll() { return true; } public FDSet newFDSet() { return new fd_set(); } public int ioctl(int fd, int cmd, int... data) { // At this time, all ioctl commands we have defined are either no parameter or 4 byte parameter. return m_Clib.ioctl(fd, cmd, data); } public List<String> getPortList() { File dir = new File(DEVICE_DIR_PATH); if (!dir.isDirectory()) { log = log && log(1, "device directory %s does not exist\n", DEVICE_DIR_PATH); return null; } String[] devs = dir.list(); LinkedList<String> list = new LinkedList<String>(); if (devs != null) { for (int i = 0; i < devs.length; i++) { String s = devs[i]; if (s.startsWith("cua") || s.startsWith("tty")) list.add(s); } } return list; } public void shutDown() { } public String getPortNamePattern() { return "^(tty\\.|cu\\.).*"; } public int setspeed(int fd, Termios termios, int speed) { int r; r = cfsetispeed(termios, speed); if (r == 0) r = cfsetospeed(termios, speed); if (r == 0) r = tcsetattr(fd, TCSANOW, termios); return r; } public int pipe(int[] fds) { return m_Clib.pipe(fds); } }