You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by jv...@apache.org on 2011/03/24 12:35:28 UTC
svn commit: r1084906 [1/2] - in /mina/sandbox/jvermillard/mina-modbus: ./
src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/mina/ src/main/java/org/apache/mina/modbus/
src/main/java/org/apache/mina/modb...
Author: jvermillard
Date: Thu Mar 24 11:35:26 2011
New Revision: 1084906
URL: http://svn.apache.org/viewvc?rev=1084906&view=rev
Log:
modbus stack need to fix test case and add javadoc
Added:
mina/sandbox/jvermillard/mina-modbus/pom.xml (with props)
mina/sandbox/jvermillard/mina-modbus/src/
mina/sandbox/jvermillard/mina-modbus/src/main/
mina/sandbox/jvermillard/mina-modbus/src/main/java/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/
mina/sandbox/jvermillard/mina-modbus/src/test/java/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderTest.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoderTest.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/tcp/
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoderMasterTest.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoderTest.java (with props)
mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoderTest.java (with props)
Modified:
mina/sandbox/jvermillard/mina-modbus/ (props changed)
Propchange: mina/sandbox/jvermillard/mina-modbus/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Mar 24 11:35:26 2011
@@ -0,0 +1 @@
+target
Added: mina/sandbox/jvermillard/mina-modbus/pom.xml
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/pom.xml?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/pom.xml (added)
+++ mina/sandbox/jvermillard/mina-modbus/pom.xml Thu Mar 24 11:35:26 2011
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF 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>
+
+ <groupId>org.apache.mina</groupId>
+ <version>2.0.3-SNAPSHOT</version>
+ <artifactId>mina-modbus</artifactId>
+ <name>Apache MINA Modbus stack</name>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <symbolicName>${project.groupId}.modbus</symbolicName>
+ <exportedPackage>${project.groupId}.modbus</exportedPackage>
+ </properties>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ <source>1.5</source>
+ <target>1.5</target>
+ <debug>true</debug>
+ <optimize>true</optimize>
+ <showDeprecations>true</showDeprecations>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.7.1</version>
+ <configuration>
+ <excludes>
+ <exclude>**/Abstract*</exclude>
+ <exclude>**/*RegressionTest*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.1.2</version>
+ <executions>
+ <execution>
+ <id>attach-source</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.2.0</version>
+ <inherited>true</inherited>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${symbolicName}</Bundle-SymbolicName>
+ <Export-Package>${exportedPackage}.*;version=${project.version}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mina-core</artifactId>
+ <version>2.0.2</version>
+ <type>bundle</type>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+
+
Propchange: mina/sandbox/jvermillard/mina-modbus/pom.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus;
+
+public interface ModbusConstants {
+ public static final int READ_DISCRETE_INPUTS = 02;
+
+ public static final int READ_COILS = 01;
+
+ public static final int WRITE_SINGLE_COILS = 05;
+
+ public static final int WRITE_MULTIPLE_COILS = 15;
+
+ public static final int READ_INPUT_REGISTERS = 04;
+
+ public static final int READ_HOLDING_REGISTERS = 03;
+
+ public static final int WRITE_SINGLE_REGISTER = 06;
+
+ public static final int WRITE_MULTIPLE_REGISTERS = 16;
+
+ public static final int READ_WRITE_MULTIPLE_REGISTERS = 23;
+
+ public static final int MASK_WRITE_REGISTER = 22;
+
+ public static final int READ_FIFO_QUEUE = 24;
+
+ public static final int READ_FILE_RECORD = 20;
+
+ public static final int WRITE_FILE_RECORD = 21;
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusConstants.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus;
+
+import org.apache.mina.core.service.IoConnector;
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.modbus.msg.ModbusMessage;
+import org.apache.mina.modbus.transport.ModbusTransport;
+import org.apache.mina.modbus.transport.rtu.RTUModbusMessage;
+import org.apache.mina.modbus.transport.rtu.RTUModbusTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class ModbusSlave {
+
+ private String name;
+
+ private ModbusTable table;
+
+ private boolean forceInitCard = false;
+
+ private Logger log;
+
+ private Handler handler = new Handler();
+
+ private ModbusTransport transport;
+
+ private Integer deviceId;
+
+ /**
+ * @param name
+ * @param hostname
+ * @param port
+ * @param table
+ */
+ public ModbusSlave(String name, ModbusTable table, ModbusTransport transport) {
+ this(name, null, table, transport);
+ }
+
+ public ModbusSlave(String name, Integer deviceId, ModbusTable table, ModbusTransport transport) {
+ super();
+ this.name = name;
+ this.deviceId = deviceId;
+ this.table = table;
+ this.transport = transport;
+ log = LoggerFactory.getLogger(ModbusSlave.class);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ IoConnector connector = null;
+
+ public void start() {
+ table.start();
+ transport.connect(handler);
+ }
+
+ public void stop() {
+
+ }
+
+ private class Handler implements IoHandler {
+
+ public Handler() {
+
+ }
+
+ public void sessionCreated(IoSession session) throws Exception {
+ session.getFilterChain().addLast("protocolCodec", new ProtocolCodecFilter(new ProtocolCodecFactory() {
+
+ public ProtocolDecoder getDecoder(IoSession session) {
+ return transport.createDecoder(false);
+ }
+
+ public ProtocolEncoder getEncoder(IoSession session) {
+ return transport.createEncoder();
+ }
+ }));
+
+ }
+
+ public void sessionOpened(IoSession session) throws Exception {
+ log.info("Connection opened : " + session.getRemoteAddress());
+
+ if (forceInitCard && (transport instanceof RTUModbusTransport)) {
+ session.write(new RTUModbusMessage(1, ModbusConstants.READ_COILS));
+ }
+ }
+
+ public void sessionClosed(IoSession session) throws Exception {
+ log.info("Connection closed : " + session.getRemoteAddress());
+ if (transport instanceof RTUModbusTransport) {
+ transport.connect(handler);
+ }
+ }
+
+ public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
+ return;
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
+ log.error("Exception : ", cause);
+ session.close(true);
+ }
+
+ public void messageReceived(IoSession session, Object message) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("RCVD : " + message);
+ }
+ if (message instanceof ModbusMessage) {
+
+ ModbusMessage msg = (ModbusMessage) message;
+ if ((deviceId != null) && (msg.getDevice() != deviceId)) {
+ return;
+ }
+ if ((msg.getFunctionCode() == ModbusConstants.READ_HOLDING_REGISTERS)
+ || (msg.getFunctionCode() == ModbusConstants.READ_INPUT_REGISTERS)) {
+
+ ModbusMessage reply = transport.createReplyMessage(msg);
+
+ // reading some words
+ int add = ((msg.getData()[0] & 0xff) << 8) + (msg.getData()[1] & 0xff);
+ int count = (msg.getData()[2] << 8) + ((msg.getData()[3]) & 0xFF);
+ if (isQuantityValidToRead(count)) {
+ if (!checkError || table.canAccessDataToRead(add, count)) {
+ byte[] res = new byte[count * 2 + 1];
+ res[0] = (byte) (count * 2);
+ for (int i = 0; i < count; i++) {
+ int word = table.readWord(add + i);
+ res[i * 2 + 1] = (byte) (word >> 8);
+ res[i * 2 + 2] = (byte) (word & 0xFF);
+ }
+
+ // sendback
+ reply.setData(res);
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x02 });
+ }
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x03 });
+ }
+
+ session.write(reply);
+
+ } else if (msg.getFunctionCode() == ModbusConstants.WRITE_SINGLE_REGISTER) {
+
+ ModbusMessage reply = transport.createReplyMessage(msg);
+
+ // writing a word
+ int add = ((msg.getData()[0] & 0xFF) << 8) + (msg.getData()[1] & 0xFF);
+ int value = ((msg.getData()[2] & 0xFF) << 8) + ((msg.getData()[3]) & 0xFF);
+ if (isValueValid(value)) {
+ if (!checkError || table.canAccessDataToWrite(add, 1)) {
+ table.writeWord(add, value);
+
+ // sendback
+ reply.setData(msg.getData());
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x02 });
+ }
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x03 });
+ }
+ session.write(reply);
+
+ } else if (msg.getFunctionCode() == ModbusConstants.WRITE_MULTIPLE_REGISTERS) {
+
+ // writing multiple words
+ int add = ((msg.getData()[0] & 0xFF) << 8) + (msg.getData()[1] & 0xFF);
+ int count = (msg.getData()[2] << 8) + ((msg.getData()[3]) & 0xFF);
+ int byteCount = msg.getData()[4];
+ // reply
+ ModbusMessage reply = transport.createReplyMessage(msg);
+ boolean validity = isQuantityValidToWrite(count, byteCount);
+ boolean accessOK = false;
+ if (validity) {
+ accessOK = !checkError || table.canAccessDataToWrite(add, count);
+ if (accessOK) {
+ reply.setData(new byte[] { msg.getData()[0], msg.getData()[1], msg.getData()[2],
+ msg.getData()[3] });
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x02 });
+ }
+ } else {
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x03 });
+ }
+ session.write(reply);
+
+ if (validity && accessOK) {
+ for (int i = 0; i < count; i++) {
+ // inverted MSB/LSB
+ table.writeWord(add + i, ((msg.getData()[5 + (i * 2)] & 0xFF) << 8)
+ + (((msg.getData()[5 + (i * 2) + 1]) & 0xFF)));
+ }
+ }
+ } else {
+ if (checkError) {
+ // reply Error message function code unsupported
+ ModbusMessage reply = transport.createReplyMessage(msg);
+ reply.setFunctionCode(reply.getFunctionCode() + 0x80);
+ reply.setData(new byte[] { 0x01 });
+ session.write(reply);
+ }
+ }
+ }
+ }
+
+ public void messageSent(IoSession session, Object message) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("SENT : " + message);
+ }
+ }
+ }
+
+ public void setForceInitCard(boolean forceInitCard) {
+ this.forceInitCard = forceInitCard;
+ }
+
+ private boolean isValueValid(int value) {
+ if ((value >= 0) && (value <= 0xFFFF)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isQuantityValidToWrite(int quantity, int byteCount) {
+ if (!checkError || ((quantity > 0) && (quantity <= 0x7B) && (byteCount == quantity * 2))) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isQuantityValidToRead(int quantity) {
+ if (!checkError || ((quantity > 0) && (quantity <= 0x7D))) {
+ return true;
+ }
+ return false;
+ }
+
+ boolean checkError = false;
+
+ public void enableCheckError() {
+ checkError = true;
+ }
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusSlave.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus;
+
+/**
+ * A modbus table. This table is a slave and reply with values to the request of the master.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ *
+ */
+public interface ModbusTable {
+
+ public void writeWord(int address, int value);
+
+ public int readWord(int address);
+
+ public void writeCoil(int address, boolean value);
+
+ public boolean readCoil(int address);
+
+ public boolean canAccessDataToRead(int addressStart, int count);
+
+ public boolean canAccessDataToWrite(int addressStart, int count);
+
+ public void start();
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/ModbusTable.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.msg;
+
+public interface ModbusMessage {
+
+ public int getDevice();
+
+ public int getFunctionCode();
+
+ public void setFunctionCode(int functionCode);
+
+ public byte[] getData();
+
+ public void setData(byte[] data);
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/msg/ModbusMessage.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport;
+
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.modbus.msg.ModbusMessage;
+
+public interface ModbusTransport {
+ ProtocolEncoder createEncoder();
+
+ ProtocolDecoder createDecoder(boolean master);
+
+ void connect(IoHandler handler);
+
+ ModbusMessage createReplyMessage(ModbusMessage query);
+
+ ModbusMessage createMessage(int functionCode, int unitId);
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/ModbusTransport.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.rtu;
+
+import org.apache.log4j.Logger;
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderException;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.mina.modbus.ModbusConstants;
+import org.apache.mina.modbus.transport.rtu.RTUModbusMessage.CRCException;
+
+public class RTUModbusDecoder extends CumulativeProtocolDecoder {
+
+ private static final Logger LOG = Logger.getLogger("RTUModbusDecoder");
+
+ private boolean master;
+
+ public RTUModbusDecoder(boolean master) {
+ this.master = master;
+ }
+
+ @Override
+ protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
+
+ in.order(ByteOrder.BIG_ENDIAN);
+
+ int startPos = in.position();
+ boolean isDecoded = false;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("doDecode bytes : " + in);
+ }
+
+ if (in.remaining() < 2) {
+ in.position(startPos);
+ return false;
+ }
+
+ if (master) {
+ isDecoded = decodeReply(in, out);
+ } else {
+ isDecoded = decodeQuery(in, out);
+ }
+
+ if (isDecoded) {
+ return true;
+ }
+
+ in.position(startPos);
+ return false;
+ }
+
+ private boolean decodeReply(IoBuffer in, ProtocolDecoderOutput out) throws CRCException, ProtocolDecoderException {
+
+ RTUModbusMessage msg;
+
+ int startPos = in.position();
+
+ int function = in.getUnsigned(startPos + 1);
+
+ // check for Modbus error
+ if ((function & 0x80) > 0) {
+ int fct = function - 0x80;
+ switch (fct) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found a modbus error message");
+ }
+
+ msg = new RTUModbusMessage(in, 5);
+ //decode
+ out.write(msg);
+ return true;
+
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+ switch (function) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+
+ if (in.remaining() < 3) {
+ return false;
+ }
+
+ int dataLen = in.getUnsigned(startPos + 2);
+ if (in.remaining() < dataLen + 5) {
+ return false;
+ }
+
+ msg = new RTUModbusMessage(in, dataLen + 5);
+ //decode
+ out.write(msg);
+ return true;
+
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+ // fixed len
+ if (in.remaining() < 8) {
+ return false;
+ }
+
+ msg = new RTUModbusMessage(in, 8);
+ //decode
+ out.write(msg);
+ return true;
+
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+ private boolean decodeQuery(IoBuffer in, ProtocolDecoderOutput out) throws CRCException, ProtocolDecoderException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decode a query : " + in);
+ }
+ int startPos = in.position();
+
+ int function = in.getUnsigned(startPos + 1);
+
+ RTUModbusMessage msg;
+ switch (function) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ // fixed len
+ if (in.remaining() < 8) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data");
+ }
+ return false;
+ }
+
+ msg = new RTUModbusMessage(in, 8);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decoded a Modbus query : " + msg);
+ }
+ out.write(msg);
+
+ return true;
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+
+ if (in.remaining() < 7) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data");
+ }
+ return false;
+ }
+
+ int dataLen = in.getUnsigned(startPos + 6);
+
+ if (in.remaining() < dataLen + 9) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data : remaining " + in.remaining() + " was expecting " + (dataLen + 9));
+ }
+ return false;
+ }
+
+ msg = new RTUModbusMessage(in, dataLen + 9);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decoded a Modbus multiple query : " + msg);
+ }
+ //decode
+ out.write(msg);
+
+ return true;
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.rtu;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderException;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RTUModbusEncoder implements ProtocolEncoder {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RTUModbusEncoder.class);
+
+ public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws ProtocolEncoderException {
+ if (message instanceof RTUModbusMessage) {
+ IoBuffer buf = ((RTUModbusMessage) message).encode();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Out bytes : " + buf.getHexDump());
+ }
+
+ out.write(buf);
+
+ } else {
+ throw new ProtocolEncoderException("Unknow message type : " + message.getClass().getName());
+ }
+ }
+
+ public void dispose(IoSession session) throws Exception {
+ }
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.rtu;
+
+import java.nio.ByteOrder;
+import java.security.InvalidParameterException;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.modbus.msg.ModbusMessage;
+
+
+public class RTUModbusMessage implements ModbusMessage {
+
+ private int functionCode;
+
+ private byte[] data;
+
+ private int device;
+
+ public RTUModbusMessage(int device, int functioncode) {
+ this(device, functioncode, new byte[] {});
+ }
+
+ public RTUModbusMessage(int device, int functioncode, byte[] data) {
+ this.device = device;
+ this.functionCode = functioncode;
+ this.data = data;
+ }
+
+ /**
+ * decode a buffer and create the PDU, test the CRC
+ * @param buffer
+ * @throws crc exception if the crc is incorrect
+ */
+ public RTUModbusMessage(IoBuffer buffer, int length) throws CRCException {
+ ByteOrder oldOrder = buffer.order();
+ int pduStart = buffer.position();
+
+ buffer.order(ByteOrder.BIG_ENDIAN);
+ device = buffer.getUnsigned(); // 1 Byte device code
+ functionCode = buffer.getUnsigned(); // 1 Byte function code
+ data = new byte[length - 4];
+ buffer.get(data, 0, data.length);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ int calculatedCRC = getCrc(buffer, pduStart, pduStart + length - 2);
+
+ int crc = buffer.getUnsignedShort(); // 2 byte CRC
+
+ if (crc != calculatedCRC) {
+ throw new CRCException("Invalid CRC, need " + calculatedCRC + " and got " + crc + ", Dump : "
+ + buffer.getHexDump());
+ }
+
+ buffer.order(oldOrder);
+ }
+
+ public int getFunctionCode() {
+ return functionCode;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public int getDevice() {
+ return device;
+ }
+
+ /**
+ * create a buffer encoding this PDU
+ * @return a new pooled ByteBuffer
+ */
+ public IoBuffer encode() {
+ IoBuffer buff = IoBuffer.allocate(4 + data.length);
+ buff.order(ByteOrder.BIG_ENDIAN);
+ buff.put((byte) device);
+ buff.put((byte) functionCode);
+ buff.put(data);
+ buff.order(ByteOrder.LITTLE_ENDIAN);
+ buff.putShort((short) getCrc(buff, 0, buff.position()));
+ buff.order(ByteOrder.BIG_ENDIAN);
+ return buff.flip();
+ }
+
+ public class CRCException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public CRCException(String message) {
+ super(message);
+ }
+
+ }
+
+ private int getCrc(IoBuffer buf, int start, int end) {
+
+ int oldPos = buf.position();
+ buf.position(start);
+
+ if (buf.position() < end) {
+ int crc = 0xFFFF;
+ while (buf.position() < end) {
+ crc ^= (buf.get() & 0xFF);
+ for (int j = 0; j < 8; j++) {
+ boolean bitOne = ((crc & 0x1) == 0x1);
+ crc >>>= 1;
+ if (bitOne) {
+ crc ^= 0x0000A001;
+ }
+ }
+ }
+ buf.position(oldPos);
+ return (crc);
+ } else {
+ throw new InvalidParameterException("Invalid start (" + start + ") and end (" + end + ")");
+ }
+ }
+
+ @Override
+ public String toString() {
+ String dataStr = "{";
+ byte[] d = getData();
+ for (int i = 0; i < d.length; i++) {
+ dataStr += (d[i] & 0xFF);
+ if ((i + 1) < d.length) {
+ dataStr += ",";
+ }
+ }
+ dataStr += "}";
+ return "RTUModbusMessage {dev=" + getDevice() + ",func=" + getFunctionCode() + ",data = " + dataStr + " }";
+ }
+
+ public void setFunctionCode(int functionCode) {
+ this.functionCode = functionCode;
+ }
+}
\ No newline at end of file
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusMessage.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.rtu;
+
+import java.net.InetSocketAddress;
+
+import org.apache.mina.core.RuntimeIoException;
+import org.apache.mina.core.future.ConnectFuture;
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.modbus.msg.ModbusMessage;
+import org.apache.mina.modbus.transport.ModbusTransport;
+import org.apache.mina.transport.socket.SocketConnector;
+import org.apache.mina.transport.socket.nio.NioSocketConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class RTUModbusTransport implements ModbusTransport {
+
+ private String hostname;
+
+ private int port;
+
+ private Logger log = LoggerFactory.getLogger(RTUModbusTransport.class);
+
+ public RTUModbusTransport(String hostname, int port) {
+ this.hostname = hostname;
+ this.port = port;
+ }
+
+ public ProtocolDecoder createDecoder(boolean master) {
+ return new RTUModbusDecoder(master);
+ }
+
+ public ProtocolEncoder createEncoder() {
+ return new RTUModbusEncoder();
+ }
+
+ private SocketConnector connector;
+
+ private IoSession session;
+
+ public void connect(final IoHandler handler) {
+ // create connection thread
+ Thread cnxThread = new Thread("ModbusConnection") {
+ @Override
+ public void run() {
+
+ connector = new NioSocketConnector();
+ connector.setHandler(handler);
+
+ while ((session == null) || !session.isConnected()) {
+ try {
+ ConnectFuture future = connector.connect(new InetSocketAddress(hostname, port));
+ future.awaitUninterruptibly();
+ session = future.getSession();
+ } catch (RuntimeIoException e) {
+ log.error("Exception while connecting : ", e);
+ }
+
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e1) {
+ log.error("Exception : ", e1);
+ }
+ }
+
+ }
+ };
+ cnxThread.start();
+
+ }
+
+ public ModbusMessage createReplyMessage(ModbusMessage query) {
+ RTUModbusMessage msg = (RTUModbusMessage) query;
+ return new RTUModbusMessage(msg.getDevice(), msg.getFunctionCode());
+ }
+
+ public ModbusMessage createMessage(int functionCode, int device) {
+ return new RTUModbusMessage(device, functionCode);
+ }
+
+}
\ No newline at end of file
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/rtu/RTUModbusTransport.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.tcp;
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderException;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.mina.modbus.ModbusConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TCPModbusDecoder extends CumulativeProtocolDecoder {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TCPModbusDecoder.class);
+
+ private boolean master;
+
+ public TCPModbusDecoder(boolean master) {
+ this.master = master;
+ }
+
+ @Override
+ protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
+
+ in.order(ByteOrder.BIG_ENDIAN);
+
+ int startPos = in.position();
+ boolean isDecoded = false;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("doDecode bytes : " + in);
+ }
+
+ if ((in.remaining() < 8)) {
+ in.position(startPos);
+ return false;
+ }
+
+ if (master) {
+ isDecoded = decodeReply(in, out);
+ } else {
+ isDecoded = decodeQuery(in, out);
+ }
+
+ if (isDecoded) {
+ return true;
+ }
+
+ in.position(startPos);
+ return false;
+ }
+
+ @SuppressWarnings("unused")
+ private boolean decodeReply(IoBuffer in, ProtocolDecoderOutput out) throws ProtocolDecoderException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decode a reply : " + in);
+ }
+ int startPos = in.position();
+
+ in.order(ByteOrder.BIG_ENDIAN);
+
+ // ModBus Application Protocol header
+
+ int transaction = in.getUnsignedShort(startPos + 0);
+ int protocolId = in.getUnsignedShort(startPos + 2);
+ int length = in.getUnsignedShort(startPos + 4);
+ int unitId = in.getUnsigned(startPos + 6);
+
+ // Start of pdu
+ int function = in.getUnsigned(startPos + 7);
+
+ TCPModbusMessage msg;
+
+ // check for Modbus error
+ if ((function & 0x80) > 0) {
+ if (length != 3) {
+ throw new ProtocolDecoderException("Incoherent value with a frame length and PDU length");
+ }
+ int fct = function - 0x80;
+ switch (fct) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found a modbus error message");
+ }
+
+ msg = new TCPModbusMessage(in);
+ //decode
+ out.write(msg);
+ return true;
+
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+ switch (function) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+
+ if (in.remaining() < 9) {
+ return false;
+ }
+
+ int dataLen = in.getUnsigned(startPos + 8);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Length (Unit Id + PDU) : " + length + " Byte Count : " + dataLen);
+ }
+ if (length != dataLen + 3) {
+ throw new ProtocolDecoderException("Incoherent value with a frame length and PDU length");
+ }
+
+ if (in.remaining() < dataLen + 9) {
+ return false;
+ }
+
+ msg = new TCPModbusMessage(in);
+ //decode
+ out.write(msg);
+ return true;
+
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+ // fixed len
+ if (length != 6) {
+ throw new ProtocolDecoderException("Incoherent value with a frame length and PDU length");
+ }
+
+ if (in.remaining() < 12) {
+ return false;
+ }
+
+ msg = new TCPModbusMessage(in);
+ //decode
+ out.write(msg);
+ return true;
+
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private boolean decodeQuery(IoBuffer in, ProtocolDecoderOutput out) throws ProtocolDecoderException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decode a query : " + in);
+ }
+ int startPos = in.position();
+
+ in.order(ByteOrder.BIG_ENDIAN);
+
+ // ModBus Application Protocol header
+ int transaction = in.getUnsignedShort(startPos + 0);
+ int protocolId = in.getUnsignedShort(startPos + 2);
+ int length = in.getUnsignedShort(startPos + 4);
+ int unitId = in.getUnsigned(startPos + 6);
+
+ // Start of pdu
+ int function = in.getUnsigned(startPos + 7);
+
+ TCPModbusMessage msg;
+ switch (function) {
+ case ModbusConstants.READ_HOLDING_REGISTERS:
+ case ModbusConstants.READ_INPUT_REGISTERS:
+ case ModbusConstants.WRITE_SINGLE_REGISTER:
+ if (length != 6) {
+ throw new ProtocolDecoderException("Incoherent value with a frame length and PDU length");
+ }
+ // fixed len
+ if (in.remaining() < 12) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data");
+ }
+ return false;
+ }
+
+ msg = new TCPModbusMessage(in);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decoded a Modbus query : " + msg);
+ }
+ out.write(msg);
+
+ return true;
+ case ModbusConstants.WRITE_MULTIPLE_REGISTERS:
+
+ if (in.remaining() < 13) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data");
+ }
+ return false;
+ }
+
+ int dataLen = in.getUnsigned(startPos + 12);
+
+ if (length != dataLen + 7) {
+ throw new ProtocolDecoderException("Incoherent value with a frame length and PDU length");
+ }
+
+ if (in.remaining() < dataLen + 13) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("no enougth data : remaining " + in.remaining() + " was expecting " + (dataLen + 13));
+ }
+ return false;
+ }
+
+ msg = new TCPModbusMessage(in);//, dataLen + 9);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decoded a Modbus multiple query : " + msg);
+ }
+ //decode
+ out.write(msg);
+
+ return true;
+ default:
+ throw new ProtocolDecoderException("Unknown data");
+ }
+ }
+
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusDecoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.tcp;
+
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderException;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+
+public class TCPModbusEncoder implements ProtocolEncoder {
+
+ public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws ProtocolEncoderException {
+ if (message instanceof TCPModbusMessage) {
+ IoBuffer buf = ((TCPModbusMessage) message).encode();
+ out.write(buf);
+ } else {
+ throw new ProtocolEncoderException("Unknow message type : " + message.getClass().getName());
+ }
+
+ }
+
+ public void dispose(IoSession session) throws Exception {
+
+ }
+
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusEncoder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.tcp;
+
+import java.nio.ByteOrder;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.modbus.msg.ModbusMessage;
+
+public class TCPModbusMessage implements ModbusMessage {
+
+ // modbus variables
+ private int functionCode;
+
+ public void setFunctionCode(int functionCode) {
+ this.functionCode = functionCode;
+ }
+
+ private byte[] data;
+
+ // TCP Modbus variables
+ private int transactionIdentifier;
+
+ private int protocolIdentifier = 0;
+
+ private int unitId;
+
+ public int getUnitId() {
+ return unitId;
+ }
+
+ public TCPModbusMessage(int transactionIdentifier, int functionCode, int unitId) {
+ this.transactionIdentifier = transactionIdentifier;
+ // this.protocolIdentifier = protocolIdentifier;
+ this.functionCode = functionCode;
+ this.unitId = unitId;
+ }
+
+ public TCPModbusMessage(IoBuffer buffer) {
+ ByteOrder oldOrder = buffer.order();
+ buffer.order(ByteOrder.BIG_ENDIAN);
+
+ transactionIdentifier = buffer.getUnsignedShort();
+ protocolIdentifier = buffer.getUnsignedShort();
+ int length = buffer.getUnsignedShort();
+ unitId = buffer.getUnsigned();
+
+ functionCode = buffer.getUnsigned(); // 1 Byte function code
+ data = new byte[length - 2];
+ buffer.get(data);
+
+ buffer.order(oldOrder);
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public int getFunctionCode() {
+ return functionCode;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public int getTransactionIdentifier() {
+ return transactionIdentifier;
+ }
+
+ public int getProtocolIdentifier() {
+ return protocolIdentifier;
+ }
+
+ /**
+ * create a buffer encoding this PDU
+ * @return a new pooled ByteBuffer
+ */
+ public IoBuffer encode() {
+ IoBuffer buff = IoBuffer.allocate(8 + data.length);
+ buff.order(ByteOrder.BIG_ENDIAN);
+
+ buff.putShort((short) transactionIdentifier);
+ buff.putShort((short) protocolIdentifier);
+ buff.putShort((short) (2 + data.length));
+ buff.put((byte) unitId);
+ buff.put((byte) getFunctionCode());
+ buff.put(data);
+ return buff.flip();
+ }
+
+ @Override
+ public String toString() {
+ String data = "{";
+ byte[] d = getData();
+ for (int i = 0; i < d.length; i++) {
+ data += (d[i] & 0xFF);
+ if ((i + 1) < d.length) {
+ data += ",";
+ }
+ }
+ data += "}";
+ return "TCPModbusMessage {transact=" + getTransactionIdentifier() + ",protocol=" + getProtocolIdentifier()
+ + ",unitId=" + getUnitId() + ",func=" + getFunctionCode() + ",data = " + data + " }";
+ }
+
+ public int getDevice() {
+ return unitId;
+ }
+
+}
\ No newline at end of file
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusMessage.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.tcp;
+
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.apache.mina.core.service.IoHandler;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.modbus.msg.ModbusMessage;
+import org.apache.mina.modbus.transport.ModbusTransport;
+import org.apache.mina.transport.socket.SocketAcceptor;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TCPModbusTransport implements ModbusTransport {
+
+ private int transactionIdentifier = 0;
+
+ private int port;
+
+ private Logger logger = LoggerFactory.getLogger(TCPModbusTransport.class);
+
+ public TCPModbusTransport(int port) {
+ this.port = port;
+ }
+
+ public void connect(IoHandler handler) {
+ SocketAcceptor acceptor = new NioSocketAcceptor();
+ acceptor.setReuseAddress(true);
+ acceptor.setHandler(handler);
+ try {
+ acceptor.bind(new InetSocketAddress(port));
+ } catch (IOException e) {
+ logger.error("Exception while binding TCP port", e);
+ }
+ }
+
+ public ProtocolDecoder createDecoder(boolean master) {
+ return new TCPModbusDecoder(master);
+ }
+
+ public ProtocolEncoder createEncoder() {
+ return new TCPModbusEncoder();
+ }
+
+ public ModbusMessage createReplyMessage(ModbusMessage query) {
+ TCPModbusMessage msg = (TCPModbusMessage) query;
+ TCPModbusMessage reply = new TCPModbusMessage(msg.getTransactionIdentifier(), msg.getFunctionCode(), msg
+ .getUnitId());
+ return reply;
+ }
+
+ public ModbusMessage createMessage(int functionCode, int unitId) {
+ return new TCPModbusMessage(((int) transactionIdentifier++ % Integer.MAX_VALUE), functionCode, unitId);
+ }
+
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/main/java/org/apache/mina/modbus/transport/tcp/TCPModbusTransport.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java
URL: http://svn.apache.org/viewvc/mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java?rev=1084906&view=auto
==============================================================================
--- mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java (added)
+++ mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java Thu Mar 24 11:35:26 2011
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.mina.modbus.transport.rtu;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.filter.codec.ProtocolCodecSession;
+import org.apache.mina.filter.codec.ProtocolDecoderException;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.apache.mina.modbus.ModbusConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class RTUModbusDecoderMasterTest extends TestCase {
+ RTUModbusDecoder decoder = new RTUModbusDecoder(true);
+
+ ProtocolCodecSession session = new ProtocolCodecSession();
+ ProtocolDecoderOutput out = session.getDecoderOutput();
+
+ static final Logger LOG = LoggerFactory.getLogger(RTUModbusDecoderMasterTest.class);
+
+ public void testDecodeOneFrame() throws Exception {
+ LOG.info("Decode one frame");
+ // write single register at address 1 and value 50, reply
+ RTUModbusMessage msg = new RTUModbusMessage(1, 6, new byte[] { (byte) 0, (byte) 1, (byte) 0, (byte) 50 });
+ IoBuffer buff = msg.encode();
+
+ // Test one decode and one output
+ IoBuffer in = IoBuffer.allocate(100);
+ in.put(buff); // put
+ in.flip();
+ decoder.decode(session, in, out);
+ Assert.assertEquals(1, session.getDecoderOutputQueue().size());
+ }
+
+ public void testDecodeOneModbusErrorFrame() throws Exception {
+ LOG.info("Decode one frame");
+ // write single register error, reply
+ RTUModbusMessage msg = new RTUModbusMessage(1, 6 + 0x80, new byte[] { (byte) 1 });
+ IoBuffer buff = msg.encode();
+
+ // Test one decode and one output
+ IoBuffer in = IoBuffer.allocate(100);
+ in.put(buff); // put
+ in.flip();
+ decoder.decode(session, in, out);
+ Assert.assertEquals(1, session.getDecoderOutputQueue().size());
+ }
+
+ public void testRejectBuggedFrame() throws Exception {
+ LOG.info("Reject bugged frame");
+ // 4 bytes frame
+ IoBuffer in = IoBuffer.allocate(10);
+ in.putChar('A'); // some crap
+ in.putChar('B');
+ in.flip();
+ //System.err.println("frame size : "+in.remaining());
+ // in.putChar('C');
+ // in.putChar('x');
+ boolean exception = false;
+ try {
+ decoder.decode(session, in, out);
+ } catch (ProtocolDecoderException e) {
+ exception = true;
+ }
+ Assert.assertTrue(exception);
+ Assert.assertEquals(0, session.getDecoderOutputQueue().size());
+
+ // 2 bytes frame
+ in = IoBuffer.allocate(10);
+ in.put((byte) 0); //
+ in.put((byte) ModbusConstants.READ_HOLDING_REGISTERS);
+ in.flip();
+ // no exceptions
+ decoder.decode(session, in, out);
+ Assert.assertEquals(0, session.getDecoderOutputQueue().size());
+ }
+
+ public void testRejectCorruptedFrame() throws Exception {
+ LOG.info("Reject corrupted frame");
+ // write single register at address 1 and value 50, reply
+ RTUModbusMessage msg = new RTUModbusMessage(1, 6, new byte[] { (byte) 0, (byte) 1, (byte) 0, (byte) 50 });
+ IoBuffer buff = msg.encode();
+
+ // Test one decode and one output
+ IoBuffer in = IoBuffer.allocate(100);
+ in.put(buff); // put
+ in.put(3, (byte) 56); // some crap
+ in.flip();
+ Exception ex = null;
+ try {
+ decoder.decode(session, in, out);
+ } catch (RTUModbusMessage.CRCException e) {
+ ex = e;
+ }
+ Assert.assertNotNull(ex);
+ Assert.assertEquals(0, session.getDecoderOutputQueue().size());
+
+ }
+
+ public void testAcceptMultiFrame() throws Exception {
+ LOG.info("Accept multi frame");
+ // write single register at address 1 and value 50, reply
+ RTUModbusMessage msg = new RTUModbusMessage(1, 16, new byte[] { (byte) 0, (byte) 1, (byte) 0, (byte) 50 });
+ IoBuffer buff = msg.encode();
+
+ // Test one decode and one output
+ IoBuffer in = IoBuffer.allocate(100);
+ in.put(buff);
+ in.flip();
+ decoder.decode(session, in, out);
+ Assert.assertEquals(1, session.getDecoderOutputQueue().size());
+
+ in = IoBuffer.allocate(100);
+ buff.flip(); // re-put
+ in.put(buff);
+ in.flip();
+ decoder.decode(session, in, out);
+ Assert.assertEquals(2, session.getDecoderOutputQueue().size());
+ }
+
+ public void testFragmentation() throws Exception {
+ LOG.info("Fragmentation");
+
+ // Read multiple register at address 1 and 10 values
+ RTUModbusMessage msgWrite10 = new RTUModbusMessage(1, ModbusConstants.READ_HOLDING_REGISTERS, new byte[] {
+ (byte) 20, (byte) 0, (byte) 1, (byte) 0, (byte) 2, (byte) 0, (byte) 3, (byte) 0, (byte) 4, (byte) 0,
+ (byte) 5, (byte) 0, (byte) 6, (byte) 0, (byte) 7, (byte) 0, (byte) 8, (byte) 0, (byte) 9, (byte) 0,
+ (byte) 10 });
+
+ // Read multiple register at address 1 and 5 values
+ RTUModbusMessage msgWrite5 = new RTUModbusMessage(1, ModbusConstants.READ_HOLDING_REGISTERS, new byte[] {
+ (byte) 10, (byte) 0, (byte) 1, (byte) 0, (byte) 2, (byte) 0, (byte) 3, (byte) 0, (byte) 4, (byte) 0,
+ (byte) 5 });
+
+ // Read multiple register at address 1 and 4 values
+ RTUModbusMessage msgWrite4 = new RTUModbusMessage(1, ModbusConstants.WRITE_MULTIPLE_REGISTERS, new byte[] {
+ (byte) 1, (byte) 0, (byte) 2, (byte) 0 });
+
+ IoBuffer buffPDU1 = msgWrite10.encode();
+ IoBuffer buffPDU2 = msgWrite5.encode();
+ IoBuffer buffPDU3 = msgWrite4.encode();
+ IoBuffer buffPDU123 = IoBuffer.allocate(buffPDU1.remaining() * 2 + buffPDU2.remaining()
+ + buffPDU3.remaining());
+ buffPDU123.put(buffPDU1);
+
+ buffPDU123.put(buffPDU2);
+ buffPDU123.put(buffPDU3);
+ buffPDU1.rewind();
+ buffPDU123.put(buffPDU1);
+ buffPDU123.flip(); // PDU123 = PDU1 + PDU2 + PDU3 + PDU1
+
+ buffPDU1.flip();
+ buffPDU2.flip();
+
+ // dezcode a plain buffer
+ decoder.decode(session, buffPDU1, out);
+ Assert.assertEquals(1, session.getDecoderOutputQueue().size());
+ buffPDU1.rewind();
+
+ IoBuffer buff1 = IoBuffer.allocate(4);
+ while (buff1.hasRemaining()) {
+ buff1.put(buffPDU1.get());
+ }
+
+ buff1.flip();
+ // decode a part of a PDU
+ decoder.decode(session, buff1, out);
+
+ IoBuffer buff2 = IoBuffer.allocate(buffPDU1.remaining());
+ while (buffPDU1.hasRemaining()) {
+ buff2.put(buffPDU1.get());
+ }
+ buff2.flip();
+
+ // decode the second part
+ decoder.decode(session, buff2, out);
+
+ Assert.assertEquals(2, session.getDecoderOutputQueue().size());
+
+ // decode four concatenated big PDU
+ decoder.decode(session, buffPDU123, out);
+ Assert.assertEquals(6, session.getDecoderOutputQueue().size());
+
+ // decode multiple PDU each byte per each byte
+ buffPDU123.rewind();
+ while (buffPDU123.hasRemaining()) {
+ IoBuffer bufOneByte = IoBuffer.allocate(1);
+ bufOneByte.put(buffPDU123.get());
+ bufOneByte.flip();
+ decoder.decode(session, bufOneByte, out);
+ }
+ Assert.assertEquals(10, session.getDecoderOutputQueue().size());
+
+ RTUModbusMessage msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite10));
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite10));
+
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite10));
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite5));
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite4));
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite10));
+ msg = (RTUModbusMessage) session.getDecoderOutputQueue().poll();
+ Assert.assertTrue(samePDU(msg, msgWrite10));
+
+ }
+
+ private boolean samePDU(RTUModbusMessage msg1, RTUModbusMessage msg2) {
+ if (msg1.getDevice() != msg2.getDevice()) {
+ return false;
+ }
+ if (msg1.getFunctionCode() != msg2.getFunctionCode()) {
+ return false;
+ }
+ if (!Arrays.equals(msg1.getData(), msg2.getData())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public void testRandomPDU() {
+ LOG.info("Random PDU rejection");
+ Random rng = new Random();
+ for (int i = 0; i < 50; i++) {
+
+ IoBuffer buggedBuff = IoBuffer.allocate(8 + rng.nextInt(12));
+
+ while (buggedBuff.remaining() > 0) {
+ buggedBuff.put((byte) rng.nextInt());
+ }
+ buggedBuff.flip();
+ //System.err.println("random buffer of len : "+buggedBuff.remaining());
+ try {
+ decoder.decode(session, buggedBuff, out);
+ } catch (Exception ex) {
+ }
+ Assert.assertEquals(0, session.getDecoderOutputQueue().size());
+ }
+ }
+
+ public void testByteInsertion() {
+ LOG.info("Insert one byte before PDU");
+ RTUModbusMessage msg = new RTUModbusMessage(1, 6, new byte[] { (byte) 0, (byte) 1, (byte) 0, (byte) 50 });
+ IoBuffer pduBuff = msg.encode();
+
+ IoBuffer buff = IoBuffer.allocate(pduBuff.remaining() + 1);
+ // add a zero before the PCU
+ buff.put((byte) 0);
+ buff.put(pduBuff);
+ buff.flip();
+ boolean exception = false;
+ try {
+ decoder.decode(session, buff, out);
+ } catch (Exception ex) {
+ exception = true;
+ }
+ Assert.assertEquals(0, session.getDecoderOutputQueue().size());
+ Assert.assertTrue(exception);
+ }
+
+}
Propchange: mina/sandbox/jvermillard/mina-modbus/src/test/java/org/apache/mina/modbus/transport/rtu/RTUModbusDecoderMasterTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain