Repository: netty/netty
Issue: Port the RXTX transport
Labels: feature

Now that the core API got pretty stable, it's good time to port the RXTX transport to the new API.


Issue comments:
@danbim you are working on it ?

"Unfortunately" I'm on holidays, so no. I'll try to do it next week. Is that fine with you guys?

Sure!

Sent from my iPhone. Excuse any typos....

Am 11.09.2012 um 11:57 schrieb Daniel Bimschas notifications@github.com:

> "Unfortunately" I'm on holidays, so no. I'll try to do it next week. Is that fine with you guys?
> 
> —
> Reply to this email directly or view it on GitHub.

@danbim Any help I could provide on this issue?

Was done via c094abad7b14fb16827b13e5671665753be9ecad


Pull request review comments:
Can you update to 2013 ?

Can you update to 2013 ?

Javadocs please :)

Javadocs to all the methods following please :)

These must be volatile ...

Can you update to 2013 ?

Can you update to 2013 ?

Can you update to 2013 ?

Can you update to 2013 ?

I think this should be removed... no ?


Patch that resolved the issue:
diff --git a/example/pom.xml b/example/pom.xml
index 24c22d7e502..8416c11ad66 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -75,6 +75,11 @@
             <artifactId>netty-transport-udt</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netty-transport-rxtx</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
     
 </project>
diff --git a/example/src/main/java/io/netty/example/rxtx/RxtxClient.java b/example/src/main/java/io/netty/example/rxtx/RxtxClient.java
new file mode 100644
index 00000000000..5ce89de457b
--- /dev/null
+++ b/example/src/main/java/io/netty/example/rxtx/RxtxClient.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.example.rxtx;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.socket.oio.OioEventLoopGroup;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import io.netty.transport.rxtx.RxtxChannel;
+import io.netty.transport.rxtx.RxtxDeviceAddress;
+
+/**
+ * Sends one message to a serial device
+ */
+public class RxtxClient {
+
+    public static void main(String[] args) throws Exception {
+        Bootstrap b = new Bootstrap();
+        try {
+            b.group(new OioEventLoopGroup())
+             .channel(RxtxChannel.class)
+             .remoteAddress(new RxtxDeviceAddress("/dev/ttyUSB0"))
+             .handler(new ChannelInitializer<RxtxChannel>() {
+                 @Override
+                 public void initChannel(RxtxChannel ch) throws Exception {
+                     ch.pipeline().addLast(
+                         new LineBasedFrameDecoder(32768),
+                         new StringEncoder(),
+                         new StringDecoder(),
+                         new RxtxClientHandler()
+                     );
+                 }
+             });
+            
+            ChannelFuture f = b.connect().sync();
+            
+            f.channel().closeFuture().sync();
+        } finally {
+            b.shutdown();
+        }
+    }
+}
diff --git a/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java b/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java
new file mode 100644
index 00000000000..6cf07c77c09
--- /dev/null
+++ b/example/src/main/java/io/netty/example/rxtx/RxtxClientHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.example.rxtx;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundMessageHandlerAdapter;
+
+public class RxtxClientHandler extends ChannelInboundMessageHandlerAdapter<String> {
+    
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) {
+        ctx.write("AT\n");
+    }
+
+    @Override
+    protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
+        if ("OK".equals(msg)) {
+            System.out.println("Serial port responded to AT");
+        }
+        else {
+            System.out.println("Serial port responded with not-OK: " + msg);
+        }
+        ctx.close();
+    }
+}
diff --git a/pom.xml b/pom.xml
index ea635cef218..4651ba63d20 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,7 @@
     <module>codec-http</module>
     <module>codec-socks</module>
     <module>transport</module>
+    <module>transport-rxtx</module>
     <module>transport-sctp</module>
     <module>transport-udt</module>
     <module>handler</module>
@@ -106,6 +107,12 @@
         <version>2.4.1</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.rxtx</groupId>
+        <artifactId>rxtx</artifactId>
+        <version>2.1.7</version>
+      </dependency>
+
       <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>servlet-api</artifactId>
diff --git a/transport-rxtx/pom.xml b/transport-rxtx/pom.xml
new file mode 100644
index 00000000000..71e46bec3f2
--- /dev/null
+++ b/transport-rxtx/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2013 The Netty Project
+  ~
+  ~ The Netty Project licenses this file to you under the Apache License,
+  ~ version 2.0 (the "License"); you may not use this file except in compliance
+  ~ with the License. You may obtain a copy of the License at:
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+  ~ License for the specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>io.netty</groupId>
+    <artifactId>netty-parent</artifactId>
+    <version>4.0.0.Beta1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>netty-transport-rxtx</artifactId>
+  <packaging>jar</packaging>
+
+  <name>Netty/RXTX Transport</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netty-buffer</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netty-codec</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>netty-transport</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.rxtx</groupId>
+      <artifactId>rxtx</artifactId>
+    </dependency>
+  </dependencies>
+ 
+</project>
+
diff --git a/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannel.java b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannel.java
new file mode 100644
index 00000000000..263023697a4
--- /dev/null
+++ b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannel.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.transport.rxtx;
+
+import static io.netty.transport.rxtx.RxtxChannelOptions.*;
+
+import io.netty.buffer.BufType;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelConfig;
+import io.netty.channel.ChannelMetadata;
+import io.netty.channel.socket.oio.AbstractOioByteChannel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.nio.channels.NotYetConnectedException;
+
+import gnu.io.CommPort;
+import gnu.io.CommPortIdentifier;
+import gnu.io.SerialPort;
+
+/**
+ * A channel to a serial device using the RXTX library.
+ */
+public class RxtxChannel extends AbstractOioByteChannel {
+    private static final ChannelMetadata METADATA = new ChannelMetadata(BufType.BYTE, true);
+    
+    private final ChannelConfig config;
+    
+    private RxtxDeviceAddress deviceAddress;
+    private SerialPort serialPort;
+    private InputStream in;
+    private OutputStream out;
+
+    public RxtxChannel() {
+        super(null, null);
+        
+        config = new RxtxChannelConfig(this);
+    }
+
+    @Override
+    public ChannelConfig config() {
+        return config;
+    }
+
+    @Override
+    public ChannelMetadata metadata() {
+        return METADATA;
+    }
+    
+    @Override
+    public boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public boolean isActive() {
+        return in != null && out != null;
+    }
+
+    @Override
+    protected int available() {
+        try {
+            return in.available();
+        } catch (IOException e) {
+            return 0;
+        }
+    }
+
+    @Override
+    protected int doReadBytes(ByteBuf buf) throws Exception {
+        try {
+            return buf.writeBytes(in, buf.writableBytes());
+        } catch (SocketTimeoutException e) {
+            return 0;
+        }
+    }
+
+    @Override
+    protected void doWriteBytes(ByteBuf buf) throws Exception {
+        if (out == null) {
+            throw new NotYetConnectedException();
+        }
+        buf.readBytes(out, buf.readableBytes());
+    }
+
+    @Override
+    protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
+        final CommPortIdentifier cpi =
+                CommPortIdentifier.getPortIdentifier(((RxtxDeviceAddress)remoteAddress).getDeviceAddress());
+        final CommPort commPort = cpi.open(this.getClass().getName(), 1000);
+        
+        deviceAddress = (RxtxDeviceAddress) remoteAddress;
+        
+        serialPort = (SerialPort) commPort;
+        serialPort.setSerialPortParams(
+            config().getOption(BAUD_RATE),
+            config().getOption(DATA_BITS).getValue(),
+            config().getOption(STOP_BITS).getValue(),
+            config().getOption(PARITY_BIT).getValue()
+        );
+        serialPort.setDTR(config().getOption(DTR));
+        serialPort.setRTS(config().getOption(RTS));
+        
+        out = serialPort.getOutputStream();
+        in = serialPort.getInputStream();
+    }
+
+    @Override
+    protected SocketAddress localAddress0() {
+        return null;
+    }
+
+    @Override
+    protected SocketAddress remoteAddress0() {
+        return deviceAddress;
+    }
+
+    @Override
+    protected void doBind(SocketAddress localAddress) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void doDisconnect() throws Exception {
+        doClose();
+    }
+
+    @Override
+    protected void doClose() throws Exception {
+        IOException ex = null;
+        
+        try {
+            if (in != null) {
+                in.close();
+            }
+        } catch (IOException e) {
+            ex = e;
+        }
+        
+        try {
+            if (out != null) {
+                out.close();
+            }
+        } catch (IOException e) {
+            ex = e;
+        }
+        
+        if (serialPort != null) {
+            serialPort.removeEventListener();
+            serialPort.close();
+        }
+        
+        in = null;
+        out = null;
+        serialPort = null;
+        
+        if (ex != null) {
+            throw ex;
+        }
+    }
+}
diff --git a/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelConfig.java b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelConfig.java
new file mode 100644
index 00000000000..44417198bf9
--- /dev/null
+++ b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelConfig.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.transport.rxtx;
+
+import static io.netty.transport.rxtx.RxtxChannelOptions.*;
+
+import io.netty.channel.ChannelOption;
+import io.netty.channel.DefaultChannelConfig;
+
+import java.util.Map;
+
+import gnu.io.SerialPort;
+
+/**
+ * A configuration class for RXTX device connections.
+ */
+public class RxtxChannelConfig extends DefaultChannelConfig {
+
+    public enum Stopbits {
+        /**
+         * 1 stop bit will be sent at the end of every character
+         */
+        STOPBITS_1(SerialPort.STOPBITS_1),
+        /**
+         * 2 stop bits will be sent at the end of every character
+         */
+        STOPBITS_2(SerialPort.STOPBITS_2),
+        /**
+         * 1.5 stop bits will be sent at the end of every character
+         */
+        STOPBITS_1_5(SerialPort.STOPBITS_1_5);
+
+        private final int value;
+
+        Stopbits(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Stopbits ofValue(int value) {
+            for (Stopbits stopbit : Stopbits.values()) {
+                if (stopbit.value == value) {
+                    return stopbit;
+                }
+            }
+            throw new IllegalArgumentException("Unknown value for Stopbits: " + value + ".");
+        }
+    }
+
+    public enum Databits {
+        /**
+         * 5 data bits will be used for each character (ie. Baudot code)
+         */
+        DATABITS_5(SerialPort.DATABITS_5),
+        /**
+         * 6 data bits will be used for each character
+         */
+        DATABITS_6(SerialPort.DATABITS_6),
+        /**
+         * 7 data bits will be used for each character (ie. ASCII)
+         */
+        DATABITS_7(SerialPort.DATABITS_7),
+        /**
+         * 8 data bits will be used for each character (ie. binary data)
+         */
+        DATABITS_8(SerialPort.DATABITS_8);
+
+        private final int value;
+
+        Databits(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Databits ofValue(int value) {
+            for (Databits databit : Databits.values()) {
+                if (databit.value == value) {
+                    return databit;
+                }
+            }
+            throw new IllegalArgumentException("Unknown value for Databits: " + value + ".");
+        }
+    }
+
+    public enum Paritybit {
+        /**
+         * No parity bit will be sent with each data character at all
+         */
+        NONE(SerialPort.PARITY_NONE),
+        /**
+         * An odd parity bit will be sent with each data character, ie. will be set
+         * to 1 if the data character contains an even number of bits set to 1.
+         */
+        ODD(SerialPort.PARITY_ODD),
+        /**
+         * An even parity bit will be sent with each data character, ie. will be set
+         * to 1 if the data character contains an odd number of bits set to 1.
+         */
+        EVEN(SerialPort.PARITY_EVEN),
+        /**
+         * A mark parity bit (ie. always 1) will be sent with each data character
+         */
+        MARK(SerialPort.PARITY_MARK),
+        /**
+         * A space parity bit (ie. always 0) will be sent with each data character
+         */
+        SPACE(SerialPort.PARITY_SPACE);
+
+        private final int value;
+
+        Paritybit(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Paritybit ofValue(int value) {
+            for (Paritybit paritybit : Paritybit.values()) {
+                if (paritybit.value == value) {
+                    return paritybit;
+                }
+            }
+            throw new IllegalArgumentException("Unknown value for paritybit: " + value + ".");
+        }
+    }
+
+    private volatile int baudrate = 115200;
+
+    private volatile boolean dtr;
+
+    private volatile boolean rts;
+
+    private volatile Stopbits stopbits = Stopbits.STOPBITS_1;
+
+    private volatile Databits databits = Databits.DATABITS_8;
+
+    private volatile Paritybit paritybit = Paritybit.NONE;
+
+    public RxtxChannelConfig(RxtxChannel channel) {
+        super(channel);
+    }
+    
+    @Override
+    public Map<ChannelOption<?>, Object> getOptions() {
+        return getOptions(super.getOptions(),
+                          BAUD_RATE, DTR, RTS, STOP_BITS, DATA_BITS, PARITY_BIT);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T getOption(ChannelOption<T> option) {
+        if (option == BAUD_RATE) {
+            return (T) Integer.valueOf(getBaudrate());
+        }
+        if (option == DTR) {
+            return (T) Boolean.valueOf(isDtr());
+        }
+        if (option == RTS) {
+            return (T) Boolean.valueOf(isRts());
+        }
+        if (option == STOP_BITS) {
+            return (T) getStopbits();
+        }
+        if (option == DATA_BITS) {
+            return (T) getDatabits();
+        }
+        if (option == PARITY_BIT) {
+            return (T) getParitybit();
+        }
+        
+        return super.getOption(option);
+    }
+    
+    @Override
+    public <T> boolean setOption(ChannelOption<T> option, T value) {
+        validate(option, value);
+        
+        if (option == BAUD_RATE) {
+            setBaudrate((Integer) value);
+        } else if (option == DTR) {
+            setDtr((Boolean) value);
+        } else if (option == RTS) {
+            setRts((Boolean) value);
+        } else if (option == STOP_BITS) {
+            setStopbits((Stopbits) value);
+        } else if (option == DATA_BITS) {
+            setDatabits((Databits) value);
+        } else if (option == PARITY_BIT) {
+            setParitybit((Paritybit) value);
+        } else {
+            return super.setOption(option, value);
+        }
+        
+        return true;
+    }
+
+    /**
+     * Sets the baud rate (ie. bits per second) for communication with the serial device.
+     * The baud rate will include bits for framing (in the form of stop bits and parity),
+     * such that the effective data rate will be lower than this value.
+     * 
+     * @param baudrate The baud rate (in bits per second)
+     */
+    public void setBaudrate(final int baudrate) {
+        this.baudrate = baudrate;
+    }
+
+    /**
+     * Sets the number of stop bits to include at the end of every character to aid the
+     * serial device in synchronising with the data.
+     * 
+     * @param stopbits The number of stop bits to use
+     */
+    public void setStopbits(final Stopbits stopbits) {
+        this.stopbits = stopbits;
+    }
+
+    /**
+     * Sets the number of data bits to use to make up each character sent to the serial
+     * device.
+     * 
+     * @param databits The number of data bits to use
+     */
+    public void setDatabits(final Databits databits) {
+        this.databits = databits;
+    }
+
+    /**
+     * Sets the type of parity bit to be used when communicating with the serial device.
+     * 
+     * @param paritybit The type of parity bit to be used
+     */
+    public void setParitybit(final Paritybit paritybit) {
+        this.paritybit = paritybit;
+    }
+
+    /**
+     * @return The configured baud rate, defaulting to 115200 if unset
+     */
+    public int getBaudrate() {
+        return baudrate;
+    }
+
+    /**
+     * @return The configured stop bits, defaulting to {@link Stopbits#STOPBITS_1} if unset
+     */
+    public Stopbits getStopbits() {
+        return stopbits;
+    }
+
+    /**
+     * @return The configured data bits, defaulting to {@link Databits#DATABITS_8} if unset
+     */
+    public Databits getDatabits() {
+        return databits;
+    }
+
+    /**
+     * @return The configured parity bit, defaulting to {@link Paritybit#NONE} if unset
+     */
+    public Paritybit getParitybit() {
+        return paritybit;
+    }
+
+    /**
+     * @return true if the serial device should support the Data Terminal Ready signal
+     */
+    public boolean isDtr() {
+        return dtr;
+    }
+
+    /**
+     * Sets whether the serial device supports the Data Terminal Ready signal, used for
+     * flow control
+     * 
+     * @param dtr true if DTR is supported, false otherwise
+     */
+    public void setDtr(final boolean dtr) {
+        this.dtr = dtr;
+    }
+
+    /**
+     * @return true if the serial device should support the Ready to Send signal
+     */
+    public boolean isRts() {
+        return rts;
+    }
+
+    /**
+     * Sets whether the serial device supports the Request To Send signal, used for flow
+     * control
+     * 
+     * @param rts true if RTS is supported, false otherwise
+     */
+    public void setRts(final boolean rts) {
+        this.rts = rts;
+    }
+}
diff --git a/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelOptions.java b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelOptions.java
new file mode 100644
index 00000000000..ff2b928cd74
--- /dev/null
+++ b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxChannelOptions.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.transport.rxtx;
+
+import io.netty.channel.ChannelOption;
+import io.netty.transport.rxtx.RxtxChannelConfig.Databits;
+import io.netty.transport.rxtx.RxtxChannelConfig.Paritybit;
+import io.netty.transport.rxtx.RxtxChannelConfig.Stopbits;
+
+/**
+ * Options for configuring a serial port connection
+ */
+public final class RxtxChannelOptions {
+    public static final ChannelOption<Integer> BAUD_RATE =
+            new ChannelOption<Integer>("BAUD_RATE");
+    
+    public static final ChannelOption<Boolean> DTR =
+            new ChannelOption<Boolean>("DTR");
+    
+    public static final ChannelOption<Boolean> RTS =
+            new ChannelOption<Boolean>("RTS");
+    
+    public static final ChannelOption<Stopbits> STOP_BITS =
+            new ChannelOption<Stopbits>("STOP_BITS");
+    
+    public static final ChannelOption<Databits> DATA_BITS =
+            new ChannelOption<Databits>("DATA_BITS");
+    
+    public static final ChannelOption<Paritybit> PARITY_BIT =
+            new ChannelOption<Paritybit>("PARITY_BIT");
+
+    private RxtxChannelOptions() {}
+}
diff --git a/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxDeviceAddress.java b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxDeviceAddress.java
new file mode 100644
index 00000000000..d1db101436f
--- /dev/null
+++ b/transport-rxtx/src/main/java/io/netty/transport/rxtx/RxtxDeviceAddress.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package io.netty.transport.rxtx;
+
+import java.net.SocketAddress;
+
+/**
+ * A {@link SocketAddress} subclass to wrap the serial port address of a RXTX
+ * device (e.g. COM1, /dev/ttyUSB0).
+ */
+public class RxtxDeviceAddress extends SocketAddress {
+
+    private static final long serialVersionUID = -2907820090993709523L;
+
+    private final String deviceAddress;
+
+    /**
+     * Creates a RxtxDeviceAddress representing the address of the serial port.
+     *
+     * @param deviceAddress the address of the device (e.g. COM1, /dev/ttyUSB0, ...)
+     */
+    public RxtxDeviceAddress(String deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    /**
+     * @return The serial port address of the device (e.g. COM1, /dev/ttyUSB0, ...)
+     */
+    public String getDeviceAddress() {
+        return deviceAddress;
+    }
+}
diff --git a/transport-rxtx/src/main/java/io/netty/transport/rxtx/package-info.java b/transport-rxtx/src/main/java/io/netty/transport/rxtx/package-info.java
new file mode 100644
index 00000000000..98223e759ea
--- /dev/null
+++ b/transport-rxtx/src/main/java/io/netty/transport/rxtx/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * A serial and parallel port communication transport based on <a href="http://rxtx.qbang.org/">RXTX</a>.
+ */
+package io.netty.transport.rxtx;


Test patch: