[zb4osgi-changeset] [scm] ZigBee 4 OSGi repository change: r407 - in /projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl: ./ src/ src/main/ src/main/assembly/ src/main/java/ src/main/java/es/ src/main/java/es/unizar/ src/main/java/es/unizar/howlab/ src/main/java/es/unizar/howlab/core/ src/main/java/es/unizar/howlab/core/zigbee/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/ src/main/resources/ src/main/resources/es/ src/main/resources/es/unizar/ src/main/resources/es/unizar/howlab/ src/main/resources/es/unizar/howlab/core/ src/main/resources/es/unizar/howlab/core/zigbee/ src/main/resources/es/unizar/howlab/core/zigbee/telegesis/ src/main/resources/es/unizar/howlab/core/zigbee/telegesis/gateway/ src/test/ src/test/java/ src/test/java/es/ src/test/java/es/unizar/ src/test/java/es/unizar/howlab/ src/test/java/es/unizar/howlab/core/ src/test/java/es/unizar/howlab/core/zigbee/ src/test/java/es/unizar/howlab/core/zigbee/telegesis/ src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/ src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/

scm-notify at zb4osgi.aaloa.org scm-notify at zb4osgi.aaloa.org
Thu Feb 2 13:18:52 CET 2012


Author: alvaro.marco
Date: Thu Feb  2 13:18:52 2012
New Revision: 407

Log:
howlab import

Added:
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/LICENSE
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/nbactions.xml
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/pom.xml
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/assembly/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/assembly/felix.xml
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/AbstractGateway.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/GatewayFactoryImpl.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/SerialListener.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/Activator.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/SerialConnectionServiceTracker.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Command305.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/ErrorCode305.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Prompt305.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/SpecialSequence305.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/LICENSE
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/gateway/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/CnxListenerTest.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeGatewayListener.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeSerialPort.java
    projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305Test.java

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/LICENSE
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/LICENSE (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/LICENSE Thu Feb  2 13:18:52 2012
@@ -1,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/nbactions.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/nbactions.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/nbactions.xml Thu Feb  2 13:18:52 2012
@@ -1,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<actions>
+    <action>
+        <actionName>run</actionName>
+        <goals>
+            <goal>package</goal>
+            <goal>antrun:run</goal>
+        </goals>
+        <activatedProfiles>
+            <activatedProfile>run-on-felix</activatedProfile>
+        </activatedProfiles>
+        <properties>
+                <skipTests>true</skipTests>
+            </properties>
+    </action>
+    <action>
+        <actionName>debug</actionName>
+        <goals>
+            <goal>package</goal>
+            <goal>antrun:run</goal>
+        </goals>
+        <properties>
+            <vm.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address}</vm.args>
+            <jpda.listen>true</jpda.listen>
+        </properties>
+        <activatedProfiles>
+            <activatedProfile>run-on-felix</activatedProfile>
+        </activatedProfiles>
+    </action>
+    <action>
+        <actionName>profile</actionName>
+        <goals>
+            <goal>package</goal>
+            <goal>antrun:run</goal>
+        </goals>
+        <properties>
+            <vm.args>${profiler.args}</vm.args>
+            <!-- XXX <java jvm="${profiler.java}" ...> -->
+            <profiler.action>profile</profiler.action>
+        </properties>
+        <activatedProfiles>
+            <activatedProfile>run-on-felix</activatedProfile>
+        </activatedProfiles>
+    </action>
+    <action>
+            <actionName>build</actionName>
+            <goals>
+                <goal>install</goal>
+            </goals>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </action>
+    <action>
+            <actionName>rebuild</actionName>
+            <goals>
+                <goal>clean</goal>
+                <goal>install</goal>
+            </goals>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </action>
+    <action>
+            <actionName>build-with-dependencies</actionName>
+            <reactor>also-make</reactor>
+            <goals>
+                <goal>install</goal>
+            </goals>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </action>
+    <action>
+            <actionName>CUSTOM-Prepare a Release</actionName>
+            <displayName>Prepare a Release</displayName>
+            <goals>
+                <goal>release:prepare</goal>
+            </goals>
+        </action>
+    <action>
+            <actionName>CUSTOM-Perform a Release</actionName>
+            <displayName>Perform a Release</displayName>
+            <goals>
+                <goal>release:perform</goal>
+            </goals>
+        </action>
+</actions>

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/pom.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/pom.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/pom.xml Thu Feb  2 13:18:52 2012
@@ -1,0 +1,266 @@
+
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>es.unizar.howlab.core.zigbee.telegesis</groupId>
+    <artifactId>telegesis-gateway-impl</artifactId>
+    <version>1.5-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>telegesis-gateway-impl OSGi Bundle</name>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0, January 2004</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+        </license>
+    </licenses>    
+
+	<!-- Añadir ruta developer, estableciendo la ruta al trunk: -->
+    <scm>
+        <developerConnection>scm:svn:https://web.hermes.cps.unizar.es/repos/howlab/Software/core/zigbee/telegesis/gateway-impl/trunk</developerConnection>    
+    </scm>
+
+<!-- Añadir distribution management (en el settings.xml tenemos que tener el usuario y contraseña para el id en el server: -->
+    <distributionManagement>
+        <repository>
+            <uniqueVersion>false</uniqueVersion>
+            <id>repo_nas_rel</id>
+            <url>ftp://howlab.dyndns.org/repo/software/releases/</url>
+            <layout>default</layout>
+        </repository>
+        <snapshotRepository>
+            <uniqueVersion>false</uniqueVersion>
+            <id>repo_nas_snap</id>
+            <url>ftp://howlab.dyndns.org/repo/software/snapshots</url>
+            <layout>default</layout>
+        </snapshotRepository> 
+    </distributionManagement>
+        <!-- Añadir los repositorios para poder localizar otros proyectos generados: -->
+    <repositories>
+        <repository>
+            <id>repo_nas_rel</id>
+            <url>ftp://howlab.dyndns.org/repo/software/releases/</url>
+        </repository>
+        <repository>
+            <id>repo_nas_snap</id>
+            <url>ftp://howlab.dyndns.org/repo/software/snapshots</url>
+        </repository>
+    </repositories>
+    
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <version>4.2.0</version>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+            <version>1.1.1</version>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>es.unizar.howlab.core</groupId>
+            <artifactId>easyJavaLib</artifactId>
+            <version>1.6</version>
+            <type>bundle</type>
+        </dependency>
+        <dependency>
+            <groupId>es.unizar.howlab.core.zigbee.telegesis</groupId>
+            <artifactId>telegesis-gateway-api</artifactId>
+            <version>1.3</version>
+            <type>bundle</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.2.0</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>es.unizar.howlab.core.zigbee.telegesis.gateway.impl.osgi.Activator</Bundle-Activator>
+                        <Export-Package>es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol</Export-Package>
+                        <Private-Package>es.unizar.howlab.core.zigbee.telegesis.gateway.impl.*</Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+<!-- Añadir pluggin maven-release-plugin  -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.2.1</version>
+            </plugin>                
+        </plugins>
+
+	<!-- Añadir extensiones wagon para que se pueda acceder al respositorio de distribucion por ftp -->
+        <extensions> 
+            <extension> 
+                <groupId>org.apache.maven.wagon</groupId> 
+                <artifactId>wagon-ftp</artifactId> 
+                <version>1.0</version>                 
+            </extension>
+        </extensions>     
+    </build>
+
+    <profiles>
+        <profile>
+            <id>build-for-felix</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.apache.felix.main</artifactId>
+                    <version>3.0.7</version>
+                    <scope>provided</scope>
+                </dependency>
+                <!-- To include a shell:
+                <dependency>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.apache.felix.gogo.shell</artifactId>
+                    <version>0.6.1</version>
+                </dependency>
+                -->
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.6</version>
+                        <executions>
+                            <execution>
+                                <id>compile</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <pathconvert property="plugins.jars" pathsep="${path.separator}">
+                                            <path refid="maven.runtime.classpath" />
+                                            <map from="${project.build.directory}${file.separator}classes" to="" />
+                                        </pathconvert>
+                                        <pathconvert pathsep=" " property="bundles">
+                                            <path path="${plugins.jars}" />
+                                            <mapper>
+                                                <chainedmapper>
+                                                    <flattenmapper />
+                                                    <globmapper from="*" to="file:modules/*" casesensitive="no" />
+                                                </chainedmapper>
+                                            </mapper>
+                                        </pathconvert>
+                                        <propertyfile file="${project.build.directory}/config.properties">
+                                            <entry key="felix.auto.start" value="${bundles} file:modules/${project.build.finalName}.jar" />
+                                            <entry key="org.osgi.framework.bootdelegation" value="*" />
+                                        </propertyfile>
+                                        <copy file="${maven.dependency.org.apache.felix.org.apache.felix.main.jar.path}" tofile="${project.build.directory}/felix.jar" />
+                                    </target>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <version>2.2</version>
+                        <executions>
+                            <execution>
+                                <id>create-executable-jar</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>single</goal>
+                                </goals>
+                                <configuration>
+                                    <descriptors>
+                                        <descriptor>${basedir}/src/main/assembly/felix.xml</descriptor>
+                                    </descriptors>
+                                    <finalName>${project.build.finalName}</finalName>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>run-on-felix</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.apache.felix.main</artifactId>
+                    <version>3.0.7</version>
+                    <scope>provided</scope>
+                </dependency>
+                <!-- esto habilita el uso de common-loggings -->
+                <dependency>
+                    <groupId>org.ops4j.pax.logging</groupId>
+                    <artifactId>pax-logging-api</artifactId>
+                    <version>1.6.3</version>                   
+                </dependency>
+                <!-- org.apache.felix:org.apache.felix.gogo.shell:0.6.1 useless from Maven since stdin is swallowed -->
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.6</version>
+                        <configuration>
+                            <target>
+                                <property name="vm.args" value="" />
+                                <pathconvert property="plugins.jars" pathsep="${path.separator}">
+                                    <path refid="maven.runtime.classpath" />
+                                    <map from="${project.build.directory}${file.separator}classes" to="" />
+                                </pathconvert>
+                                <makeurl property="urls" separator=" ">
+                                    <path path="${plugins.jars}" />
+                                    <path location="${project.build.directory}/${project.build.finalName}.jar" />
+                                </makeurl>
+                                <propertyfile file="${project.build.directory}/run.properties">
+                                    <entry key="felix.auto.start" value="${urls}" />
+                                    <entry key="felix.auto.deploy.action" value="uninstall,install,update,start" />
+                                    <entry key="org.osgi.framework.storage" value="${project.build.directory}${file.separator}felix-cache" />
+                                    <entry key="org.osgi.framework.bootdelegation" value="*" />
+                                </propertyfile>
+                                <makeurl property="run.properties.url" file="${project.build.directory}/run.properties" />
+                                <java fork="true" jar="${maven.dependency.org.apache.felix.org.apache.felix.main.jar.path}">
+                                    <sysproperty key="felix.config.properties" value="${run.properties.url}" />
+                                    <jvmarg line="${vm.args}" />
+                                </java>
+                            </target>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/assembly/felix.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/assembly/felix.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/assembly/felix.xml Thu Feb  2 13:18:52 2012
@@ -1,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly>
+ <id>all</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <dependencySets>
+    <dependencySet>
+        <useProjectArtifact>false</useProjectArtifact>
+        <outputDirectory>modules</outputDirectory>
+        <excludes>
+          <exclude>org.apache.felix:org.apache.felix.main</exclude>
+        </excludes>
+    </dependencySet>
+  </dependencySets>
+  <files>
+    <file>
+      <source>${project.build.directory}/${project.build.finalName}.jar</source>
+      <outputDirectory>modules</outputDirectory>
+    </file>
+    <file>
+      <source>${project.build.directory}/felix.jar</source>
+      <outputDirectory>bin</outputDirectory>
+    </file>
+    <file>
+      <source>${project.build.directory}/config.properties</source>
+      <outputDirectory>conf</outputDirectory>
+    </file>
+  </files>
+</assembly>

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/AbstractGateway.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/AbstractGateway.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/AbstractGateway.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,855 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import es.unizar.howlab.core.io.serial.SerialConnection;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.GatewayListener;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.TelegesisErrorException;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.ZigbeeDeviceType;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.*;
+import es.unizar.howlab.easyjavalib.threading.Locker;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Abstract implementation of class Gateway
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public abstract class AbstractGateway implements Gateway {
+    // Logger
+
+    private Log logger = LogFactory.getLog(this.getClass().getName());
+    // ProductID
+    protected String deviceName = "";
+    protected String firmwareRevision = "";
+    protected String dongleAddress = "";
+
+    @Override
+    abstract public String[] getProductId();
+
+    @Override
+    abstract public void reset();
+
+    @Override
+    abstract public void restoreFactoryDefaults();
+
+    @Override
+    abstract public String readRegister(short regAddress) throws TelegesisErrorException;
+
+    @Override
+    abstract public boolean readRegisterBit(short regAddress, short bitNumber) throws TelegesisErrorException;
+
+    @Override
+    abstract public void writeRegister(short regAddress, String regData) throws TelegesisErrorException;
+
+    @Override
+    abstract public void writeRegisterBit(short regAddress, short bitNumber, boolean bitData) throws TelegesisErrorException;
+
+    @Override
+    abstract public void writeRegister(short regAddress, String regData, String password) throws TelegesisErrorException;
+
+    @Override
+    abstract public void writeRegisterBit(short regAddress, short bitNumber, boolean bitData, String password) throws TelegesisErrorException;
+
+    @Override
+    abstract public short readRemoteRegisterRequest(String EUI64Addr, short regAddress) throws TelegesisErrorException;
+
+    @Override
+    abstract public short readRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber) throws TelegesisErrorException;
+
+    @Override
+    abstract public short writeRemoteRegisterRequest(String EUI64Addr, short regAddress, String regData) throws TelegesisErrorException;
+
+    @Override
+    abstract public short writeRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber, boolean bitData) throws TelegesisErrorException;
+
+    @Override
+    abstract public short writeRemoteRegisterRequest(String EUI64Addr, short regAddress, String regData, String password) throws TelegesisErrorException;
+
+    @Override
+    abstract public short writeRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber, boolean bitData, String password) throws TelegesisErrorException;
+
+    @Override
+    abstract public short[] scanEnergy() throws TelegesisErrorException;
+
+    @Override
+    abstract public PANScanResult[] scanForActivePANs() throws TelegesisErrorException;
+
+    @Override
+    abstract public NetworkJoinedInfo createNetwork() throws TelegesisErrorException;
+
+    @Override
+    abstract public NetworkJoinedInfo joinNetwork() throws TelegesisErrorException;
+
+    @Override
+    abstract public NetworkJoinedInfo joinNetwork(int channel, String PID) throws TelegesisErrorException;
+
+    @Override
+    abstract public void leaveNetwork() throws TelegesisErrorException;
+
+    @Override
+    abstract public short leaveNetworkRequest(String address) throws TelegesisErrorException;
+
+    @Override
+    abstract public NetworkInformation getNetworkInformation();
+
+    @Override
+    abstract public short requestNeighbourTable(short index, String address) throws TelegesisErrorException;
+
+    @Override
+    abstract public void requestNodeId(String address) throws TelegesisErrorException;
+
+    @Override
+    abstract public short requestNodeEUI64Addr(String address, String nodeId) throws TelegesisErrorException;
+
+    @Override
+    abstract public short requestNodeDescriptor(String address, String nodeId) throws TelegesisErrorException;
+
+    @Override
+    abstract public short requestNodePowerDescriptor(String address, String nodeId) throws TelegesisErrorException;
+
+    @Override
+    abstract public short requestNodeActiveEndPoints(String address, String nodeId) throws TelegesisErrorException;
+
+    @Override
+    abstract public short requestNodeEndPointSimpleDescriptor(String address, String nodeId, short EP) throws TelegesisErrorException;
+
+    @Override
+    abstract public void findNodesMatchingDescriptor(String profileId, String[] inClusterList, String[] outClusterList) throws TelegesisErrorException;
+
+    @Override
+    abstract public void annouceLocalNode() throws TelegesisErrorException;
+
+    @Override
+    abstract public void setSourceRoute(String destNode, String[] route) throws TelegesisErrorException;
+
+    @Override
+    abstract public void findRoute(String address) throws TelegesisErrorException;
+
+    @Override
+    abstract public void scanNetwork(int numHops) throws TelegesisErrorException;
+
+    @Override
+    abstract public void updateNetworkKey() throws TelegesisErrorException;
+
+    @Override
+    abstract public void becomeTrustCenter() throws TelegesisErrorException;
+
+    @Override
+    abstract public void becomeNetworkManager() throws TelegesisErrorException;
+
+    @Override
+    abstract public void changeNetworkChannel() throws TelegesisErrorException;
+
+    @Override
+    abstract public void changeNetworkChannel(int channel) throws TelegesisErrorException;
+
+    @Override
+    abstract public AddressTableEntry[] getAddressTable();
+
+    @Override
+    abstract public void setAddressTableEntry(short index, String nodeID, String EUI64Addr) throws TelegesisErrorException;
+
+    @Override
+    abstract public MulticastTableEntry[] getMulticastTable();
+
+    @Override
+    abstract public void setMulticastTableEntry(short index, String ID, short EP) throws TelegesisErrorException;
+
+    @Override
+    abstract public void sendBroadcast(int numHops, String data) throws TelegesisErrorException;
+
+    @Override
+    abstract public void sendBroadcast(int numHops, byte[] data) throws TelegesisErrorException;
+
+    @Override
+    abstract public short sendMessageRequest(String address, String data) throws TelegesisErrorException;
+
+    @Override
+    abstract public short sendMessageRequest(String address, byte[] data) throws TelegesisErrorException;
+
+    @Override
+    abstract public void sendMulticastBroadcast(int numHops, String ID, String data) throws TelegesisErrorException;
+
+    @Override
+    abstract public void sendMulticastBroadcast(int numHops, String ID, byte[] data) throws TelegesisErrorException;
+
+    @Override
+    abstract public String writeCommand(String cmd, boolean expectResponse) throws TelegesisErrorException;
+
+    @Override
+    abstract public boolean open();
+
+    @Override
+    abstract public boolean close();
+
+    @Override
+    abstract public boolean isOpen();
+
+    @Override
+    abstract public SerialConnection getConnection();
+
+    @Override
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    @Override
+    public String getFirmwareRevision() {
+        return firmwareRevision;
+    }
+
+    @Override
+    public String getDongleAddress() {
+        return dongleAddress;
+    }
+    // <editor-fold defaultstate="collapsed" desc="GESTION BLOQUEO">
+    private Locker locker = new Locker(this.getClass().getSimpleName());
+
+    @Override
+    public boolean tryLock(int milliseconds) {
+        logger.trace("Gateway305::tryLock(milliseconds=" + milliseconds + ")");
+        return locker.tryLock(milliseconds);
+
+    }
+
+    @Override
+    public void lock(int milliseconds) {
+        logger.trace("Gateway305::lock(milliseconds=" + milliseconds + ")");
+        locker.lock(milliseconds);
+
+    }
+
+    @Override
+    public boolean unlock() {
+        logger.trace("Gateway305::unlock()");
+        return locker.unlock();
+
+    }
+
+    /**
+     * Función para ejecutar control de bloqueo (bloquea la ejecucion)
+     */
+    protected void checkLock() {
+        locker.checkLock();
+    }
+    // </editor-fold>
+    // <editor-fold defaultstate="collapsed" desc="GESTION LISTENERS">
+    protected final ArrayList<GatewayListener> gtwyListeners = new ArrayList<GatewayListener>();
+    protected final HashMap<GatewayListener, Executor> gtwyExecutors = new HashMap<GatewayListener, Executor>();
+
+    @Override
+    public void registerListener(GatewayListener lstnr) {
+        logger.trace("AbstractGateway::registerListener(lstnr=" + lstnr + ")");
+        synchronized (gtwyListeners) {
+            if (gtwyListeners.add(lstnr)) {
+                Executor ex = Executors.newSingleThreadExecutor();
+                gtwyExecutors.put(lstnr, ex);
+            }
+
+        }
+    }
+
+    @Override
+    public void unregisterListener(GatewayListener lstnr) {
+        logger.trace("AbstractGateway::unregisterListener(lstnr=" + lstnr + ")");
+        synchronized (gtwyListeners) {
+            if (gtwyListeners.remove(lstnr)) {
+                gtwyExecutors.remove(lstnr);
+            }
+        }
+    }
+
+    /**
+     * Notifies about acknowledgement of a node communication operation, 
+     * providing SEQ number and acknowledge result (ACK/NACK)
+     * @param seqNumber SEQ number
+     * @param wasOK True for ACK, false for NACK
+     */
+    protected void fireAcknowledgement(final short seqNumber, final boolean wasACK) {
+        logger.trace("AbstractGateway::fireAcknowledgement(seqNumber=" + seqNumber + ", wasACK=" + wasACK + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.acknowledgement(seqNumber, wasACK, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+
+    }
+
+    /**
+     * Notifies about a route to a remote device found
+     * @param EUI64Addr Remote node address
+     * @param numHops Number of hops
+     * @param route Array containing network addresses of intermediate nodes up 
+     * to remote node, excluding local node
+     */
+    protected void fireRouteRecordReceived(final String EUI64Addr, final int numHops, final String[] route) {
+        logger.trace("AbstractGateway::fireRouteRecordReceived(EUI64Addr=" + EUI64Addr + ", numHops=" + numHops + ", route=" + route + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.routeRecordReceived(EUI64Addr, numHops, route, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about reception of a broadcast message
+     * @param EUI64Addr Sender address
+     * @param message Message received
+     */
+    protected void fireBroadcastMessageReceived(final String EUI64Addr, final byte[] message) {
+        logger.trace("AbstractGateway::fireBroadcastMessageReceived(EUI64Addr=" + EUI64Addr + ", message=" + message + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.broadcastMessageReceived(EUI64Addr, message, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about reception of a message, whether it was a broadcast message
+     * multicast or unicast
+     * @param EUI64Addr Sender address
+     * @param message Message received
+     * @param type Message type
+     */
+    protected void fireMessageReceived(final String EUI64Addr, final byte[] message, final String type) {
+        logger.trace("AbstractGateway::fireMessageReceived(EUI64Addr=" + EUI64Addr + ", message=" + message + ", type=" + type + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.messageReceived(EUI64Addr, message, type, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about reception of a message not handled by Telegesis dongle,
+     * providing whole APS frame
+     * @param EUI64Addr Sender address
+     * @param nodeID Sender network address
+     * @param sourceEP Sender EndPoint id
+     * @param destEP Receiver EndPoint id
+     * @param profileID ProfileID
+     * @param clusterID ClusterID 
+     * @param payload Message received
+     */
+    protected void fireMessageReceived(final String EUI64Addr, final String nodeID, final short sourceEP, final short destEP, final String profileID, final String clusterID, final byte[] payload) {
+        logger.trace("AbstractGateway::fireMessageReceived(EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", sourceEP=" + sourceEP + ", destEP=" + destEP + ", profileID=" + profileID + ", clusterID=" + clusterID + ", payload=" + payload + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.endpointMessageReceived(EUI64Addr, nodeID, sourceEP, destEP, profileID, clusterID, payload, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node announce
+     * @param type DeviceType (COO, FFD...)
+     * @param EUI64Addr Node's address
+     * @param nodeID Node's network address
+     * @param RSSI RSSI level (dBm) of the last hop
+     * @param LQI LQI indicator of the last hop
+     * @param parentID Parent's network address or null
+     */
+    protected void fireNodeAnnounce(final ZigbeeDeviceType type, final String EUI64Addr, final String nodeID, final int RSSI, final short LQI) {
+        logger.trace("AbstractGateway::fireNodeAnnounce(type=" + type + ", EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", RSSI=" + RSSI + "LQI=" + LQI + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeAnnounce(type, EUI64Addr, nodeID, RSSI, LQI, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a new node announce
+     * @param EUI64Addr Node's address
+     * @param nodeID Node's network address
+     * @param parentID Parent's network address
+     */
+    protected void fireNewNode(final String EUI64Addr, final String nodeID, final String parentID) {
+        logger.trace("AbstractGateway::fireNewNode(EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", parentID=" + parentID + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.newNode(EUI64Addr, nodeID, parentID, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about local node left PAN
+     * Note: also notifies about end device losing parent
+     */
+    protected void fireLeftPAN() {
+        logger.trace("AbstractGateway::fireLeftPAN()");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.leftPAN(gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about local node joining PAN
+     * @param channel Network channel (ranging from 0x0B to 0x1A)
+     * @param PID Network PID
+     * @param EPID Network EPID
+     */
+    protected void fireJoinedPan(final int channel, final String PID, final String EPID) {
+        logger.trace("AbstractGateway::fireJoinedPan(channel=" + channel + ", PID=" + PID + ", EPID=" + EPID + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.joinedPan(channel, PID, EPID, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about operation result of writing on a register
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     * @param errorCode Operation result
+     */
+    protected void fireRegisterWrited(final String nodeID, final String EUI64Addr, final short errorCode) {
+        logger.trace("AbstractGateway::fireRegisterWrited(nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ", errorCode=" + errorCode + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.registerWrited(nodeID, EUI64Addr, errorCode, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about reading of a register
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     * @param register Register readed
+     * @param errorCode Operation result
+     * @param data Register contents
+     */
+    protected void fireRegisterReaded(final String nodeID, final String EUI64Addr, final short register, final short errorCode, final String data) {
+        logger.trace("AbstractGateway::fireRegisterReaded(nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ", register=" + register + ", errorCode=" + errorCode + ", data=" + data + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.registerReaded(nodeID, EUI64Addr, register, errorCode, data, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies response abour an address request to a node
+     * @param errorCode request result
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     */
+    protected void fireAddrResponse(final short errorCode, final String nodeID, final String EUI64Addr) {
+        logger.trace("AbstractGateway::fireAddrResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EUI64Addr=" + EUI64Addr + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.addrResponse(errorCode, nodeID, EUI64Addr, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a Neighbour table request response.
+     * Note: tableLength != table.length() means there are records pending to 
+     * receive (if requested)
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param tableLength Total neighbour table
+     * @param table received records
+     */
+    protected void fireNeighbourTableResponse(final String nodeID, final short errorCode, final int tableLength, final NeighbourTableEntry[] table) {
+        logger.trace("AbstractGateway::fireNeighbourTableResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", tableLength=" + tableLength + ", table=" + table + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.neighbourTableResponse(nodeID, errorCode, tableLength, table, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param descriptor Map containig pairs <key,value> of related descriptor
+     */
+    protected void fireNodeDescriptorResponse(final String nodeID, final short errorCode, final Map descriptor) {
+        logger.trace("AbstractGateway::fireNodeDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", descriptor=" + descriptor + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeDescriptorResponse(nodeID, errorCode, descriptor, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param descriptor power descriptor
+     */
+    protected void firePowerDescriptorResponse(final String nodeID, final short errorCode, final String descriptor) {
+        logger.trace("AbstractGateway::firePowerDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", descriptor=" + descriptor + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.powerDescriptorResponse(nodeID, errorCode, descriptor, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EPList EndPoint list
+     * @param gtwy Gateway launching notification
+     */
+    protected void fireNodeActiveEPResponse(final String nodeID, final short errorCode, final short[] EPList) {
+        logger.trace("AbstractGateway::fireNodeActiveEPResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EPList=" + EPList + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeActiveEPResponse(nodeID, errorCode, EPList, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node simple descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EP EndPoint requested
+     * @param ProfileID
+     * @param DeviceID
+     * @param inClusterList String array containing supported in cluster 
+     * @param outClusterList String array containing supported out cluster 
+     */
+    protected void fireNodeEndPointSimpleDescriptorResponse(final String nodeID, final short errorCode,
+            final short EP, final String ProfileID, final String DeviceID, final String[] inClusterList, final String[] outClusterList) {
+        logger.trace("AbstractGateway::fireNodeEndPointSimpleDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode
+                + ", EP=" + EP + ", ProfileID=" + ProfileID + ", DeviceID=" + DeviceID + ", inClusterList=" + inClusterList + ", outClusterList=" + outClusterList + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeEndPointSimpleDescriptorResponse(nodeID, errorCode, EP, ProfileID, DeviceID, inClusterList, outClusterList, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node matching a previous descriptor request response
+     * NOTE: profile
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EPList EndPoint list
+     */
+    protected void fireNodeMatchingDescriptorResponse(final String nodeID, final short errorCode, final short[] EPList) {
+        logger.trace("AbstractGateway::fireNodeMatchingDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EPList=" + EPList + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeMatchingDescriptorResponse(nodeID, errorCode, EPList, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about and unhandled telegesis command:
+     * - SDATA
+     * - FN0130
+     * - SINK
+     * - ADSK
+     * - dataMODE
+     * - OPEN
+     * - CLOSED
+     * - TRACK
+     * - TRACK2
+     * - PWRCHANGE
+     * - RX
+     * - NM
+     * - ENTERING BLOAD
+     * @param command not handled command
+     * @param parameters command parameters list
+     */
+    protected void fireUnhandledCommand(final String command, final String[] parameters) {
+        logger.trace("AbstractGateway::fireUnhandledCommand(command=" + command + ", parameters=" + parameters + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.unhandledCommand(command, parameters, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about unknonwn incomming messages
+     * @param message 
+     */
+    protected void fireUnknownMessage(final String message) {
+        logger.trace("AbstractGateway::fireUnknownMessage(message=" + message + ")");
+        synchronized (gtwyListeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = gtwyListeners.iterator();
+            final Gateway gtwy = this;
+            while (it.hasNext()) {
+                final GatewayListener lstnr = (GatewayListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.unknownMessage(message, gtwy);
+                    }
+                };
+                Executor ex = gtwyExecutors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+    // </editor-fold>
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,2305 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.TelegesisErrorException;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.ZigbeeDeviceType;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.*;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.Command305;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.ErrorCode305;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.Prompt305;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.SpecialSequence305;
+import es.unizar.howlab.core.io.serial.SerialConnection;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Class mplementation for a Telegesis Gateway version 305
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class Gateway305 extends AbstractGateway implements Gateway, SerialListener.MessageParser {
+
+    private static final String FIRMWARE_REVISION = "R305";
+    private static final String[] COMPATIBLE_FIRMWARE = new String[]{"R302X", "R303X", "R304X"};
+    private static final int COMMAND_RESPONSE_TIMEOUT = 1000;
+    private static final int RESET_RESPONSE_TIMEOUT = 2000;
+    private static final int FACTORY_RESPONSE_TIMEOUT = 2000;
+    //
+    // Tiempos de bloqueo
+    private static final int SERIAL_PORT_BLOCKING_4_SEC = 4000;
+    private static final int SERIAL_PORT_BLOCKING_10_SEC = 10000;
+    private static final int SERIAL_PORT_BLOCKING_16_SEC = 16000;
+    //
+    // configuraciones por defecto de registros para tráfico de mensajes
+    private static final short S_REG_ADDR_PROMPT_ENABLE_1 = 0x0E;
+    private static final short S_REG_ADDR_PROMPT_ENABLE_2 = 0x0F;
+    private static final short S_REG_ADDR_UART_SETUP = 0x12;
+    private static final short S_REG_BIT_NO_COMMAND_ECHO = 4;
+    private static final String DEFAULT_PROMPT_ENABLE_1 = "8000";
+    private static final String DEFAULT_PROMPT_ENABLE_2 = "0106";
+    //
+    // puerto para comunicar con el gateway
+    private SerialConnection serialPort;
+    private SerialListener spLstnr;
+    private boolean gtwyIsOpen = false;
+    private final String SYNC_COMMAND = "SYNC_COMMAND"; // objeto referencia para exclusión mutua entre operaciones (synchronized(SYNC_COMMAND) { ... })
+    // Logger
+    Log logger = LogFactory.getLog(Gateway305.class.getName());
+
+    public Gateway305(SerialConnection cnx) {
+        logger.trace("Gateway305::Gateway305(cnx=" + cnx + ")");
+        // Guardamos el puerto
+        serialPort = cnx;
+
+        // creamos el listener, pero el registro se debe hacer en el OPEN
+        spLstnr = new SerialListener(this);
+
+    }
+
+    @Override
+    public String toString() {
+        if (serialPort != null) {
+            return String.format("Gateway %s at %s", deviceName, serialPort);
+        } else {
+            return "Uninitialized gateway";
+        }
+    }
+    // <editor-fold defaultstate="collapsed" desc="utilidades de parseo de respuestas">
+
+    @Override
+    public void serialPortError() {
+        logger.trace("Gateway305::serialPortError()");
+        logger.warn("Error accesing physical dongle, closing Gateway");
+        this.close();
+        //TODO: despublicar gateway?
+
+    }
+
+    @Override
+    public void hasNewPromps() {
+        logger.trace("Gateway305::hasNewPromps()");
+        // recuperamos el mensaje
+        String prompt = spLstnr.getNextPrompt();
+        while (prompt != null) {
+            logger.info("Prompt received by gateway: " + prompt);
+            /*
+             * Comprobamos el mensaje recibido, a la vez que lo procesamos. La 
+             * función que lo comprueba devuelve true si era un mensaje de ese 
+             * tipo, con lo que la utilizamos para procesar y discriminar a la 
+             * vez. La estructura de if's anidados procesa los tipos de mensajes
+             * de forma secuencial, por lo que el orden está establecido (o debe 
+             * establecerse) para procesar en primer lugar los mensajes más 
+             * frecuentes
+             */
+            if (parseACKPrompt(prompt)) { // comprobamos si es un ACK
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseMessageReceivedPrompt(prompt)) { // comprobamos si se trata de un mensaje
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseAddrResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje de ruta
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseEndPointMessagePrompt(prompt)) { // comprobamos si se trata de un mensaje
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseRegisterReadPrompt(prompt)) { // comprobamos si se trata de un registro leido
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseRegisterWritePrompt(prompt)) { // comprobamos si se trata de un registro escrito
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseNodeAnnouncePrompt(prompt)) { // comprobamos si se trata de un anuncio de nodo
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseRouteRecordPrompt(prompt)) { // comprobamos si se trata de un mensaje de ruta
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseNewNodePrompt(prompt)) { // comprobamos si se trata de un nuevo nodo
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseJoinedPanPrompt(prompt)) { // comprobamos si se trata de un mensaje de incorporación a PAN
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseLeftPanPrompt(prompt)) { // comprobamos si se trata de un mensaje de abandono de PAN
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más
+            } else if (parseUnhandledMessagePrompt(prompt)) { // comprobamos si se trata de un mensaje no implementado
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parseNeighbourTableResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje de tabla de vecinos
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parseNodeDescriptorResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje Node Descriptor
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parseNodeEndPointSimpleDescriptorResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje EndPoint Simple Descriptor
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parsePowerDescriptorResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje Power Descriptor
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parseNodeMatchingDescriptorResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje Node Matching Descioptor
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else if (parseActiveEndPointsResponsePrompt(prompt)) { // comprobamos si se trata de un mensaje Active End Points
+                // si devuelve TRUE, ha procesado el mensaje, no hay que hacer nada más                
+            } else { // se trata de un mensaje desconocido
+                fireUnknownMessage(prompt);
+            }
+
+            // comprobamos si hay mas prompts
+            prompt = spLstnr.getNextPrompt();
+        }
+    }
+
+    /**
+     * Bloquea el puerto contra escritura para recibir respuestas
+     * NOTA: esto se ha definido en una función para asegurar que se ejecuta 
+     * siempre de la misma forma
+     * @param milliseconds tiempo máximo de bloqueo del puerto
+     */
+    private void lockPortForResponses(int milliseconds) {
+        logger.trace("Gateway305::lockPortForResponses(milliseconds=" + milliseconds + ")");
+        // bloqueamos el acceso al puerto
+        serialPort.blockWriting(milliseconds);
+        // Marcamos que podemos esperar una respuesta
+        spLstnr.setExpectResponse();
+    }
+
+    /**
+     * Libera el puerto contra escritura, y borra la marca de respuestas
+     */
+    private void unlockPortForResponses() {
+        logger.trace("Gateway305::unlockPortForResponses()");
+        // liberamos el acceso al puerto
+        serialPort.unblockWriting();
+        // Marcamos que ya no esperamos respuesta
+        spLstnr.clearExpectResponse();
+    }
+
+    /**
+     * Comprueba la respuesta recibida, generando excepciones si es null o 
+     * ERROR:XX
+     * NOTA: esta función YA es llamada dentro de writeCommand
+     * @param response frame a analizar
+     * @throws TelegesisErrorException 
+     */
+    private void checkResponseNullOrErrorAndThrowException(String response) throws TelegesisErrorException {
+        logger.trace("Gateway305::checkResponseNullOrErrorAndThrowException(response=" + response + ")");
+        if (response == null) {
+            unlockPortForResponses();
+            ErrorCode305 errorCode = ErrorCode305.COMMUNICATION_ERROR;
+            throw new TelegesisErrorException(errorCode.toString(), errorCode.getMessage());
+        } else if (response.startsWith(SpecialSequence305.COMMAND_ERROR.getText())) {
+            unlockPortForResponses();
+            String strErrorCode = response.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1];
+            ErrorCode305 errorCode = ErrorCode305.valueOf(ErrorCode305.class, "TELEGESIS_ERROR_" + strErrorCode);
+            throw new TelegesisErrorException(errorCode.name(), errorCode.getMessage());
+        }
+    }
+
+    /**
+     * Obtiene el SEQ Number de una respuesta recibida, o genera la excepcion
+     * correspondiente
+     * @param frame respuesta a analizar
+     * @return numero de secuencia
+     * @throws TelegesisErrorException 
+     */
+    private short getSeqNumber(String frame) throws TelegesisErrorException {
+        logger.trace("Gateway305::getSeqNumber(frame=" + frame + ")");
+        // comprobamos SEQ:XX
+        if (frame.startsWith(SpecialSequence305.SEQUENCE_NUMBER.getText())) {
+            String seqNumber = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1];
+            return (short) Integer.parseInt(seqNumber, 16);
+        } else {
+            throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), ErrorCode305.BAD_RESPONSE.getMessage());
+        }
+    }
+
+    /**
+     * Procesa un mensaje ACK, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseACKPrompt(String frame) {
+        logger.trace("Gateway305::parseACKPrompt(frame=" + frame + ")");
+        // comprobamos ACK:XX
+        // comprobamos NACK:XX
+        if (frame.startsWith(Prompt305.ACK.getText())
+                || frame.startsWith(Prompt305.NACK.getText())) {
+            String command = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[0];
+            String parameter = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1];
+            short seqNumber = (short) Integer.parseInt(parameter, 16);
+            boolean wasACK = command.equals(Prompt305.ACK.getText());
+            fireAcknowledgement(seqNumber, wasACK);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje ROUTE_RECORD, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseRouteRecordPrompt(String frame) {
+        logger.trace("Gateway305::parseRouteRecordPrompt(frame=" + frame + ")");
+        // comprobamos SR:XX,<EUI64>,<NodeID>,...
+        if (frame.startsWith(Prompt305.ROUTE_RECORD.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            int numHops = Integer.parseInt(parameters[0], 16);
+            String EUI64Addr = parameters[1];
+            String[] route = new String[parameters.length - 2];
+            System.arraycopy(parameters, 2, route, 0, route.length);
+            fireRouteRecordReceived(EUI64Addr, numHops, route);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje broadcast, multicast o unicast, lanzando las 
+     * notificaciones correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseMessageReceivedPrompt(String frame) {
+        logger.trace("Gateway305::parseMessageReceivedPrompt(frame=" + frame + ")");
+        // comprobamos BCAST:[<EUI64>,]XX=Data
+        // comprobamos MCAST:[<EUI64>,]XX=Data
+        // comprobamos UCAST:[<EUI64>,]XX=Data
+        if ((frame.startsWith(Prompt305.BROADCAST_RECEIVED.getText()))
+                || frame.startsWith(Prompt305.MULTICAST_RECEIVED.getText())
+                || frame.startsWith(Prompt305.UNICAST_RECEIVED.getText())) {
+            String[] message = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText(), 2);// limitamos el split a 2 para asegurarnos de que no pille un caracter en los datos
+            String command = message[0];
+            String strParam = message[1];
+            // Obtenemos los parámetros y comprobamos para determinar el formato
+            String[] parameters = strParam.split(SpecialSequence305.PARAMETER_SEPARATOR.getText(), 2); // limitamos el split a 2 para asegurarnos de que no pille un caracter en los datos
+            String EUI64Addr;
+            String dataParam;
+            // no podemos basarnos en la longitud para comprobar, ya que podría haber una coma en la posicion 13 de los datos
+            // comprobamos que el parámetro es una cadena hexadecimal válida, ya que en otro caso tendríamos por medio un "="
+            if (parameters[0].contains("=")) { // la EUI64Addr no viene en el mensaje
+                EUI64Addr = null;
+                dataParam = strParam;
+            } else {
+                EUI64Addr = parameters[0];
+                dataParam = parameters[1];
+            }
+            String[] dataParams = dataParam.split(SpecialSequence305.DATA_SEPARATOR.getText(), 2); // limitamos el split a 2 para asegurarnos de que no pille un caracter en los datos
+            int dataLengh = Integer.parseInt(dataParams[0], 16); // no se utiliza
+            byte[] data = dataParams[1].getBytes(Charset.forName("ISO-8859-1"));
+            // utilizaremos el comando como tipo de mensaje
+            if (command.equals("BCAST")) {
+                fireBroadcastMessageReceived(EUI64Addr, data);
+            } else {
+                fireMessageReceived(EUI64Addr, data, command);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje RX, lanzando las notificaciones correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseEndPointMessagePrompt(String frame) {
+        logger.trace("Gateway305::parseEndPointMessagePrompt(frame=" + frame + ")");
+        // comprobamos RX:<EUI64>,<NodeID>,<profileID>, <destinationEndpoint>,<SourceEndpoint>,<clusterID>,<length>:<payload>
+        // comprobamos RX:<NodeID>,<profileID>, <destinationEndpoint>,<SourceEndpoint>,<clusterID>,<length>:<payload>
+        if (frame.startsWith(Prompt305.END_POINT_MESSAGE.getText())) {
+            String[] message = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText(), 2);
+            String strParam = message[1];
+            // comprobamos el formato del mensaje, recuperando el primer parámetro
+            String[] parameters;
+            int offset = 0;
+            String EUI64Addr;
+            String firstParam = strParam.split(SpecialSequence305.PARAMETER_SEPARATOR.getText())[0];
+            if (firstParam.length() == 4) { // se trata del NodeID, hay 6 parámetros
+                parameters = strParam.split(SpecialSequence305.PARAMETER_SEPARATOR.getText(), 6);
+                EUI64Addr = null;
+            } else { // se trata de la EUI64Addr, hay 7 parámetros
+                parameters = strParam.split(SpecialSequence305.PARAMETER_SEPARATOR.getText(), 7);
+                EUI64Addr = parameters[0];
+                offset = 1;
+            }
+            String nodeID = parameters[offset];
+            String profileID = parameters[offset + 1];
+            short destEP = (short) Integer.parseInt(parameters[offset + 2], 16);
+            short sourceEP = (short) Integer.parseInt(parameters[offset + 3], 16);
+            String clusterID = parameters[offset + 4];
+            String[] payload = parameters[offset + 5].split(SpecialSequence305.COMMAND_SEPARATOR.getText(), 2);
+            int dataLengh = Integer.parseInt(payload[0], 16); // no se utiliza
+            byte[] data = payload[1].getBytes(Charset.forName("ISO-8859-1"));
+            fireMessageReceived(EUI64Addr, nodeID, sourceEP, destEP, profileID, clusterID, data);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de anuncio de nodo, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNodeAnnouncePrompt(String frame) {
+        logger.trace("Gateway305::parseNodeAnnouncePrompt(frame=" + frame + ")");
+        // comprobamos COO:<EUI64>,<NodeID>
+        // comprobamos FFD:<EUI64>,<NodeID>
+        // comprobamos ZED:<EUI64>,<NodeID>
+        // comprobamos MED:<EUI64>,<NodeID>
+        // comprobamos SED:<EUI64>,<NodeID>
+        if ((frame.startsWith(Prompt305.COO_ANNOUNCE.getText()))
+                || frame.startsWith(Prompt305.FFD_ANNOUNCE.getText())
+                || frame.startsWith(Prompt305.ZED_ANNOUNCE.getText())
+                || frame.startsWith(Prompt305.MED_ANNOUNCE.getText())
+                || frame.startsWith(Prompt305.SED_ANNOUNCE.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String EUI64Addr = parameters[0];
+            String nodeID = parameters[1];
+            int RSSI = 0;
+            short LQI = 0;
+            if (parameters.length == 4) {
+                RSSI = Integer.parseInt(parameters[2]);
+                LQI = (short) Integer.parseInt(parameters[3], 16);
+            }
+            ZigbeeDeviceType type = getTypeFromPrompt(frame);
+            fireNodeAnnounce(type, EUI64Addr, nodeID, RSSI, LQI);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de anuncio de nodo, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNewNodePrompt(String frame) {
+        logger.trace("Gateway305::parseNewNodePrompt(frame=" + frame + ")");
+        // comprobamos NEWNODE:<NodeID>,<EUI64>,<Parent NodeId>,
+        if (frame.startsWith(Prompt305.NEWNODE_ANNOUNCE.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeID = parameters[0];
+            String EUI64Addr = parameters[1];
+            String parentID = parameters[2];
+            fireNewNode(EUI64Addr, nodeID, parentID);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de abandono de PAN, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseLeftPanPrompt(String frame) {
+        logger.trace("Gateway305::parseLeftPanPrompt(frame=" + frame + ")");
+        // comprobamos LeftJPAN
+        // comprobamos LostJPAN
+        if (frame.startsWith(Prompt305.LEFT_PAN.getText())
+                || frame.startsWith(Prompt305.LOST_PAN.getText())) {
+            fireLeftPAN();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de incorporación a PAN, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseJoinedPanPrompt(String frame) {
+        logger.trace("Gateway305::parseJoinedPanPrompt(frame=" + frame + ")");
+        // comprobamos JPAN:<channel>,<PID>,<EPID>
+        if (frame.startsWith(Prompt305.JOIN_PAN.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            int channel = Integer.parseInt(parameters[0]);
+            String PID = parameters[1];
+            String EPID = parameters[2];
+            fireJoinedPan(channel, PID, EPID);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de lectura de registro, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseRegisterReadPrompt(String frame) {
+        logger.trace("Gateway305::parseRegisterReadPrompt(frame=" + frame + ")");
+        // comprobamos SREAD:<NodeID>,<EUI64>,<Register>,<errorcode>[=<Data>]
+        if (frame.startsWith(Prompt305.REGISTER_READ.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = parameters[0];
+            String EUI64Addr = parameters[1];
+            short register = (short) Integer.parseInt(parameters[2], 16);
+            String[] errorAndData = parameters[3].split(SpecialSequence305.DATA_SEPARATOR.getText());
+            short errorCode = (short) Integer.parseInt(errorAndData[0], 16);
+            String data = (errorAndData.length == 2 ? errorAndData[1] : null);
+            fireRegisterReaded(nodeId, EUI64Addr, register, errorCode, data);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de escritura de registro, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseRegisterWritePrompt(String frame) {
+        logger.trace("Gateway305::parseRegisterWritePrompt(frame=" + frame + ")");
+        // comprobamos SWRITE:<NodeID>,<EUI64>,<errorcode>
+        if (frame.startsWith(Prompt305.REGISTER_WRITE.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = parameters[0];
+            String EUI64Addr = parameters[1];
+            short errorCode = (short) Integer.parseInt(parameters[2], 16);
+            fireRegisterWrited(nodeId, EUI64Addr, errorCode);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de respuesta desde direccion, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseAddrResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseAddrResponsePrompt(frame=" + frame + ")");
+        // comprobamos AddrResp:<errorcode>[,<NodeID>,<EUI64>]
+        if (frame.startsWith(Prompt305.ADDR_RESPONSE.getText())) {
+            String[] parameters = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            short errorCode = (short) Integer.parseInt(parameters[0], 16);
+            String nodeId = (parameters.length == 3 ? parameters[1] : null);
+            String EUI64Addr = (parameters.length == 3 ? parameters[2] : null);
+            fireAddrResponse(errorCode, nodeId, EUI64Addr);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de tabla de vecinos, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNeighbourTableResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseNeighbourTableResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //[0]NTable:<NodeID>,<errorcode> 
+        //[1]Length:03 
+        //[2]No.| Type | EUI | ID | LQI 
+        //[3]00.| FFD | 000D6F000015896B | BC04 | FF 
+        //[4]01.| FFD | 000D6F00000B3E77 | 739D | FF 
+        //[5]02.| FFD | 000D6F00000AAD11 | 75E3 | FF        
+        if (frame.startsWith(Prompt305.NEIGHBOUR_TABLE_RESPONSE.getText())) {
+            // separamos el comando en líneas:
+            String[] lines = frame.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            // analizamos la primera linea
+            String[] params = lines[0].split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje
+            int tableLength = 0;
+            NeighbourTableEntry[] nTable = null;
+            if (errorCode == 0) {
+                tableLength = Integer.parseInt(lines[1].split(":")[1]);
+                int numRecords = lines.length - 3;
+                /* Se ha detectado este tipo de respuesta:
+                [0]NTable:<NodeID>,<errorcode> 
+                [1]Length:02
+                ==> esto hará que numRecords sea negativo, con lo que saltará una excepción
+                El caso numRecords = 0 también es anormal
+                 */
+                if (numRecords <= 0) {
+                    logger.warn(String.format("[Gateway] Received malformed NTable response: %s ", frame));
+                    // respondemos TRUE, pero no lanzamos el evento
+                    return true;
+                }
+                nTable = new NeighbourTableEntry[numRecords];
+                for (int i = 3; i < lines.length; i++) {
+                    String line = lines[i].replace("|", ",");
+                    String[] record = line.split(",");
+                    short index = (short) Integer.parseInt(record[0].substring(0, 2));
+                    ZigbeeDeviceType type = getTypeFromPrompt(record[1].trim());
+                    String EUI64Addr = record[2].trim();
+                    String nodeID = record[3].trim();
+                    short LQI = (short) Integer.parseInt(record[4].trim(), 16);
+                    nTable[i - 3] = new NeighbourTableEntry(index, type, EUI64Addr, nodeID, LQI);
+                }
+
+            }
+            fireNeighbourTableResponse(nodeId, errorCode, tableLength, nTable);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje Node Descriptor, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNodeDescriptorResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseNodeDescriptorResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //[0]NodeDesc:<NodeID>,<errorcode>
+        //[1]NodeDesc:0D57 
+        //[2]Type:FFD 
+        //[3]ComplexDesc:No 
+        //[4]UserDesc:No 
+        //[5]APSFlags:00 
+        //[6]FreqBand:40 
+        //[7]MacCap:8E 
+        //[8]ManufCode:1010 
+        //[9]MaxBufSize:52 
+        //[.]MaxInSize:0080 
+        //[.]SrvMask:0000 
+        //[.]MaxOutSize:0080 
+        //[.]DescCap:00
+        if (frame.startsWith(Prompt305.NODE_DESC_RESPONSE.getText())) {
+            // separamos el comando en líneas:
+            String[] lines = frame.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            // analizamos la primera linea
+            String[] params = lines[0].split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje
+            Map descriptor = new HashMap();
+            for (int i = 1; i < lines.length; i++) {
+                String[] record = lines[i].split(":");
+                descriptor.put(record[0], record[1]);
+            }
+            fireNodeDescriptorResponse(nodeId, errorCode, descriptor);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje Power Descriptor, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parsePowerDescriptorResponsePrompt(String frame) {
+        logger.trace("Gateway305::parsePowerDescriptorResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //PowerDesc:<NodeID>,<errorcode>[,<PowerDescriptor>]
+        if (frame.startsWith(Prompt305.POWER_DESC_RESPONSE.getText())) {
+            // obtenemos parámetros
+            String[] params = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje            
+            String descriptor = (params.length == 3 ? params[2] : null);
+            firePowerDescriptorResponse(nodeId, errorCode, descriptor);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje Active EndPoint List, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseActiveEndPointsResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseActiveEndPointsResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //ActEpDesc:<NodeID>,<errorcode>[,XX,...]
+        if (frame.startsWith(Prompt305.ACTIVE_EP_RESPONSE.getText())) {
+            // obtenemos parámetros
+            String[] params = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje
+            int numEPs;
+            short[] EPList;
+            if (errorCode == (short) 0) {
+                numEPs = params.length - 2;
+                EPList = new short[numEPs];
+                for (int i = 2; i < params.length; i++) {
+                    EPList[i - 2] = (short) Integer.parseInt(params[i], 16);
+                }
+            } else {
+                numEPs = 0;
+                EPList = null;
+
+            }
+            fireNodeActiveEPResponse(nodeId, errorCode, EPList);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje Node EndPoint Simple Descriptor, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNodeEndPointSimpleDescriptorResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseNodeEndPointSimpleDescriptorResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //[0]SimpleDesc:<NodeID>,<errorcode> 
+        //[1]EP:XX 
+        //[2]ProfileID:XXXX 
+        //[3]DeviceID:XXXXvXX 
+        //[4]InCluster:<Cluster List> 
+        //[5]OutCluster:<Cluster List>
+        if (frame.startsWith(Prompt305.EP_SIMPLE_DESC_RESPONSE.getText())) {
+            // separamos el comando en líneas:
+            String[] lines = frame.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            // analizamos la primera linea
+            String[] params = lines[0].split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje
+            short EP = (short) Integer.parseInt(lines[1].split(":")[1]);
+            String[] arrProfileID = (lines.length == 1 ? null : lines[2].split(":"));
+            String[] arrDeviceID = (lines.length == 1 ? null : lines[3].split(":"));
+            String[] arrInClusterList = (lines.length == 1 ? null : lines[4].split(":"));
+            String[] arrOutClusterList = (lines.length == 1 ? null : lines[5].split(":"));
+            String profileID = (arrProfileID.length == 1 ? null : arrProfileID[1]);
+            String deviceID = (arrDeviceID.length == 1 ? null : arrDeviceID[1]);
+            String[] inCluster = (arrInClusterList.length == 1 ? null : arrInClusterList[1].split(","));
+            String[] outCluster = (arrOutClusterList.length == 1 ? null : arrOutClusterList[1].split(","));
+
+//            String inClusterList = (lines.length == 1 ? null : lines[4].split(":")[1]);
+//            String outClusterList = (lines.length == 1 ? null : lines[5].split(":")[1]);
+//            String[] inCluster = (inClusterList == null ? null : inClusterList.split(","));
+//            String[] outCluster = (outClusterList == null ? null : outClusterList.split(","));
+            fireNodeEndPointSimpleDescriptorResponse(nodeId, errorCode, EP, profileID, deviceID, inCluster, outCluster);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje Active EndPoint List, lanzando las notificaciones 
+     * correspondientes
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseNodeMatchingDescriptorResponsePrompt(String frame) {
+        logger.trace("Gateway305::parseNodeMatchingDescriptorResponsePrompt(frame=" + frame + ")");
+        // comprobamos:
+        //MatchDesc:<NodeID>,<errorcode>,XX,...
+        if (frame.startsWith(Prompt305.NODES_MATCH_DESC_RESPONSE.getText())) {
+            // obtenemos parámetros
+            String[] params = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText())[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            String nodeId = params[0];
+            short errorCode = (short) Integer.parseInt(params[1], 16);
+            // continuamos analizando el mensaje
+            int numEPs = params.length - 2;
+            short[] EPList = new short[numEPs];
+            for (int i = 2; i < params.length; i++) {
+                EPList[i - 2] = (short) Integer.parseInt(params[i], 16);
+            }
+            fireNodeMatchingDescriptorResponse(nodeId, errorCode, EPList);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Procesa un mensaje de respuesta no procesada, lanzando las notificaciones 
+     * correspondientes
+     * - SDATA
+     * - FN0130
+     * - SINK
+     * - ADSK
+     * - DataMODE
+     * - OPEN
+     * - CLOSED
+     * - TRACK
+     * - TRACK2
+     * - PWRCHANGE
+     * - RX
+     * - NM
+     * - ENTERING BLOAD
+     * @param frame mensaje a analizar
+     * @return TRUE si efectivamente es un mensaje válido, FALSE en otro caso
+     */
+    private boolean parseUnhandledMessagePrompt(String frame) {
+        logger.trace("Gateway305::parseUnhandledMessagePrompt(frame=" + frame + ")");
+        // comprobamos mensajes
+        if (frame.startsWith(Prompt305.SINK_DATA_MESSAGE.getText())
+                || frame.startsWith(Prompt305.SINK_DATA_MESSAGE_FN0130.getText())
+                || frame.startsWith(Prompt305.SINK_ANNOUCE.getText())
+                || frame.startsWith(Prompt305.SINK_SELECTED.getText())
+                || frame.startsWith(Prompt305.DATA_MODE.getText())
+                || frame.startsWith(Prompt305.DATA_MODE_OPEN.getText())
+                || frame.startsWith(Prompt305.DATA_MODE_CLOSED.getText())
+                || frame.startsWith(Prompt305.TRACKING_MESSAGE.getText())
+                || frame.startsWith(Prompt305.TRACKING_MESSAGE_2.getText())
+                || frame.startsWith(Prompt305.POWER_CHANGE.getText())
+                || frame.startsWith(Prompt305.REPORT_WARNING.getText())
+                || frame.startsWith(Prompt305.ENTERING_BOOTLOAD.getText())) {
+            String[] frameSpplited = frame.split(SpecialSequence305.COMMAND_SEPARATOR.getText());
+            String command = frameSpplited[0];
+            String[] parameters;
+            if (frameSpplited.length == 2) {
+                parameters = frameSpplited[1].split(SpecialSequence305.PARAMETER_SEPARATOR.getText());
+            } else {
+                parameters = new String[0];
+            }
+            fireUnhandledCommand(command, parameters);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // </editor-fold>
+    // <editor-fold defaultstate="collapsed" desc="Operaciones del Gateway">
+    @Override
+    public String[] getProductId() {
+        logger.trace("Gateway305::getProductId()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISPLAY_PRODUCT_IDENTIFICATION.getText();
+
+            // Enviamos el mensaje
+            String response = null;
+            try {
+                response = writeCommand(cmd);
+                return response.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            } catch (TelegesisErrorException ex) {
+                // lanzamos un warning
+                logger.warn("Gateway305::getProductId(): ERROR", ex);
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public void reset() {
+        logger.trace("Gateway305::reset()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SOFTWARE_RESET.getText();
+
+//            // Enviamos directamente el comando por el puerto serie, sin esperar respuesta ni bloquear puerto
+//            serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+            // Enviamos el mensaje
+            String response = null;
+            try {
+                response = writeCommand(cmd, RESET_RESPONSE_TIMEOUT);
+                // debería ser OK, no la comprobamos
+                if (!response.equals(SpecialSequence305.COMMAND_OK.getText())) {
+                    // lanzamos un warning
+                    logger.warn(String.format("Gateway305::reset(): ERROR (unexpected response: %s)", response));
+                }
+            } catch (TelegesisErrorException ex) {
+                // lanzamos un warning
+                logger.warn("Gateway305::reset(): ERROR", ex);
+            }
+
+        }
+    }
+
+    @Override
+    public void restoreFactoryDefaults() {
+        logger.trace("Gateway305::restoreFactoryDefaults()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.RESTORE_FACTORY_DEFAULTS.getText();
+
+//            // Enviamos directamente el comando por el puerto serie, sin esperar respuesta ni bloquear puerto
+//            serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+            // Enviamos el mensaje
+            String response = null;
+            try {
+                response = writeCommand(cmd, FACTORY_RESPONSE_TIMEOUT);
+                // debería ser OK, no la comprobamos
+                if (!response.equals(SpecialSequence305.COMMAND_OK.getText())) {
+                    // lanzamos un warning
+                    logger.warn(String.format("Gateway305::restoreFactoryDefaults(): ERROR (unexpected response: %s)", response));
+                } else {
+                    // inicializamos la comunicacion
+                    if (!init()) {
+                        logger.warn("Gateway305::restoreFactoryDefaults(): ERROR re-initializiong dongle");
+
+                    }
+
+                }
+            } catch (TelegesisErrorException ex) {
+                // lanzamos un warning
+                logger.warn("Gateway305::restoreFactoryDefaults(): ERROR", ex);
+            }
+
+        }
+    }
+
+    @Override
+    public String readRegister(short regAddress) throws TelegesisErrorException {
+        logger.trace("Gateway305::readRegister(regAddress=" + regAddress + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register
+                    + SpecialSequence305.REGISTER_QUERY.getText();
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            return response;
+
+        }
+    }
+
+    @Override
+    public boolean readRegisterBit(short regAddress, short bitNumber) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRegisterBit(regAddress=" + regAddress + ", bitNumber=" + bitNumber + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register + bit
+                    + SpecialSequence305.REGISTER_QUERY.getText();
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            if (response.equals("0")) {
+                return false;
+            } else if (response.equals("1")) {
+                return true;
+            } else {
+                ErrorCode305 errorCode = ErrorCode305.BAD_RESPONSE;
+                throw new TelegesisErrorException(errorCode.name(), errorCode.getMessage());
+            }
+
+        }
+
+    }
+
+    @Override
+    public void writeRegister(short regAddress, String regData) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRegister(regAddress=" + regAddress + ", regData=" + regData + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + regData;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public void writeRegisterBit(short regAddress, short bitNumber, boolean bitData) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRegisterBit(regAddress=" + regAddress + ", bitNumber=" + bitNumber + ", bitData=" + bitData + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            String bitValue = (bitData ? "1" : "0");
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register + bit
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + bitValue;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public void writeRegister(short regAddress, String regData, String password) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRegister(regAddress=" + regAddress + ", regData=" + regData + ", password=" + password + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + regData
+                    + SpecialSequence305.PASSWORD_SEPARATOR.getText()
+                    + password;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void writeRegisterBit(short regAddress, short bitNumber, boolean bitData, String password) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRegisterBit(regAddress=" + regAddress + ", bitNumber=" + bitNumber + ", bitData=" + bitData + ", password=" + password + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            String bitValue = (bitData ? "1" : "0");
+            // componemos mensaje
+            String cmd = Command305.S_REGISTER_ACCESS.getText()
+                    + register + bit
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + bitValue
+                    + SpecialSequence305.PASSWORD_SEPARATOR.getText()
+                    + password;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public short readRemoteRegisterRequest(String EUI64Addr, short regAddress) throws TelegesisErrorException {
+        logger.trace("Gateway305::readRemoteRegisterRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register
+                    + SpecialSequence305.REGISTER_QUERY.getText();
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short readRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber) throws TelegesisErrorException {
+        logger.trace("Gateway305::readRemoteRegisterBitRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ", bitNumber=" + bitNumber + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register + bit
+                    + SpecialSequence305.REGISTER_QUERY.getText();
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short writeRemoteRegisterRequest(String EUI64Addr, short regAddress, String regData) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRemoteRegisterRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ", regData=" + regData + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + regData;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short writeRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber, boolean bitData) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRemoteRegisterBitRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ", bitNumber=" + bitNumber + ", bitData=" + bitData + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            String bitValue = (bitData ? "1" : "0");
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register + bit
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + bitValue;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short writeRemoteRegisterRequest(String EUI64Addr, short regAddress, String regData, String password) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRemoteRegisterRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ", regData=" + regData + ", password=" + password + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + regData
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + password;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short writeRemoteRegisterBitRequest(String EUI64Addr, short regAddress, short bitNumber, boolean bitData, String password) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeRemoteRegisterBitRequest(EUI64Addr=" + EUI64Addr + ", regAddress=" + regAddress + ", bitNumber=" + bitNumber + ", bitData=" + bitData + ", password=" + password + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // obtenemos el registro
+            String register = String.format("%02X", regAddress);
+            String bit = String.format("%02X", bitNumber);
+            String bitValue = (bitData ? "1" : "0");
+            // componemos mensaje
+            String cmd = Command305.REMOTE_S_REGISTER_ACCESS.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + EUI64Addr
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + register + bit
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + bitValue
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + password;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+
+        }
+    }
+
+    @Override
+    public short[] scanEnergy() throws TelegesisErrorException {
+        logger.trace("Gateway305::scanEnergy()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SCAN_THE_ENERGY_OF_ALL_CHANNELS.getText();
+
+            // enviamos el mensaje, esperando respuesta durante 16 segundos
+            String response = writeCommand(cmd, SERIAL_PORT_BLOCKING_16_SEC); //throws TelegesisErrorException if null or ERROR:XX
+
+            // analizamos la respuesta
+            if (response.startsWith("+ESCAN")) {
+                String[] channels = response.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+                short[] energy = new short[16]; //Nota: el scan no tiene por que devolver los 16 canales
+                for (int i = 1; i < channels.length; i++) {
+                    String[] strChannel = channels[i].split(":");
+                    int channelId = Integer.parseInt(strChannel[0]) - 11; // los canales empiezan a contar en 11
+                    energy[channelId] = (short) Integer.parseInt(strChannel[1], 16);
+                }
+                return energy;
+            } else {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public PANScanResult[] scanForActivePANs() throws TelegesisErrorException {
+        logger.trace("Gateway305::scanForActivePANs()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SCAN_FOR_ACTIVE_PANS.getText();
+
+            // bloqueamos la escritura para recibir respuestas durante 4 segundos
+            lockPortForResponses(SERIAL_PORT_BLOCKING_4_SEC);
+
+            //Enviamos el comando directamente por el puerto serie
+            serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+
+            boolean scanEnd = false;
+            ArrayList<PANScanResult> scanResult = new ArrayList<PANScanResult>();
+            while (!scanEnd) {
+                // recuperamos la respuesta
+                String scanResponse = spLstnr.waitForNextResponse(SERIAL_PORT_BLOCKING_4_SEC);
+                checkResponseNullOrErrorAndThrowException(scanResponse);
+                // analizamos la respuesta            
+                if (scanResponse.startsWith(SpecialSequence305.COMMAND_OK.getText())) {
+                    // hemos finalizado el scan
+                    scanEnd = true;
+                } else if (scanResponse.startsWith("+PANSCAN")) {
+                    String[] scanRecord = scanResponse.split(":")[1].split(",");
+                    int channel = Integer.parseInt(scanRecord[0]);
+                    String PANID = scanRecord[1];
+                    String EPID = scanRecord[2];
+                    short profile = (short) Integer.parseInt(scanRecord[3], 16);
+                    boolean permitJoin = scanRecord[4].equals("01") ? true : false;
+                    PANScanResult psr = new PANScanResult(channel, PANID, EPID, profile, permitJoin);
+                    scanResult.add(psr);
+                } else {
+                    unlockPortForResponses();
+                    throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), scanResponse);
+                }
+            }
+            // liberamos el puerto
+            unlockPortForResponses();
+
+            // devolvemos resultados
+            return scanResult.toArray(new PANScanResult[0]);
+
+        }
+    }
+
+    @Override
+    public NetworkJoinedInfo createNetwork() throws TelegesisErrorException {
+        logger.trace("Gateway305::createNetwork()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.ESTABLISH_PERSONAL_AREA_NETWORK.getText();
+            // lanzamos la ejecucion
+            return executeNetworkJoinCommand(cmd, SERIAL_PORT_BLOCKING_16_SEC);
+        }
+    }
+
+    @Override
+    public NetworkJoinedInfo joinNetwork() throws TelegesisErrorException {
+        logger.trace("Gateway305::joinNetwork()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.JOIN_NETWORK.getText();
+            // lanzamos la ejecucion
+            return executeNetworkJoinCommand(cmd, SERIAL_PORT_BLOCKING_4_SEC);
+        }
+    }
+
+    @Override
+    public NetworkJoinedInfo joinNetwork(int channel, String PID) throws TelegesisErrorException {
+        logger.trace("Gateway305::joinNetwork(channel=" + channel + ", PID=" + PID + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.JOIN_SPECIFIC_PAN.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02d", channel)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + PID;
+            // lanzamos la ejecucion
+            return executeNetworkJoinCommand(cmd, SERIAL_PORT_BLOCKING_4_SEC);
+        }
+    }
+
+    /**
+     * Procesamiento comun para comandos:
+     * ESTABLISH_PERSONAL_AREA_NETWORK
+     * JOIN_NETWORK
+     * JOIN_SPECIFIC_PAN
+     * @param cmd comando a ejecutar
+     * @param blockingTime tiempo de bloqueo de puerto
+     * @return resultado de la operacion de red
+     * @throws TelegesisErrorException si ocurre algún error
+     */
+    private NetworkJoinedInfo executeNetworkJoinCommand(String cmd, int blockingTime) throws TelegesisErrorException {
+        logger.trace("Gateway305::executeNetworkJoinCommand(cmd=" + cmd + ", blockingTime=" + blockingTime + ")");
+        // bloqueamos la escritura en el puerto para recibir repsuestas, y 
+        // marcamos que JPAN debe considerarse como respuesta
+        lockPortForResponses(blockingTime);
+        spLstnr.capturePromptAsResponse("JPAN");
+
+        //Enviamos el comando directamente por el puerto serie
+        serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+
+        // recuperamos las respuestas (JPAN,OK)
+        String jpanResponse = spLstnr.waitForNextResponse(blockingTime);
+
+        // analizamos la respuesta
+        checkResponseNullOrErrorAndThrowException(jpanResponse);
+        NetworkJoinedInfo nji = null;
+        boolean unexpectedResponse = false;
+
+        if (jpanResponse.startsWith("JPAN")) {
+            // analizamos resultado
+            String[] jpanRecord = jpanResponse.split(":")[1].split(",");
+            int channel = Integer.parseInt(jpanRecord[0]);
+            String PANID = jpanRecord[1];
+            String EPID = jpanRecord[2];
+            nji = new NetworkJoinedInfo(channel, PANID, EPID);
+
+            // recuperamos la siguiente respuesta (debe ser OK)
+            jpanResponse = spLstnr.getNextResponse();
+            checkResponseNullOrErrorAndThrowException(jpanResponse);
+            if (!jpanResponse.equals(SpecialSequence305.COMMAND_OK.getText())) { // respuesta inesperada!!!
+                unexpectedResponse = true;
+            }
+        } else { // respuesta inesperada!!!
+            unexpectedResponse = true;
+        }
+
+        // liberamos puerto
+        unlockPortForResponses();
+        spLstnr.clearExpectedPrompts();
+        if (unexpectedResponse) {
+            //hacemos log de la respuesta
+            TelegesisErrorException tee = new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), jpanResponse);
+            logger.warn("Gateway305::executeNetworkJoinCommand: ERROR", tee);
+            return null;
+        } else {
+            return nji;
+        }
+
+    }
+
+    @Override
+    public void leaveNetwork() throws TelegesisErrorException {
+        logger.trace("Gateway305::leaveNetwork()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISASSOCIATE_LOCAL_DEVICE_FROM_PAN.getText();
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public short leaveNetworkRequest(String address) throws TelegesisErrorException {
+        logger.trace("Gateway305::leaveNetworkRequest(address=" + address + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISASSOCIATE_REMOTE_NODE_FROM_PAN.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public NetworkInformation getNetworkInformation() {
+        logger.trace("Gateway305::getNetworkInformation()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISPLAY_NETWORK_INFORMATION.getText();
+            // enviamos el mensaje, esperando respuesta
+            String response = null;
+            try {
+                response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            } catch (TelegesisErrorException ex) {
+                return null;
+            }
+
+            // analizamos la respuesta
+            if (response.startsWith("+N")) {
+                // analizamos resultado
+                String[] niRecord = response.split("=")[1].split(",");
+                if (niRecord[0].equalsIgnoreCase("NoPAN")) {
+                    //no hay red formada, devolvemos null
+                    return null;
+                } else {
+                    ZigbeeDeviceType devType = getTypeFromPrompt(niRecord[0]);
+                    int channel = Integer.parseInt(niRecord[1]);
+                    short power = (short) Integer.parseInt(niRecord[2], 16);
+                    String PID = niRecord[3];
+                    String EPID = niRecord[4];
+
+                    return new NetworkInformation(devType, channel, power, PID, EPID);
+                }
+            } else {
+                // respuesta inesperada
+                //TODO: hacer log del error
+                return null;
+            }
+
+        }
+    }
+
+    @Override
+    public short requestNeighbourTable(short index, String address) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNeighbourTable(index=" + index + ", address=" + address + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISPLAY_NEIGHBOUR_TABLE.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", index)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + address;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public void requestNodeId(String address) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodeId(address=" + address + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_NODEID.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address;
+            // enviamos el mensaje, esperando la respuesta (pero no hacemos nada con ella
+            writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+        }
+    }
+
+    @Override
+    public short requestNodeEUI64Addr(String address, String nodeId) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodeEUI64Addr(address=" + address + ", nodeId=" + nodeId + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_EUI.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeId;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public short requestNodeDescriptor(String address, String nodeId) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodeDescriptor(address=" + address + ", nodeId=" + nodeId + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_NODE_DESCRIPTOR.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeId;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public short requestNodePowerDescriptor(String address, String nodeId) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodePowerDescriptor(address=" + address + ", nodeId=" + nodeId + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_NODE_POWER_DESCRIPTOR.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeId;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public short requestNodeActiveEndPoints(String address, String nodeId) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodeActiveEndPoints(address=" + address + ", nodeId=" + nodeId + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_NODE_ACTIVE_ENDPOINT_LIST.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeId;
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public short requestNodeEndPointSimpleDescriptor(String address, String nodeId, short EP) throws TelegesisErrorException {
+        logger.trace("Gateway305::requestNodeEndPointSimpleDescriptor(address=" + address + ", nodeId=" + nodeId + ", EP=" + EP + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.REQUEST_ENDPOINT_SIMPLE_DESCRIPTOR.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeId
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + String.format("%02X", EP);
+            // enviamos el mensaje, esperando la respuesta
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+
+            //devolvemos el seq Number
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public void findNodesMatchingDescriptor(String profileId, String[] inClusterList, String[] outClusterList) throws TelegesisErrorException {
+        logger.trace("Gateway305::findNodesMatchingDescriptor(profileId=" + profileId + ", inClusterList=" + inClusterList + ", outClusterList=" + outClusterList + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.FIND_NODES_WHICH_MATCH_A_SPECIFIC_DESCRIPTOR.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + profileId
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText();
+            // añadimos inClusterList
+            cmd += String.format("%02d", inClusterList.length);
+            for (int i = 0; i < inClusterList.length; i++) {
+                cmd += SpecialSequence305.PARAMETER_SEPARATOR.getText() + inClusterList[i];
+            }
+            // añadimos outClusterList
+            cmd += SpecialSequence305.PARAMETER_SEPARATOR.getText() + String.format("%02d", outClusterList.length);
+            for (int i = 0; i < outClusterList.length; i++) {
+                cmd += SpecialSequence305.PARAMETER_SEPARATOR.getText() + outClusterList[i];
+            }
+
+            // enviamos el mensaje, esperando la respuesta, pero no hacemos nada con ella
+            writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+        }
+    }
+
+    @Override
+    public void annouceLocalNode() throws TelegesisErrorException {
+        logger.trace("Gateway305::annouceLocalNode()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.ANNOUNCE_LOCAL_DEVICE_IN_THE_NETWORK.getText();
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void setSourceRoute(String destNode, String[] route) throws TelegesisErrorException {
+        logger.trace("Gateway305::setSourceRoute(destNode=" + destNode + ", route=" + route + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SET_SOURCE_ROUTE_TO_REMOTE_DEVICE.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + destNode;
+            for (int i = 0; i < route.length; i++) {
+                cmd += SpecialSequence305.PARAMETER_SEPARATOR.getText() + route[i];
+            }
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public void findRoute(String address) throws TelegesisErrorException {
+        logger.trace("Gateway305::findRoute(address=" + address + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.FIND_THE_SOURCE_ROUTE_TO_A_REMOTE_DEVICE.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address;
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void scanNetwork(int numHops) throws TelegesisErrorException {
+        logger.trace("Gateway305::scanNetwork(numHops=" + numHops + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SCAN_NETWORK.getText();
+            if ((numHops >= 0) && (numHops <= 30)) {
+                cmd += SpecialSequence305.COMMAND_SEPARATOR.getText() + String.format("%02d", numHops);
+            }
+
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void updateNetworkKey() throws TelegesisErrorException {
+        logger.trace("Gateway305::updateNetworkKey()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.UPDATE_THE_NETWORK_KEY.getText();
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void becomeTrustCenter() throws TelegesisErrorException {
+        logger.trace("Gateway305::becomeTrustCenter()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.MAKE_LOCAL_DEVICE_THE_TRUST_CENTRE.getText();
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void becomeNetworkManager() throws TelegesisErrorException {
+        logger.trace("Gateway305::becomeNetworkManager()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.MAKE_THE_LOCAL_DEVICE_NETWORK_MANAGER.getText();
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void changeNetworkChannel() throws TelegesisErrorException {
+        logger.trace("Gateway305::changeNetworkChannel()");
+        changeNetworkChannel(0);
+    }
+
+    @Override
+    public void changeNetworkChannel(int channel) throws TelegesisErrorException {
+        logger.trace("Gateway305::changeNetworkChannel(channel=" + channel + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.CHANGE_THE_NETWORK_CHANNEL.getText();
+            if ((channel >= 11) && (channel <= 26)) {
+                cmd += SpecialSequence305.COMMAND_SEPARATOR.getText() + String.format("%02d", channel);
+            }
+
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public AddressTableEntry[] getAddressTable() {
+        logger.trace("Gateway305::getAddressTable()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISPLAY_ADDRESS_TABLE.getText();
+            // la respuesta a este comando puede vernir fraccionada, por lo que 
+            // indicamos que la respuesta puede tener un tamaño estimado de 260 bytes
+            spLstnr.setNextFrameExpectedSize(240); // este valor está tuneado para que funcione
+            // enviamos el mensaje, esperando respuesta
+            String response = null;
+            try {
+                response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            } catch (TelegesisErrorException ex) {
+                logger.warn("[GATEWAY] error requesting address table: " + ex.getLocalizedMessage());
+                return null;
+            }
+            // analizamos la respuesta
+            //[0]No. | Active |  ID  | EUI
+            //[1]00  |   N    | FFFF |FFFFFFFFFFFFFFFF
+            //[2]01  |   N    | FFFF |FFFFFFFFFFFFFFFF
+            //[3]02  |   N    | FFFF |FFFFFFFFFFFFFFFF
+            //[4]03  |   N    | FFFF |FFFFFFFFFFFFFFFF
+            //[5]04  |   N    | FFFF |FFFFFFFFFFFFFFFF
+            //[6]05  |   N    | FFFF |FFFFFFFFFFFFFFFF        
+            String[] lines = response.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            if (lines.length == 7) {
+                // analizamos resultado
+                AddressTableEntry[] ate = new AddressTableEntry[6];
+                for (int i = 1; i < lines.length; i++) {
+                    String line = lines[i].replace("|", ",");
+                    String[] record = line.split(",");
+                    short index = (short) Integer.parseInt(record[0].substring(0, 2), 16);
+                    boolean active = (record[1].trim().equals("N") ? false : true);
+                    String nodeID = record[2].trim();
+                    String EUI64Addr = record[3].trim();
+                    ate[i - 1] = new AddressTableEntry(index, active, nodeID, EUI64Addr);
+                }
+                return ate;
+            } else {
+                // respuesta inesperada
+                //TODO: hacer log del error
+                return null;
+            }
+
+        }
+    }
+
+    @Override
+    public void setAddressTableEntry(short index, String nodeID, String EUI64Addr) throws TelegesisErrorException {
+        logger.trace("Gateway305::setAddressTableEntry(index=" + index + ", nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SET_ADDRESS_TABLE_ENTRY.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", index)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + nodeID
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + EUI64Addr;
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public MulticastTableEntry[] getMulticastTable() {
+        logger.trace("Gateway305::getMulticastTable()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.DISPLAY_MULTICAST_TABLE.getText();
+
+            // la respuesta a este comando puede vernir fraccionada, por lo que 
+            // indicamos que la respuesta puede tener un tamaño estimado de 96 bytes
+            spLstnr.setNextFrameExpectedSize(96);
+            // enviamos el mensaje, esperando respuesta
+            String response = null;
+            try {
+                response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            } catch (TelegesisErrorException ex) {
+                logger.warn("[GATEWAY] error requesting multicast address table: " + ex.getLocalizedMessage());
+                return null;
+            }
+            // analizamos la respuesta
+            //[0]No. |  ID  | EP
+            //[1]00  | 0000 | 01  
+            //[2]01  | 0000 | 01  
+            //[3]02  | 0000 | 00  
+            //[4]03  | 0000 | 00  
+            //[5]04  | 0000 | 00          
+            String[] lines = response.split(SpecialSequence305.FRAME_SEPARATOR.getText());
+            if (lines.length == 6) {
+                // analizamos resultado
+                MulticastTableEntry[] mte = new MulticastTableEntry[5];
+                for (int i = 1; i < lines.length; i++) {
+                    String line = lines[i].replace("|", ",");
+                    String[] record = line.split(",");
+                    short index = (short) Integer.parseInt(record[0].substring(0, 2), 16);
+                    String ID = record[1].trim();
+                    short EP = (short) Integer.parseInt(record[2].trim(), 16);
+                    mte[i - 1] = new MulticastTableEntry(index, ID, EP);
+                }
+                return mte;
+            } else {
+                // respuesta inesperada
+                //TODO: hacer log del error
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public void setMulticastTableEntry(short index, String ID, short EP) throws TelegesisErrorException {
+        logger.trace("Gateway305::setMulticastTableEntry(index=" + index + ", ID=" + ID + ", EP=" + EP + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.SET_MULTICAST_TABLE_ENTRY.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", index)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + ID
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + String.format("%02X", EP);
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void sendBroadcast(int numHops, String data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendBroadcast(numHops=" + numHops + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // validamos numHops
+            if ((numHops < 0) || (numHops > 30)) {
+                numHops = 0;
+            }
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_BROADCAST.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02d", numHops)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + data;
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+    }
+
+    @Override
+    public void sendBroadcast(int numHops, byte[] data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendBroadcast(numHops=" + numHops + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // validamos numHops
+            if ((numHops < 0) || (numHops > 30)) {
+                numHops = 0;
+            }
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_BROADCAST_OF_BINARY_DATA.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", data.length)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + String.format("%02d", numHops)
+                    + SpecialSequence305.CMD_END.getText()
+                    + new String(data, Charset.forName("ISO-8859-1"));
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public short sendMessageRequest(String address, String data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendMessageRequest(address=" + address + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_UNICAST.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.DATA_SEPARATOR.getText()
+                    + data;
+            // enviamos el mensaje, esperando la respuesta (SEQ)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public short sendMessageRequest(String address, byte[] data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendMessageRequest(address=" + address + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_UNICAST_OF_BINARY_DATA.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", data.length)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + address
+                    + SpecialSequence305.CMD_END.getText()
+                    + new String(data, Charset.forName("ISO-8859-1"));
+            // enviamos el mensaje, esperando la respuesta (SEQ)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            return getSeqNumber(response);
+        }
+    }
+
+    @Override
+    public void sendMulticastBroadcast(int numHops, String ID, String data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendMulticastBroadcast(numHops=" + numHops + ", ID=" + ID + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // validamos numHops
+            if ((numHops < 0) || (numHops > 30)) {
+                numHops = 0;
+            }
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_MULTICAST.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02d", numHops)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + ID
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + data;
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+
+        }
+    }
+
+    @Override
+    public void sendMulticastBroadcast(int numHops, String ID, byte[] data) throws TelegesisErrorException {
+        logger.trace("Gateway305::sendMulticastBroadcast(numHops=" + numHops + ", ID=" + ID + ", data=" + data + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // validamos numHops
+            if ((numHops < 0) || (numHops > 30)) {
+                numHops = 0;
+            }
+            // componemos mensaje
+            String cmd = Command305.TRANSMIT_A_MULTICAST_OF_BINARY_DATA.getText()
+                    + SpecialSequence305.COMMAND_SEPARATOR.getText()
+                    + String.format("%02X", data.length)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + String.format("%02d", numHops)
+                    + SpecialSequence305.PARAMETER_SEPARATOR.getText()
+                    + ID
+                    + SpecialSequence305.CMD_END.getText()
+                    + new String(data, Charset.forName("ISO-8859-1"));
+            // enviamos el mensaje, esperando la respuesta (OK)
+            String response = writeCommand(cmd); //throws TelegesisErrorException if null or ERROR:XX
+            if (!SpecialSequence305.COMMAND_OK.getText().equals(response)) {
+                throw new TelegesisErrorException(ErrorCode305.BAD_RESPONSE.name(), response);
+            }
+        }
+
+    }
+
+    @Override
+    public String writeCommand(String cmd, boolean expectResponse) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeCommand(cmd=" + cmd + ", expectResponse=" + expectResponse + ")");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        synchronized (SYNC_COMMAND) { // sincronizamos para evitar solape de comandos
+            // comprobamos si esperamos respuesta
+            if (expectResponse) {
+                // enviamos el mensaje, esperando la respuesta
+                return writeCommand(cmd);
+            } else {
+                //Enviamos el comando por el puerto serie, sin esperar respuesta
+                serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+                return null;
+            }
+        }
+
+    }
+
+    /**
+     * Envía un comando, por el puerto serie, esperando la respuesta 
+     * predeterminada del gateway ([response][OK] o [ERROR])
+     * @param cmd comando a enviar
+     * @return respuesta recibida ([response] o [OK])
+     * @throws TelegesisErrorException si se ha recibido un [ERROR] o null
+     */
+    private String writeCommand(String cmd) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeCommand(cmd=" + cmd + ")");
+
+        // llamamos al método con timeout por defecto
+        return writeCommand(cmd, COMMAND_RESPONSE_TIMEOUT);
+
+    }
+
+    /**
+     * Envía un comando, por el puerto serie, esperando la respuesta 
+     * predeterminada del gateway ([response][OK] o [ERROR])
+     * @param cmd comando a enviar
+     * @param milliseconds tiempo de bloqueo de puerto para esperar respuesta
+     * @return respuesta recibida ([response] o [OK])
+     * @throws TelegesisErrorException si se ha recibido un [ERROR] o null
+     */
+    private String writeCommand(String cmd, int milliseconds) throws TelegesisErrorException {
+        logger.trace("Gateway305::writeCommand(cmd=" + cmd + ", milliseconds=" + milliseconds + ")");
+        // bloqueamos el acceso al puerto para recibir la respuesta
+        lockPortForResponses(milliseconds);
+
+        //Enviamos el comando por el puerto serie
+        serialPort.writeString(cmd + SpecialSequence305.CMD_END.getText());
+
+        // recuperamos la respuesta
+        String response = this.spLstnr.waitForNextResponse(milliseconds);
+        // comprobamos respuestas de error (null o ERROR)
+        checkResponseNullOrErrorAndThrowException(response);
+
+        // comprobamos respuesta distinta de OK
+        if (response.startsWith(SpecialSequence305.COMMAND_OK.getText())) {
+            // liberamos puerto y borramos marca de respuesta
+            unlockPortForResponses();
+            return response;
+        } else {
+            // se trata de un comando con respuesta local, a continuación deberíamos
+            // tener un OK
+            spLstnr.setNextFrameExpectedSize(1);
+            lockPortForResponses(milliseconds);
+            String secResponse = spLstnr.waitForNextResponse(milliseconds);
+            checkResponseNullOrErrorAndThrowException(secResponse);
+            // liberamos puerto y borramos marca de respuesta
+            unlockPortForResponses();
+            return response;
+
+        }
+    }
+
+    // </editor-fold>
+    @Override
+    public boolean open() {
+        logger.trace("Gateway305::open()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        logger.info("[Gateway open] Checking available gateway at " + serialPort);
+
+        // preinicializamos la marca de gateway abierto a false
+        gtwyIsOpen = false;
+
+        // comprobamos si el puerto está abierto
+        if (!serialPort.isOpen()) {
+            // intentamos abrir el puerto, si hay error devolvemos false
+            if (!serialPort.open()) {
+                logger.info("[Gateway open] Error opening serial port " + serialPort);
+                return false;
+            }
+        }
+
+        // registramos el listener del puerto 
+        serialPort.registerListener(spLstnr);
+
+        // Recuperamos el productID
+        String[] pid = getProductId();
+        // comprobamos resultados
+        if (pid == null) { // comprobamos respuesta válida
+            close();
+            return false;
+        } else if (pid.length != 3) {
+            close();
+            return false;
+        }
+
+        // guardamos respuesta
+        deviceName = pid[0].trim();
+        firmwareRevision = pid[1].trim();
+        dongleAddress = pid[2].trim();
+
+        // comprobamos versión base
+        boolean isFWComp = false;
+        if (firmwareRevision.startsWith(FIRMWARE_REVISION)) {
+            isFWComp = true;
+        } else // comprobamos compatibilidad firmware
+        {
+            for (int i = 0; i < COMPATIBLE_FIRMWARE.length; i++) {
+                if (COMPATIBLE_FIRMWARE[i].equals(firmwareRevision)) {
+                    isFWComp = true;
+                    break;
+                }
+            }
+        }
+
+        // si no es compatible, cerramos el puerto
+        if (!isFWComp) {
+            close();
+            return false;
+        }
+
+        // configuramos el gateway
+        if (!init()) {
+            close();
+            return false;
+        }
+
+        // hemos llegado hasta aquí, todo correcto, marcamos gateway abierto y devolvemos true
+        logger.info("Gateway sucessfully open");
+        gtwyIsOpen = true;
+        return gtwyIsOpen;
+    }
+
+    /**
+     * Realiza la configuración básica del gateway
+     * @return true si se han ejecutado todas las operaciones correctamente
+     */
+    private boolean init() {
+        logger.trace("Gateway305::init()");
+
+        // escribimos la configuración de registros
+        try {
+            this.writeRegister(S_REG_ADDR_PROMPT_ENABLE_1, DEFAULT_PROMPT_ENABLE_1);
+            this.writeRegister(S_REG_ADDR_PROMPT_ENABLE_2, DEFAULT_PROMPT_ENABLE_2);
+            this.writeRegisterBit(S_REG_ADDR_UART_SETUP, S_REG_BIT_NO_COMMAND_ECHO, true);
+        } catch (TelegesisErrorException ex) {
+            logger.warn("Error while initializing gateway", ex);
+            return false;
+        }
+
+
+        return true;
+
+    }
+
+    @Override
+    public boolean close() {
+        logger.trace("Gateway305::close()");
+        // comprobamos el bloqueo del gateway
+        checkLock();
+
+        gtwyIsOpen = false;
+        // eliminamos el registro del listener con el puerto serie
+        serialPort.unregisterListener(spLstnr);
+        logger.info("Gateway closed");
+        return true;
+    }
+
+    @Override
+    public boolean isOpen() {
+        logger.trace("Gateway305::isOpen()");
+        return gtwyIsOpen;
+    }
+
+    @Override
+    public SerialConnection getConnection() {
+        logger.trace("Gateway305::getConnection()");
+
+        return serialPort;
+
+    }
+    // #########################################################################
+
+    private ZigbeeDeviceType getTypeFromPrompt(String prompt) {
+        logger.trace("Gateway305::getTypeFromPrompt(prompt=" + prompt + ")");
+        if (prompt.startsWith(Prompt305.COO_ANNOUNCE.getText())) {
+            return ZigbeeDeviceType.Coordinator;
+        } else if (prompt.startsWith(Prompt305.FFD_ANNOUNCE.getText())) {
+            return ZigbeeDeviceType.Router;
+        } else if (prompt.startsWith("RFD")) { // asumimos EndDevice para consuatl en tabla de vecinos
+            return ZigbeeDeviceType.EndDevice;
+        } else if (prompt.startsWith(Prompt305.ZED_ANNOUNCE.getText())) {
+            return ZigbeeDeviceType.EndDevice;
+        } else if (prompt.startsWith(Prompt305.MED_ANNOUNCE.getText())) {
+            return ZigbeeDeviceType.MobileEndDevice;
+        } else if (prompt.startsWith(Prompt305.SED_ANNOUNCE.getText())) {
+            return ZigbeeDeviceType.SleepyEndDevice;
+        } else { // NEWNODE
+            return ZigbeeDeviceType.Unknown;
+        }
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/GatewayFactoryImpl.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/GatewayFactoryImpl.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/GatewayFactoryImpl.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,46 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.core.io.serial.SerialConnection;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class GatewayFactoryImpl implements es.unizar.howlab.core.zigbee.telegesis.gateway.GatewayFactory {
+
+    @Override
+    public Gateway createGateway(SerialConnection connection) {
+        
+        // comprobamos para todas las implementaciones soportadas
+        Gateway testGtwy;
+        
+        // comprobamos version R305X
+        testGtwy = new Gateway305(connection);
+        if (testGtwy.open()){
+            return testGtwy;
+        } else {
+            testGtwy.close();
+        }
+        
+        // no es un gateway valido
+        return null;
+    }
+    
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/SerialListener.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/SerialListener.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/SerialListener.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,521 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import es.unizar.howlab.core.io.serial.SerialConnection.State;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.Prompt305;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.SpecialSequence305;
+import es.unizar.howlab.core.io.serial.*;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Class for
+ * @author alvaro
+ */
+public class SerialListener implements SerialConnectionListener {
+
+    private byte[] msgBuffer = null;
+    private LinkedBlockingQueue<String> strPrompts = new LinkedBlockingQueue<String>();
+    private LinkedBlockingQueue<String> strResponses = new LinkedBlockingQueue<String>();
+    // Coleccion para almacenar los promts de longitud variable
+    ArrayList variableLengthPrompt = new ArrayList();
+    final MessageParser msgParser;
+    // Logger
+    Log logger = LogFactory.getLog(SerialListener.class.getName());
+
+    /**
+     * Constructor. realiza las operaciones de inicialización del listener
+     */
+    public SerialListener(MessageParser parser) {
+        logger.trace("SerialListener::SerialListener(parser=" + parser + ")");
+
+        msgParser = parser;
+        // Inicializamos la coleccion de promts de longitud variable
+        variableLengthPrompt.add(Prompt305.BROADCAST_RECEIVED);
+        variableLengthPrompt.add(Prompt305.MULTICAST_RECEIVED);
+        variableLengthPrompt.add(Prompt305.UNICAST_RECEIVED);
+        variableLengthPrompt.add(Prompt305.END_POINT_MESSAGE);
+
+
+    }
+
+    @Override
+    public void stateChanged(State state, SerialConnection serial) {
+        switch (state) {
+            case OPEN:
+            case PORT_IN_USE:
+            case TOO_MANY_LISTENERS:
+            case UNKNOWN:
+            case NO_SUCH_PORT:
+            case UNSUPPORTED_COMM:
+                // Estos estados no deberían producirse o no nos interesan
+                break;
+            case UNPLUGGED:
+                // notificamos error para cerrar el gateway
+                msgParser.serialPortError();
+                break;
+            case CLOSE:
+                // notificamos error para cerrar el gateway
+                msgParser.serialPortError();
+                break;
+        }
+    }
+
+    /**
+     * Interfaz para notificar de la existencia de mensajes recibidos
+     */
+    public interface MessageParser {
+
+        /**
+         * Notifica que se han recibido prompts
+         */
+        public void hasNewPromps();
+
+        /**
+         * Notifica de un error de puerto
+         */
+        public void serialPortError();
+    }
+
+    /**
+     * Comprueba si tenemos nuevos datos
+     * @return 
+     */
+    public boolean hasNewFrames() {
+        logger.trace("SerialListener::hasNewFrames()");
+        return !strPrompts.isEmpty();
+    }
+
+    @Override
+    public void eventMessage(SerialMessage message, SerialConnection serialConnection) {
+        logger.trace("SerialListener::eventMessage(message=" + message + ", serialConnection=" + serialConnection + ")");
+        switch (message.getType()) {
+            case messageReceived:
+                processIncommingMessage(message.getBinaryMessage());
+                break;
+            case commandSent: // mensaje saliente, ignoramos
+                break;
+        }
+    }
+
+    /**
+     * Acumula los mensajes recibidos
+     * @param incommingMsg 
+     */
+    public synchronized void processIncommingMessage(byte[] incommingMsg) {
+        logger.trace("SerialListener::processIncommingMessage(incommingMsg=" + incommingMsg + ")");
+        logger.info(String.format("received %d bytes by SerialListener", incommingMsg.length));
+        // acumulamos mensaje recibido
+        if (msgBuffer == null) {
+            msgBuffer = incommingMsg.clone();
+        } else {
+            byte[] previousMsg = msgBuffer.clone();
+            msgBuffer = new byte[incommingMsg.length + previousMsg.length];
+            System.arraycopy(previousMsg, 0, msgBuffer, 0, previousMsg.length);
+            System.arraycopy(incommingMsg, 0, msgBuffer, previousMsg.length, incommingMsg.length);
+        }
+
+        // Lanzamos el procesamiento del mensaje
+        parseMsgBuffer();
+
+    }
+
+    /**
+     * Recupera el siguiente prompt recibido (eliminándolo de la cola)
+     * @return Siguiente prompt recibido, o null si no hay ninguno
+     */
+    public String getNextPrompt() {
+        logger.trace("SerialListener::getNextPrompt()");
+        try {
+            return strPrompts.poll(10, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ex) {
+            logger.warn("SerialListener::getNextPrompt() interrupted", ex);
+            return null;
+        }
+    }
+
+    /**
+     * Recupera la siguiente respuesta a comando recibida (aliminádolo de la cola)
+     * @return Siguiente respuesta, o null si no hay ninguna
+     */
+    public String getNextResponse() {
+        logger.trace("SerialListener::getNextResponse()");
+        try {
+            return strResponses.poll(10, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ex) {
+            logger.warn("SerialListener::getNextResponse() interrupted", ex);
+            return null;
+        }
+    }
+
+    /**
+     * Recupera la siguiente repuesta (eliminándola de la cola), esperando 
+     * @param timeout tiempo antes de abandonar respuesta
+     * @return Siguiente respuesta recibida, o null si no hay ninguna
+     */
+    public String waitForNextResponse(long timeout) {
+        logger.trace("SerialListener::waitForNextResponse(timeout=" + timeout + ")");
+        try {
+            return strResponses.poll(timeout, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ex) {
+            logger.warn("SerialListener::waitForNextResponse() interrupted", ex);
+            return null;
+        }
+    }
+
+    /**
+     * Examina el siguiente prompt recibido (sin eliminarlo de la cola)
+     * @return Siguiente prompt recibido, o null si no hay ninguno
+     */
+    public String inspectNextPrompt() {
+        logger.trace("SerialListener::inspectNextPrompt()");
+        return strPrompts.peek();
+    }
+
+    /**
+     * Examina la siguiente respuesta a comando recibida (sin eliminarlo de la cola)
+     * @return Siguiente respuesta, o null si no hay ninguna
+     */
+    public String inspectNextResponse() {
+        logger.trace("SerialListener::inspectNextResponse()");
+        return strResponses.peek();
+    }
+    private ArrayList promptsToCaptureAsResponses = new ArrayList();
+
+    /**
+     * Establece un prompt para que se considere respuesta a un comando
+     * @param prompt prompt experado
+     */
+    public void capturePromptAsResponse(String prompt) {
+        logger.trace("SerialListener::capturePromptAsResponse(prompt=" + prompt + ")");
+        promptsToCaptureAsResponses.add(prompt);
+    }
+
+    /**
+     * Elimina un prompt de la lista de prompts a capturar como respuesta
+     * @param prompt 
+     */
+    public void removeExpectedPrompt(String prompt) {
+        logger.trace("SerialListener::removeExpectedPrompt()");
+        promptsToCaptureAsResponses.remove(prompt);
+    }
+
+    /**
+     * Vacía la lista de prompts a capturar
+     */
+    public void clearExpectedPrompts() {
+        logger.trace("SerialListener::clearExpectedPrompts()");
+        promptsToCaptureAsResponses.clear();
+    }
+    private boolean expectResponse;
+    private int nextFrameExpectedSize;
+
+    /**
+     * Establece el tamaño estimado del frame a recibir
+     * @param frameSize Tamaño estimado del frame a recibir
+     */
+    public void setNextFrameExpectedSize(int frameSize) {
+        logger.trace("SerialListener::setNextFrameExpectedSize(frameSize=" + frameSize + ")");
+        nextFrameExpectedSize = frameSize;
+    }
+
+    /**
+     * Establece la marca de que esperamos una respuesta
+     */
+    public void setExpectResponse() {
+        logger.trace("SerialListener::setExpectResponse()");
+        expectResponse = true;
+    }
+
+    /**
+     * Borra la marca de esperar respuesta, con lo que todos los mensajes 
+     * entrantes serán intepretados como prompts
+     */
+    public void clearExpectResponse() {
+        logger.trace("SerialListener::clearExpectResponse()");
+        expectResponse = false;
+    }
+
+    /**
+     * Realiza el procesamiento del buffer de entrada
+     */
+    private void parseMsgBuffer() {
+        logger.trace("SerialListener::parseMsgBuffer()");
+        // recuperamos las tramas de mensajes
+        String frame = getNextFrameFromMsgBuffer();
+        boolean hasNewPrompt = false;
+        while (frame != null) {
+            logger.info("Received frame by SerialListener: " + frame);
+            // comprobamos si no está marcado el flag de esperando respuesta, 
+            //en cuyo caso directamente lo interpretamos como un prompt
+            if (!expectResponse) {
+                hasNewPrompt = true;
+                strPrompts.add(frame);
+            } else { // si esperamos una respuesta, comprobamos si se trata de una respuesta o un prompt
+                // comprobamos primero si se trata de un prompt a capturar como respuesta
+                String command = frame.split(":")[0];
+                if (promptsToCaptureAsResponses.contains(command)) {
+                    strResponses.add(frame);
+                    promptsToCaptureAsResponses.remove(command);
+                } else {
+                    // comprobamos si se trata de un promot o una respuesta            
+                    Prompt305[] promptList = Prompt305.values();
+                    boolean isPrompt = false;
+                    for (int i = 0; i < promptList.length; i++) {
+                        if (promptList[i].chekMessage(frame.getBytes(Charset.forName("ISO-8859-1")), 0)) {
+                            isPrompt = true;
+                            break;
+                        }
+                    }
+                    if (isPrompt) {
+                        strPrompts.add(frame);
+                        hasNewPrompt = true;
+                    } else { // se trata de una respuesta a un comando
+                        strResponses.add(frame);
+                    }
+                }
+
+            }
+            // recuperamos el siguiente frame
+            frame = getNextFrameFromMsgBuffer();
+        }
+        //Notificamos la existencia de mensajes
+        if (hasNewPrompt) {
+            msgParser.hasNewPromps();
+        }
+
+    }
+
+    /**
+     * Obtiene la siguiente trama siguiente en el mensaje, y la elimina del buffer.
+     * @return String con la trama del mensaje o null si no hay trama
+     */
+    private String getNextFrameFromMsgBuffer() {
+        logger.trace("SerialListener::getNextFrameFromMsgBuffer()");
+        /*
+         * La estructura del mensaje es:
+         * 0x0D, 0x0A ==> inicio de trama
+         * 0xXX, 0xXX, ... ==> datos
+         * 0x0D, 0x0A ==> fin de trama
+         * 
+         * Nota: los datos también pueden contener la secuencia {0x0D, 0x0A}
+         * (salto de línea), por lo que el final de trama efectivo debe 
+         * considerarse si:
+         * - no hay más datos (esto implica cierto riesgo), o
+         * - el resto del mensaje empieza con un inicio de trama 
+         */
+
+        // Comprobamos que el inicio del mensaje es correcto
+        //int startMsgPos = findSequence(msgBuffer, SpecialSequence305.FRAME_SEPARATOR.getBytes(Charset.forName("ISO-8859-1")), 0);
+        int startMsgPos = findSequence(new String(msgBuffer, Charset.forName("ISO-8859-1")), SpecialSequence305.FRAME_SEPARATOR.getText(), 0);
+        if (startMsgPos < 0) { // no hemos encontrado el inicio del mensaje, abandonamos
+            return null;
+        } else if (startMsgPos > 0) { // hemos recibido un mensaje incompleto, borramos el principio y notificamos warning
+            //Log warning de mensaje incompleto
+            byte[] discardBuffer = new byte[startMsgPos];
+            System.arraycopy(msgBuffer, 0, discardBuffer, 0, discardBuffer.length);
+            logger.warn(String.format("[SerialListener] Received message incomplete. Discarding %d bytes (%s)", startMsgPos, new String(discardBuffer, Charset.forName("ISO-8859-1"))));
+            // guardamos el mensaje a procesar    
+            byte[] trimBuffer = new byte[msgBuffer.length - startMsgPos];
+            System.arraycopy(msgBuffer, startMsgPos, trimBuffer, 0, trimBuffer.length);
+            msgBuffer = trimBuffer.clone();
+        }
+
+        //Nota: a partir de este punto, el mensaje empieza con un inicio de trama en la posicion 0
+
+        // Comprobamos el extremo final
+        boolean frameEndFound = false;
+        int frameSepLength = SpecialSequence305.FRAME_SEPARATOR.getBytes().length;
+        // para buscar el final de la trama, estimamos cual es la posición del 
+        // final de la misma en función de la trama recibida
+        int nextSearchEndPos = frameSepLength + estimateFrameMinLength(msgBuffer, frameSepLength);
+        int endMsgPos = nextSearchEndPos; // por inicializarlo en algo...
+        while (!frameEndFound) {
+            //endMsgPos = findSequence(msgBuffer, SpecialSequence305.FRAME_SEPARATOR.getBytes(Charset.forName("ISO-8859-1")), nextSearchEndPos);
+            endMsgPos = findSequence(new String(msgBuffer, Charset.forName("ISO-8859-1")), SpecialSequence305.FRAME_SEPARATOR.getText(), nextSearchEndPos);
+            // comprobamos las condiciones de final de trama
+            if (endMsgPos < 0) { // no hemos encontrado el final del mensaje, abandonamos
+                return null;
+            } else if ((endMsgPos - frameSepLength < nextFrameExpectedSize)) { // comprobamos si el tamaño del frame se corresponde con lo que esperabamos recibir, y en caso negativo seguimos buscando
+                nextSearchEndPos = endMsgPos + frameSepLength;
+            } else if ((endMsgPos + frameSepLength) == msgBuffer.length) { // no hay más datos
+                frameEndFound = true;
+                //} else if (checkSequence(msgBuffer, SpecialSequence305.FRAME_SEPARATOR.getBytes(Charset.forName("ISO-8859-1")), endMsgPos + frameSepLength)) { // comprobamos si los datos siguientes contienen el inicio de trama
+            } else if (checkSequence(new String(msgBuffer, Charset.forName("ISO-8859-1")), SpecialSequence305.FRAME_SEPARATOR.getText(), endMsgPos + frameSepLength)) { // comprobamos si los datos siguientes contienen el inicio de trama
+                frameEndFound = true;
+            } else { // modificamos el indice para buscar la secuencia y continuamos buscando
+                nextSearchEndPos = endMsgPos + frameSepLength;
+            }
+        }
+
+        // recuperamos el frame
+        byte[] msgFrame = new byte[endMsgPos - frameSepLength];
+        System.arraycopy(msgBuffer, frameSepLength, msgFrame, 0, msgFrame.length);
+        String nextFrame = new String(msgFrame, Charset.forName("ISO-8859-1"));
+
+        // guardamos el resto del mensaje
+        byte[] remainderMsg = new byte[msgBuffer.length - endMsgPos - frameSepLength];
+        System.arraycopy(msgBuffer, endMsgPos + frameSepLength, remainderMsg, 0, remainderMsg.length);
+        msgBuffer = remainderMsg.clone();
+
+        // comprobacion de mensajes con doble FRAME_SEPARATOR al principio
+        if (nextFrame.startsWith(SpecialSequence305.FRAME_SEPARATOR.getText())) {
+            nextFrame = nextFrame.substring(SpecialSequence305.FRAME_SEPARATOR.getBytes().length);
+        }
+        
+        //Restablecemos el tamaño esperado para el proximo frame
+        nextFrameExpectedSize = 1;
+        
+        logger.debug(String.format("[SerialListener] getNexFrame: frame=%s, length=%d", nextFrame, nextFrame.length()));
+        // devolvemos el frame localizado
+        return nextFrame;
+    }
+
+    /**
+     * Estima la longitud mínima de la trama, de acuerdo al contenido de la misma
+     * @param msg Mensaje a analizar
+     * @param startPos Punto a partir del cual se busca
+     * @return posible longitud de la trama
+     */
+    private int estimateFrameMinLength(byte[] msg, int startPos) {
+        logger.trace("SerialListener::estimateFrameMinLength(msg=" + msg + ", startPos=" + startPos + ")");
+        int estimateLength = 0;
+
+        // comprobamos si se trata de una respuesta tipo prompt de longitud variable
+        Iterator it = variableLengthPrompt.iterator();
+        while (it.hasNext()) {
+//------------------------------------------------------------------------------
+//            Posible alternativa para omitir el uso de Prompt305
+//------------------------------------------------------------------------------
+//            String strTestPrompt = ((Prompt305) it.next()).getText();
+//            String inMsg = new String(msg);
+//            int pos = inMsg.indexOf(strTestPrompt, startPos);
+//            if (pos >= startPos) {
+//                int sizePos = findSequence(msg, "=".getBytes(Charset.forName("ISO-8859-1")), startPos) - 2;
+//                String strDataSize = new String(msg, sizePos, 2);
+//                int dataSize = Integer.parseInt(strDataSize);
+//                estimateLength = (sizePos - startPos) + dataSize + 3; //...XX=<data>
+//                break;
+//            } else {
+//                estimateLength = strTestPrompt.length();
+//            }
+//------------------------------------------------------------------------------
+
+            Prompt305 testPrompt = (Prompt305) it.next();
+            if (testPrompt.chekMessage(msg, startPos)) {
+                if (testPrompt.getHasData()) {
+                    int sizePos = startPos + testPrompt.getMinSize();
+                    if (sizePos == startPos) {
+                        //sizePos = findSequence(msg, "=".getBytes(Charset.forName("ISO-8859-1")), startPos) - 2;
+                        sizePos = findSequence(new String(msg, Charset.forName("ISO-8859-1")), "=", startPos) - 2;
+                    }
+                    String strDataSize = new String(msg, sizePos, 2, Charset.forName("ISO-8859-1"));
+                    int dataSize = Integer.parseInt(strDataSize, 16);
+                    estimateLength = (sizePos - startPos) + dataSize + 3; //...XX=<data>
+                } else {
+                    estimateLength = testPrompt.getMinSize();
+                }
+                break;
+            }
+        }// el resto de opciones son mensajes en respuesta a un comando que deben seguir un fin de trama
+
+        // devolvemos la longitud estimada
+        return estimateLength;
+    }
+
+    /**
+     * Devuelve la posición de inicio de la secuencia en el mensaje
+     * @param message mensaje a analizar
+     * @param sequence secuencia a buscar
+     * @param start posición de inicio de búsqueda
+     * @return posición donde se ubica la seuencia
+     */
+    private int findSequence(byte[] message, byte[] sequence, int start) {
+        logger.trace("SerialListener::findSequence(message=" + message + ", sequence=" + sequence + ", start=" + start + ")");
+        int startPos = -1;
+        // recorremos el mensaje
+        for (int i = start; i <= message.length - sequence.length; i++) {
+            // Buscamos la secuencia en la posición del índice
+            if (checkSequence(message, sequence, i)) {
+                startPos = i;
+                break;
+            }
+        }
+
+        return startPos;
+    }
+
+    /**
+     * Devuelve la posición de inicio de la secuencia en el mensaje
+     * @param message mensaje a analizar
+     * @param sequence secuencia a buscar
+     * @param start posición de inicio de búsqueda
+     * @return posición donde se ubica la seuencia
+     */
+    private int findSequence(String message, String sequence, int start) {
+        logger.trace("SerialListener::findSequence(message=" + message + ", sequence=" + sequence + ", start=" + start + ")");
+        return message.indexOf(sequence, start);
+    }
+
+    /**
+     * Comprueba si el mensaje contiene la secuencia en la posición indicada
+     * (no hace búsqueda)
+     * @param message mensaje que contiene (o no) la secuencia
+     * @param sequence secuencia a buscar
+     * @param pos posición donde queremos comprobar la secuencia
+     * @return TRUE si coincide, FALSE si no
+     */
+    private boolean checkSequence(byte[] message, byte[] sequence, int pos) {
+        logger.trace("SerialListener::checkSequence(message=" + message + ", sequence=" + sequence + ", pos=" + pos + ")");
+        // comprobamos tamaño
+        if (message.length < sequence.length + pos) {
+            return false;
+        }
+        // comprobamos secuencia
+        for (int i = 0; i < sequence.length; i++) {
+            // si no coincide la secuencia en un carácter, devolvemos FALSE
+            if (message[pos + i] != sequence[i]) {
+                return false;
+            }
+        }
+        // si hemos llegado aquí, coincide la secuencia, devolvemos TRUE
+        return true;
+    }
+
+    /**
+     * Comprueba si el mensaje contiene la secuencia en la posición indicada
+     * (no hace búsqueda)
+     * @param message mensaje que contiene (o no) la secuencia
+     * @param sequence secuencia a buscar
+     * @param pos posición donde queremos comprobar la secuencia
+     * @return TRUE si coincide, FALSE si no
+     */
+    private boolean checkSequence(String message, String sequence, int pos) {
+        logger.trace("SerialListener::checkSequence(message=" + message + ", sequence=" + sequence + ", pos=" + pos + ")");
+        if (message.indexOf(sequence, pos) == pos) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/Activator.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/Activator.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/Activator.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,76 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.osgi;
+
+import es.unizar.howlab.core.zigbee.telegesis.gateway.GatewayFactory;
+import es.unizar.howlab.core.io.serial.SerialConnection;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.GatewayFactoryImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+    private static BundleContext bc = null;
+    private ServiceRegistration srGF = null;
+    private ServiceTracker st = null;
+    SerialConnectionServiceTracker stc = null;
+    // Logger
+    static Log logger = LogFactory.getLog(Activator.class.getName());
+
+    public static BundleContext getBundleContext(){
+        logger.trace("Activator::getBundleContext()");
+        return bc;
+    }
+    
+    @Override
+    public void start(BundleContext context) throws Exception {
+        logger.trace("Activator::start(context=" + context + ")");
+
+        // guardamos el bundle m_context
+        bc = context;
+
+        // Creamos el GatewayFactoryImpl
+        GatewayFactory gtwyF = new GatewayFactoryImpl();
+        // Registramos el GatewayFactoryImpl //TODO: revisar propiedades en el registro?
+        srGF = context.registerService(GatewayFactory.class.getName(), gtwyF, null);
+        
+        // Creamos el tracker para el puerto serie que se encargará de crear los gateways
+        stc = new SerialConnectionServiceTracker();
+        st = new ServiceTracker(bc, SerialConnection.class.getName(), stc);
+        // arrancamos el tracker
+        st.open();
+
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        logger.trace("Activator::stop(context=" + context + ")");
+        // paramos el service tracker
+        st.close();
+
+        // paramos el SerialConnectionServiceTracker para despublicar los gateways
+        stc.stop();
+
+        // desregistramos el Gateway Factory
+        srGF.unregister();
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/SerialConnectionServiceTracker.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/SerialConnectionServiceTracker.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/osgi/SerialConnectionServiceTracker.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,133 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.osgi;
+
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.GatewayFactory;
+import es.unizar.howlab.core.io.serial.SerialConnection;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.osgi.Constants;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ *
+ * @author alvaro
+ */
+public class SerialConnectionServiceTracker implements ServiceTrackerCustomizer {
+
+    HashMap<ServiceReference, ServiceRegistration> serialConnectionsUsed = new HashMap<ServiceReference, ServiceRegistration>();
+
+    /**
+     * Ejecuta las operaciones de detencion del tracker
+     */
+    public void stop() {
+
+        // Despublicamos los gateways publicados
+        Iterator<ServiceReference> it = serialConnectionsUsed.keySet().iterator();
+        BundleContext bc = Activator.getBundleContext();
+        while (it.hasNext()) {
+            ServiceReference srefSerial = it.next();
+            // recuperamos el gateway correspondiente para cerrarlo
+            ServiceRegistration sregGtwy = serialConnectionsUsed.get(srefSerial);
+            Gateway gt = (Gateway) bc.getService(sregGtwy.getReference());
+            gt.close();
+            
+            // desregisramos el gatewaw
+            sregGtwy.unregister();
+
+            // soltamos el puerto serie
+            bc.ungetService(srefSerial);
+        }
+
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+
+        BundleContext bc = Activator.getBundleContext();
+        // recuperamos el GatewayFactory
+        ServiceReference srFactory = bc.getServiceReference(GatewayFactory.class.getName());
+        if (srFactory == null) { // no se debería dar esta situación, pero...
+            return null;
+        }
+        GatewayFactory gtwyF = (GatewayFactory) bc.getService(srFactory);
+
+        // recuperamos el puerto serie
+        SerialConnection serialCNX = (SerialConnection) bc.getService(reference);
+
+
+        // intentamos crear un gateway en el puerto serie
+        Gateway gtwy = gtwyF.createGateway(serialCNX);
+        if (gtwy == null) {
+            // soltamos el puerto serie
+            bc.ungetService(reference);
+            serialCNX = null;
+        } else {
+            // registramos el Gateway en OSGi
+            Dictionary properties = new Hashtable();
+            properties.put(Constants.GATEWAY_DEVICE_NAME, gtwy.getDeviceName());
+            properties.put(Constants.GATEWAY_DONGLE_ADDRESS, gtwy.getDongleAddress());
+            properties.put(Constants.GATEWAY_FIRMWARE_REVISION, gtwy.getFirmwareRevision());
+            ServiceRegistration srGateway = bc.registerService(Gateway.class.getName(), gtwy, properties);
+            
+            // lo añadimos a la lista de gateways
+            serialConnectionsUsed.put(reference, srGateway);
+        }
+
+        // Soltamos el GatewayFactory
+        bc.ungetService(srFactory);
+        gtwyF = null;
+
+        // devolvemos el puerto serie (será null si no hemos abierto un gateway
+        return serialCNX;
+
+    }
+
+    @Override
+    public void modifiedService(ServiceReference reference, Object service) {
+        // no hacemos nada
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        // Comprobamos si es un puerto asociado a un SerialConnection
+        if (serialConnectionsUsed.containsKey(reference)) {
+            BundleContext bc = Activator.getBundleContext();
+            // Recuperamos el Gateway
+            ServiceRegistration sregGateway = serialConnectionsUsed.get(reference);
+            Gateway gtwy = (Gateway) bc.getService(sregGateway.getReference());
+            // cerramos el gateway
+            gtwy.close();
+            // despublicamos el gateway            
+            sregGateway.unregister();
+
+            // Soltamos el puerto serie
+            bc.ungetService(reference);
+
+            // los eliminamos de la lista
+            serialConnectionsUsed.remove(reference);
+
+        }
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Command305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Command305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Command305.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,96 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol;
+
+import java.nio.charset.Charset;
+
+/**
+ *
+ * @author alvaro
+ */
+public enum Command305 {
+
+    DISPLAY_PRODUCT_IDENTIFICATION("ATI"),
+    SOFTWARE_RESET("ATZ"),
+    RESTORE_FACTORY_DEFAULTS("AT&F"),
+    ENTER_THE_BOOTLOADER_MENU("AT+BLOAD"),
+    CLONE_LOCAL_NODE_TO_REMOTE_NODE("AT+CLONE"),
+    PASS_NEW_FIRMWARE_IMAGE_TO_REMOTE_NODE("AT+PASSTHROUGH"),
+    RECOVER_FROM_A_FAILED_CLONE_ATTEMPT("AT+RECOVER"),
+    S_REGISTER_ACCESS("ATS"),
+    REMOTE_S_REGISTER_ACCESS("ATREMS"),
+    REMOTE_S_REGISTER_ACCESS_ALL("ATSALL"),
+    DISPLAY_ALL_S_REGISTERS("AT+TOKDUMP"),
+    SCAN_THE_ENERGY_OF_ALL_CHANNELS("AT+ESCAN"),
+    SCAN_FOR_ACTIVE_PANS("AT+PANSCAN"),
+    ESTABLISH_PERSONAL_AREA_NETWORK("AT+EN"),
+    JOIN_NETWORK("AT+JN"),
+    JOIN_SPECIFIC_PAN("AT+JPAN"),
+    SILENT_JOIN("AT+SJN"),
+    DISASSOCIATE_LOCAL_DEVICE_FROM_PAN("AT+DASSL"),
+    DISASSOCIATE_REMOTE_NODE_FROM_PAN("AT+DASSR"),
+    DISPLAY_NETWORK_INFORMATION("AT+N?"),
+    DISPLAY_NEIGHBOUR_TABLE("AT+NTABLE"),
+    DISPLAY_ROUTING_TABLE("AT+RTABLE"),
+    REQUEST_NODEID("AT+IDREQ"),
+    REQUEST_EUI("AT+EUIREQ"),
+    REQUEST_NODE_DESCRIPTOR("AT+NODEDESC"),
+    REQUEST_NODE_POWER_DESCRIPTOR("AT+POWERDESC"),
+    REQUEST_NODE_ACTIVE_ENDPOINT_LIST("AT+ACTEPDESC"),
+    REQUEST_ENDPOINT_SIMPLE_DESCRIPTOR("AT+SIMPLEDESC"),
+    FIND_NODES_WHICH_MATCH_A_SPECIFIC_DESCRIPTOR("AT+MATCHREQ"),
+    ANNOUNCE_LOCAL_DEVICE_IN_THE_NETWORK("AT+ANNCE"),
+    SET_SOURCE_ROUTE_TO_REMOTE_DEVICE("AT+SR"),
+    FIND_THE_SOURCE_ROUTE_TO_A_REMOTE_DEVICE("AT+FNDSR"),
+    POLL_FOR_DATA_FROM_PARENT("AT+POLL"),
+    REJOIN_THE_NETWORK("AT+REJOIN"),
+    SCAN_NETWORK("AT+SN"),
+    UPDATE_THE_NETWORK_KEY("AT+KEYUPD"),
+    MAKE_LOCAL_DEVICE_THE_TRUST_CENTRE("AT+BECOMETC"),
+    MAKE_THE_LOCAL_DEVICE_NETWORK_MANAGER("AT+BECOMENM"),
+    CHANGE_THE_NETWORK_CHANNEL("AT+CCHANGE"),
+    DISPLAY_ADDRESS_TABLE("AT+ATABLE"),
+    SET_ADDRESS_TABLE_ENTRY("AT+ASET"),
+    DISPLAY_MULTICAST_TABLE("AT+MTABLE"),
+    SET_MULTICAST_TABLE_ENTRY("AT+MSET"),
+    TRANSMIT_A_BROADCAST("AT+BCAST"),
+    TRANSMIT_A_BROADCAST_OF_BINARY_DATA("AT+BCASTB"),
+    TRANSMIT_A_UNICAST("AT+UCAST"),
+    TRANSMIT_A_UNICAST_OF_BINARY_DATA("AT+UCASTB"),
+    TRANSMIT_DATA_TO_THE_SINK("AT+SCAST"),
+    TRANSMIT_BINARY_DATA_TO_THE_SINK("AT+SCASTB"),
+    SEARCH_FOR_A_SINK("AT+SSINK"),
+    TRANSMIT_A_MULTICAST("AT+MCAST"),
+    TRANSMIT_A_MULTICAST_OF_BINARY_DATA("AT+MCASTB"),
+    ENTER_DATA_MODE("AT+DMODE"),
+    LEAVE_DATA_MODE("+++"),
+    PLAY_A_TUNE_ON_REMOTE_DEVBOARD("AT+IDENT"),
+    SEND_BINARY_RAW_DATA("AT+RDATAB");
+    private final String command;
+
+    Command305(String command) {
+        this.command = command;
+    }
+
+    public String getText() {
+        return command;
+    }
+
+    public byte[] getBytes() {
+        return command.getBytes(Charset.forName("ISO-8859-1"));
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/ErrorCode305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/ErrorCode305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/ErrorCode305.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,94 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol;
+
+/**
+ *
+ * @author alvaro
+ */
+public enum ErrorCode305 {
+    TELEGESIS_ERROR_00("Everything OK - Success"),
+    TELEGESIS_ERROR_01("Couldn’t poll Parent because of Timeout"),
+    TELEGESIS_ERROR_02("Unknown command"),
+    TELEGESIS_ERROR_04("Invalid S-Register"),
+    TELEGESIS_ERROR_05("Invalid parameter"),
+    TELEGESIS_ERROR_06("Recipient could not be reached"),
+    TELEGESIS_ERROR_07("Message was not acknowledged"),
+    TELEGESIS_ERROR_08("No sink known"),
+    TELEGESIS_ERROR_09("Address Table entry is in use and cannot be modified"),
+    TELEGESIS_ERROR_0A("Message could not be sent"),
+    TELEGESIS_ERROR_0B("Local node is not sink"),
+    TELEGESIS_ERROR_0C("Too many characters"),
+    TELEGESIS_ERROR_0E("Background Scan in Progress (Please wait and try again)"),
+    TELEGESIS_ERROR_0F("Fatal error initialising the network"),
+    TELEGESIS_ERROR_10("Error bootloading"),
+    TELEGESIS_ERROR_12("Fatal error initialising the stack"),
+    TELEGESIS_ERROR_18("Node has run out of Buffers"),
+    TELEGESIS_ERROR_19("Trying to write read-only register"),
+    TELEGESIS_ERROR_1A("Data Mode Refused by Remote Node"),
+    TELEGESIS_ERROR_1B("Connection Lost in Data Mode"),
+    TELEGESIS_ERROR_1C("Remote node is already in Data Mode"),
+    TELEGESIS_ERROR_20("Invalid password"),
+    TELEGESIS_ERROR_25("Cannot form network"),
+    TELEGESIS_ERROR_27("No network found"),
+    TELEGESIS_ERROR_28("Operation cannot be completed if node is part of a PAN"),
+    TELEGESIS_ERROR_2C("Error leaving the PAN"),
+    TELEGESIS_ERROR_2D("Error scanning for PANs"),
+    TELEGESIS_ERROR_33("No response from the remote bootloader"),
+    TELEGESIS_ERROR_34("Target did not respond during cloning"),
+    TELEGESIS_ERROR_35("Timeout occurred during xCASTB"),
+    TELEGESIS_ERROR_39("MAC Transmit Queue is Full"),
+    TELEGESIS_ERROR_70("Invalid Operation"),
+    TELEGESIS_ERROR_72("More than 10 unicast messages were in flight at the same time"),
+    TELEGESIS_ERROR_74("Message too long"),
+    TELEGESIS_ERROR_80("ZDP Invalid Request Type"),
+    TELEGESIS_ERROR_81("ZDP Device not Found"),
+    TELEGESIS_ERROR_82("ZDP Invalid Endpoint"),
+    TELEGESIS_ERROR_83("ZDP Not Active"),
+    TELEGESIS_ERROR_84("ZDP Not Supported"),
+    TELEGESIS_ERROR_85("ZDP Timeout"),
+    TELEGESIS_ERROR_86("ZDP No Match"),
+    TELEGESIS_ERROR_87("ZDP Table Full"),
+    TELEGESIS_ERROR_88("ZDP No Entry"),
+    TELEGESIS_ERROR_89("ZDP No Descriptor"),
+    TELEGESIS_ERROR_91("Operation only possible if connected to a PAN"),
+    TELEGESIS_ERROR_93("Node is not part of a Network"),
+    TELEGESIS_ERROR_94("Cannot join network"),
+    TELEGESIS_ERROR_96("Mobile End Device Move to new Parent Failed"),
+    TELEGESIS_ERROR_98("Cannot join ZigBee 2006 Network as Router"),
+    TELEGESIS_ERROR_A1("More than 8 broadcasts were sent within 8 seconds"),
+    TELEGESIS_ERROR_AB("Trying to join, but no beacons could be heard"),
+    TELEGESIS_ERROR_AC("Network key was sent in the clear when trying to join secured"),
+    TELEGESIS_ERROR_AD("Did not receive Network Key"),
+    TELEGESIS_ERROR_AE("No Link Key received"),
+    TELEGESIS_ERROR_AF("Preconfigured Key Required"),
+    TELEGESIS_ERROR_C5("NWK Already Present"),
+    TELEGESIS_ERROR_C7("NWK Table Full"),
+    TELEGESIS_ERROR_C8("NWK Unknown Device"),
+    COMMUNICATION_ERROR("Communication error"),
+    NULL_RESPONSE("No expected response after timeout"),
+    BAD_RESPONSE("Unexpected response");
+    private final String message;
+
+    ErrorCode305(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Prompt305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Prompt305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/Prompt305.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,148 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol;
+
+import java.nio.charset.Charset;
+
+/**
+ *
+ * @author alvaro
+ */
+public enum Prompt305 {
+
+    //OK("OK", 2, false, false), //OK
+    //ERROR("ERROR", 8, true, false), //ERROR:XX
+    //SEQ("SEQ", 6, true, false), //SEQ:XX
+    ACK("ACK", 6, true, false), //ACK:XX
+    NACK("NACK", 7, true, false), //NACK:XX
+    ROUTE_RECORD("SR", 27, true, false), //SR:XX,<EUI64>,<nodeId>
+    BROADCAST_RECEIVED("BCAST", 0, true, true), // BCAST:[<EUI64>,]XX=<data>
+    MULTICAST_RECEIVED("MCAST", 0, true, true), // MCAST:[<EUI64>,]XX=<data>
+    UNICAST_RECEIVED("UCAST", 0, true, true), // UCAST:[<EUI64>,]XX=<data>
+    SINK_DATA_MESSAGE("SDATA", 32, true, false), //{NO BIEN DOCUMENTADO} SDATA:[<EUI64>],<ioread>,<A/D1>,<A/D2>, <sequenceNo>,<Vcc> 
+    SINK_DATA_MESSAGE_FN0130("FN0130", 32, true, false), //{NO BIEN DOCUMENTADO}FN0130:[<EUI64>,]<NodeID>,<ioread>,<sequence no>,<S46>[,<A/D1>][,<A/D2>][,<A/D3>][,<A/D4>]
+    COO_ANNOUNCE("COO", 25, true, false), //COO:<EUI64>,<nodeId>
+    FFD_ANNOUNCE("FFD", 25, true, false), //FFD:<EUI64>,<nodeId>
+    SED_ANNOUNCE("SED", 25, true, false), //SED:<EUI64>,<nodeId>
+    MED_ANNOUNCE("MED", 25, true, false), //MED:<EUI64>,<nodeId>
+    ZED_ANNOUNCE("ZED", 25, true, false), //ZED:<EUI64>,<nodeId>
+    NEWNODE_ANNOUNCE("NEWNODE", 34, true, false), //NEWNODE:<EUI64>,<nodeId>,<parent nodeId>
+    LEFT_PAN("LeftPAN", 7, false, false), //LeftPAN
+    LOST_PAN("LostPAN", 7, false, false), //LostPAN
+    JOIN_PAN("JPAN", 29, true, false), //JPAN:<channel>,<PID>,<EPID>
+    SINK_SELECTED("SINK", 26, true, false), //SINK:<EUI64>,<NodeID>
+    SINK_ANNOUCE("ADSK", 26, true, false), //ADSK:<EUI64>,<NodeID>
+    REGISTER_READ("SREAD", 33, true, false), //SREAD:<NodeID>,<EUI64>,<Register>,<errorcode>[=<Data>]
+    REGISTER_WRITE("SWRITE", 31, true, false), //SWRITE:<NodeID>,<EUI64>,<errorcode>
+    DATA_MODE("DataMODE", 30, true, false), //DataMODE:<NodeID>,<EUI64>
+    DATA_MODE_RESPONSE("DataMODE", 33, true, false), //DataMODE:<NodeID>,<EUI64>,<errorcode>
+    DATA_MODE_OPEN("OPEN", 4, false, false), //OPEN
+    DATA_MODE_CLOSED("CLOSED", 6, false, false), //CLOSED
+    TRACKING_MESSAGE("TRACK", 87, true, false), //{NO BIEN DOCUMENTADO} TRACK:<EUI64 R>,<EUI64 S>,<RSSI>, <i/o read>,<AD1>,<AD2>,<Vcc>,<S46>
+    TRACKING_MESSAGE_2("TRACK2", 61, true, false), //{NO BIEN DOCUMENTADO} TRACK2:<EUI64 R>,<EUI64 S>,<RSSI>,<I/O read>,<S46>
+    POWER_CHANGE("PWRCHANGE", 14, true, false), //PWRCHANGE:XXXX
+    END_POINT_MESSAGE("RX", 41, true, true), //RX:<EUI64>,<NodeID>,<profileID>, <destinationEndpoint>,<SourceEndpoint>,<clusterID>,<length>:<payload>
+    REPORT_WARNING("NM", 20, true, false), //NM:ES REPORT WARNING
+    ENTERING_BOOTLOAD("ENTERING BLOAD", 14, false, false), //ENTERING BLOAD
+    NEIGHBOUR_TABLE_RESPONSE("NTable", 14, true, false), //NTable:<NodeID>,<errorcode>...
+    //ROUTE_TABLE_RESPONSE("RTable", 14, true, false), //RTable:<NodeID>,<errorcode>...
+    ADDR_RESPONSE("AddrResp", 11, true, false), //AddrResp:<errorcode>[,<NodeID>,<EUI64>]
+    NODE_DESC_RESPONSE("NodeDesc", 16, true, false), //NodeDesc:<NodeID>[,<errorcode> | ...]
+    POWER_DESC_RESPONSE("PowerDesc", 17, true, false), //PowerDesc:<NodeID>,<errorcode>[,PowerDescriptor]
+    ACTIVE_EP_RESPONSE("ActEpDesc", 17, true, false), //ActEpDesc:<NodeID>,<errorcode>[,XX,...]
+    EP_SIMPLE_DESC_RESPONSE("SimpleDesc", 18, true, false), //SimpleDesc:<NodeID>,<errorcode> ...
+    NODES_MATCH_DESC_RESPONSE("MatchDesc", 17, true, false); //MatchDesc:<NodeID>,<errorcode>,XX,...
+    //
+    private final String prompt;
+    private final int minSize;
+    private final boolean hasParameters;
+    private final boolean hasData;
+
+    /**
+     * 
+     * @param prompt Cadena de texto correspondiente
+     * @param minSize Tamaño mínimo del mensaje, o posición que ocupa el campo de datos si es distinto de cero
+     * @param hasData indica si tiene un campo de datos
+     */
+    Prompt305(String prompt, int minSize, boolean hasParameters, boolean hasData) {
+        this.prompt = prompt;
+        this.minSize = minSize;
+        this.hasParameters = hasParameters;
+        this.hasData = hasData;
+    }
+
+    /**
+     * Comprueba si el mensaje proporcionado corresponde al promt
+     * @param message Mensaje a comprobar
+     * @param startPos Posicion de inicio de búsqueda
+     * @return 
+     */
+    public boolean chekMessage(byte[] message, int startPos) {
+        // componemos cadena de comparacion
+        String testPrompt = prompt;
+        if (hasParameters) {
+            testPrompt += SpecialSequence305.COMMAND_SEPARATOR.getText();
+        }
+        byte[] sequence = testPrompt.getBytes(Charset.forName("ISO-8859-1"));
+        
+        // comprobamos tamaño
+        if (message.length < sequence.length + startPos) {
+            return false;
+        }
+        // comprobamos secuencia
+        for (int i = 0; i < sequence.length; i++) {
+            // si no coincide la secuencia en un carácter, devolvemos FALSE
+            if (message[startPos + i] != sequence[i]) {
+                return false;
+            }
+        }
+        // si hemos llegado aquí, coincide la secuencia, devolvemos TRUE
+        return true;
+
+
+    }
+
+    public String getText() {
+        return prompt;
+    }
+
+    /**
+     * representación en bytes de la cadena de texto del mensaje
+     * @return 
+     */
+    public byte[] getBytes() {
+        return prompt.getBytes(Charset.forName("ISO-8859-1"));
+    }
+
+    /**
+     * Tamaño del mensaje (o tamaño mínimo), para mensajes de longitud fija. 
+     * Para mensajes que tienen un campo de datos, si el valor es distinto de 
+     * cero indica la posición del parámetro que indica la longitud de los datos
+     * @return Tamaño o posición de los datos
+     */
+    public int getMinSize() {
+        return minSize;
+    }
+
+    /**
+     * Indica si tiene un campo de datos de longitud variable
+     * @return TRUE si tiene campo de datos
+     */
+    public boolean getHasData() {
+        return hasData;
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/SpecialSequence305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/SpecialSequence305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/protocol/SpecialSequence305.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,50 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol;
+
+import java.nio.charset.Charset;
+
+/**
+ *
+ * @author alvaro
+ */
+public enum SpecialSequence305 {
+
+    COMMAND_OK("OK"),
+    COMMAND_ERROR("ERROR"),
+    SEQUENCE_NUMBER("SEQ"),
+    COMMAND_SEPARATOR(":"),
+    PASSWORD_SEPARATOR(":"),
+    PARAMETER_SEPARATOR(","),
+    REGISTER_QUERY("?"),
+    DATA_SEPARATOR("="),
+    CMD_END("\r"),
+    FRAME_SEPARATOR("\r\n");
+    private final String sequence;
+
+    SpecialSequence305(String sequence) {
+        this.sequence = sequence;
+    }
+
+    public String getText() {
+        return sequence;
+    }
+    
+    public byte[] getBytes(){
+        return sequence.getBytes(Charset.forName("ISO-8859-1"));
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/LICENSE
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/LICENSE (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/main/resources/LICENSE Thu Feb  2 13:18:52 2012
@@ -1,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/CnxListenerTest.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/CnxListenerTest.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/CnxListenerTest.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,162 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import java.nio.charset.Charset;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.SerialListener;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.SpecialSequence305;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author alvaro
+ */
+public class CnxListenerTest {
+
+    public CnxListenerTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of hasNewFrames method, of class SerialListener.
+     */
+    //@Test
+    public void testprocessIncommingMessage() {
+        System.out.println("testprocessIncommingMessage");
+        SerialListener instance = new SerialListener(new SerialListener.MessageParser() {
+            @Override
+            public void hasNewPromps() {
+                //throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public void serialPortError() {
+                //throw new UnsupportedOperationException("Not supported yet.");
+            }
+        });
+        String EUI64 = "1122334455667788";
+        String nodeID = "1122";
+        String PID = "1122";
+        String EPID = "1122334455667788";
+        //String msgData = "123\r\n678";
+        String msgData = "12345678";
+        String[] testMessages = new String[]{
+            "TRACK2:" + EUI64 + "," + EUI64 + ",00,12341234,12341234",
+            "RX:" + EUI64 + "," + nodeID + ",0011,01,01,0123,08:0011223344556677",
+            //"OK", //(se ha eliminado de la lista de prompts)
+            //"ERROR:01", //(se ha eliminado de la lista de prompts)
+            //"TELEGESIS ETRX2\r\nR305X\r\n000D6F0000945F79\r\n\r\nOK",
+            //"ERROR:01\r\n\r\nERROR:03", //(se ha eliminado de la lista de prompts)
+            "ACK:01",
+            "NACK:01",
+            //"SEQ:01",
+            "SR:01," + EUI64 + "," + nodeID,
+            "BCAST:05=12345",
+            "UCAST:" + EUI64 + ",05=123\r\n",
+            "UCAST:" + EUI64 + ",05=\r\n123",
+            "BCAST:" + EUI64 + ",05=12345",
+            "MCAST:" + EUI64 + ",05=12345",
+            "UCAST:" + EUI64 + ",05=12345",
+            //
+            //"ERROR:XX", //(se ha eliminado de la lista de prompts)
+            "ACK:XX",
+            "NACK:XX",
+            "SR:XX," + EUI64 + "," + nodeID,
+            "BCAST:08=" + msgData,
+            "BCAST:" + EUI64 + ",08=" + msgData,
+            "MCAST:08=" + msgData,
+            "MCAST:" + EUI64 + ",08=" + msgData,
+            "UCAST:08=" + msgData,
+            "UCAST:" + EUI64 + ",08=" + msgData,
+            "SDATA:12341234,12341234,12341234,01,12341234",
+            "SDATA:" + EUI64 + ",12341234,12341234,12341234,01,12341234",
+            "FN0130:" + nodeID + ",12341234,01,12341234",
+            "FN0130:" + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "FN0130:" + EUI64 + "," + nodeID + ",12341234,01,12341234",
+            "FN0130:" + EUI64 + "," + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "COO:" + EUI64 + "," + nodeID,
+            "FFD:" + EUI64 + "," + nodeID,
+            "SED:" + EUI64 + "," + nodeID,
+            "MED:" + EUI64 + "," + nodeID,
+            "ZED:" + EUI64 + "," + nodeID,
+            "NEWNODE:" + EUI64 + "," + nodeID + "," + nodeID,
+            "LeftPAN",
+            "LostPAN",
+            "JPAN:11," + PID + "," + EPID,
+            "SINK:" + EUI64 + "," + nodeID,
+            "ADSK:" + EUI64 + "," + nodeID,
+            "SREAD:" + nodeID + "," + EUI64 + ",00,02",
+            "SREAD:" + nodeID + "," + EUI64 + ",00,00=0800",
+            "SWRITE:" + nodeID + "," + EUI64 + ",00",
+            "DataMODE:" + nodeID + "," + EUI64,
+            "DataMODE:" + nodeID + "," + EUI64 + ",00",
+            "OPEN",
+            "CLOSED",
+            "TRACK:" + EUI64 + "," + EUI64 + ",00,12341234,12341234,12341234,12341234,12341234",
+            "TRACK2:" + EUI64 + "," + EUI64 + ",00,12341234,12341234",
+            "PWRCHANGE:XXXX",
+            "AddrResp:02",
+            "AddrResp:00," + nodeID + "," + EUI64,
+            "NTable:" + nodeID + ",00\r\nLength:02\r\nNo. | Dev |       EUI        |  ID  | LQI\r\n00. | FFD | 000D6F000086F533 | 8FC6 | FF\r\n01. | FFD | 000D6F0000354A07 | CF8E | FF",
+            //"ACK:31\r\n\r\nSR:00,000D6F000086F533,8FC6\r\n\r\nRTable:8FC6,00\r\nLength:40\r\nNo. | Dest | Next | Status00. | 0000 | 0000 | 38\r\n01. | 0000 | 0000 | 03\r\n02. | 0000 | 0000 | 03\r\n03. | 0000 | 0000 | 03\r\n04. | 0000 | 0000 | 03\r\n05. | 0000 | 0000 | 03\r\n06. | 0000 | 0000 | 03\r\n07. | 0000 | 0000 | 03\r\n08. | 0000 | 0000 | 03\r\n09. | 0000 | 0000 | 03\r\n10. | 0000 | 0000 | 03\r\n11. | 0000 | 0000 | 03\r\n12. | 0000 | 0000 | 03\r\n13. | 0000 | 0000 | 03\r\n14. | 0000 | 0000 | 03",
+            "ACK:35\r\n\r\nNodeDesc:0000,00\r\nType:COO\r\nComplexDesc:No\r\nUserDesc:No\r\nAPSFlags:00\r\nFreqBand:40\r\nMacCap:8F\r\nManufCode:1010\r\nMaxBufSize:52\r\nMaxInSize:0080\r\nSrvMask:0000\r\nMaxOutSize:0080\r\nDescCap:00",
+            "ACK:38\r\n\r\nPowerDesc:0000,00,C110",
+            "ACK:3B\r\n\r\nActEpDesc:0000,00,01",
+            "ACK:41\r\n\r\nSimpleDesc:0000,00\r\nEP:01\r\nProfileID:C091\r\nDeviceID:0001v05\r\nInCluster:0002,0003,000B,000D\r\nOutCluster:0002,0004,0006,000B,000D",
+            "MatchDesc:0000,00,01\r\n\r\nSR:00,000D6F000086F533,8FC6\r\n\r\nMatchDesc:8FC6,00,01",
+            "RX:" + EUI64 + "," + nodeID + ",0011,01,01,0123,08:12345678",
+            "NM:ES REPORT WARNING",
+            "ENTERING BLOAD",};
+
+        for (int i = 0; i < testMessages.length; i++) {
+            String testMessage = SpecialSequence305.FRAME_SEPARATOR.getText() + testMessages[i] + SpecialSequence305.FRAME_SEPARATOR.getText();
+            instance.processIncommingMessage(testMessage.getBytes(Charset.forName("ISO-8859-1")));
+            String frame = instance.getNextPrompt();
+            String wholeFrame = "";
+            while (frame != null) {
+                wholeFrame += SpecialSequence305.FRAME_SEPARATOR.getText() + frame + SpecialSequence305.FRAME_SEPARATOR.getText();
+                frame = instance.getNextPrompt();
+            }
+            if (!wholeFrame.equals(SpecialSequence305.FRAME_SEPARATOR.getText() + testMessages[i] + SpecialSequence305.FRAME_SEPARATOR.getText())) {
+                System.out.println("Enviado: " + SpecialSequence305.FRAME_SEPARATOR.getText() + testMessages[i] + SpecialSequence305.FRAME_SEPARATOR.getText());
+                System.out.println("Recibido: " + wholeFrame);
+                fail("No coincide lo enviado y lo recibido");
+            }
+            //assertEquals(testMessages[i],frame);
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeGatewayListener.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeGatewayListener.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeGatewayListener.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,777 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import java.nio.charset.Charset;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.GatewayListener;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.ZigbeeDeviceType;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.NeighbourTableEntry;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class FakeGatewayListener implements GatewayListener {
+
+    Gateway gtwy = null;
+    String lastCommand;
+    short seqNumber;
+    boolean wasACK;
+    String EUI64Addr;
+    String payload;
+    int numHops;
+    String[] route;
+    String message;
+    String messageType;
+    ZigbeeDeviceType devType;
+    String nodeID;
+    String parentID;
+    int RSSI;
+    short LQI;
+    int channel;
+    String PID;
+    String EPID;
+    String data;
+    short errorCode;
+    short register;
+    int neighbourTableLength;
+    NeighbourTableEntry[] neighbourTable;
+    Map nodeDescriptor;
+    String powerDescriptor;
+    short[] EPList;
+    short EP;
+    short destEP;
+    short sourceEP;
+    String profileID;
+    String clusterID;
+    String DeviceID;
+    String[] inClusterList;
+    String[] outClusterList;
+    String command;
+    String[] parameters;
+
+    private void sleep() {
+        try {
+            Thread.sleep(100);
+        } catch (InterruptedException ex) {
+            Logger.getLogger(FakeGatewayListener.class.getName()).log(Level.SEVERE, null, ex);
+        }
+
+    }
+
+    /**
+     * Notifies about acknowledgement of a node communication operation, 
+     * providing SEQ number and acknowledge result (ACK/NACK)
+     * @param seqNumber SEQ number
+     * @param wasOK True for ACK, false for NACK
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void acknowledgement(short seqNumber, boolean wasACK, Gateway gtwy) {
+        System.out.println("acknowledgement");
+        lastCommand = "acknowledgement";
+        this.seqNumber = seqNumber;
+        this.wasACK = wasACK;
+        this.gtwy = gtwy;
+    }
+
+    public void checkAcknowledgementError(short seqNumber, boolean wasACK, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("acknowledgement")) {
+            fail("acknowledgement");
+        } else if (seqNumber != this.seqNumber) {
+            fail("seqNumber: " + this.seqNumber);
+        } else if (wasACK != this.wasACK) {
+            fail("wasACK: " + this.wasACK);
+        } else if (wasACK != this.wasACK) {
+            fail("wasACK: " + this.wasACK);
+        }
+    }
+
+    /**
+     * Notifies about a route to a remote device found
+     * @param EUI64Addr Remote node address
+     * @param numHops Number of hops
+     * @param route Array containing network addresses of intermediate nodes up 
+     * to remote node, excluding local node
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void routeRecordReceived(String EUI64Addr, int numHops, String[] route, Gateway gtwy) {
+        System.out.println("routeRecordReceived");
+        lastCommand = "routeRecordReceived";
+        this.gtwy = gtwy;
+        this.EUI64Addr = EUI64Addr;
+        this.numHops = numHops;
+        this.route = route;
+    }
+
+    public void checkRouteRecordReceived(String EUI64Addr, int numHops, String[] route, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("routeRecordReceived")) {
+            fail("routeRecordReceived");
+        } else if (!EUI64Addr.equals(this.EUI64Addr)) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (numHops != this.numHops) {
+            fail("numHops: " + this.numHops);
+        } else if (!Arrays.equals(route, this.route)) {
+            fail("route: " + this.route);
+        }
+    }
+
+    /**
+     * Notifies about reception of a broadcast message
+     * @param EUI64Addr Sender address
+     * @param message Message received
+     */
+    @Override
+    public void broadcastMessageReceived(String EUI64Addr, byte[] message, Gateway gtwy) {
+        System.out.println("broadcastMessageReceived");
+        lastCommand = "broadcastMessageReceived";
+        this.gtwy = gtwy;
+        this.EUI64Addr = (EUI64Addr != null ? EUI64Addr : "");
+        this.message = new String(message,Charset.forName("ISO-8859-1"));
+    }
+
+    public void checkBroadcastMessageReceived(String EUI64Addr, byte[] message, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("broadcastMessageReceived")) {
+            fail("broadcastMessageReceived");
+        } else if (!this.EUI64Addr.equals((EUI64Addr != null ? EUI64Addr : ""))) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (!Arrays.equals(message, this.message.getBytes(Charset.forName("ISO-8859-1")))) {
+            fail("message: " + this.message);
+        }
+    }
+
+    /**
+     * Notifies about reception of a message, whether it was a broadcast message
+     * multicast or unicast
+     * @param EUI64Addr Sender address
+     * @param message Message received
+     * @param messageType Message messageType
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void messageReceived(String EUI64Addr, byte[] message, String type, Gateway gtwy) {
+        System.out.println("messageReceived");
+        lastCommand = "messageReceived";
+        this.gtwy = gtwy;
+        this.EUI64Addr = (EUI64Addr != null ? EUI64Addr : "");
+        this.message = new String(message,Charset.forName("ISO-8859-1"));
+        this.messageType = type;
+    }
+
+    public void checkMessageReceived(String EUI64Addr, byte[] message, String type, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("messageReceived")) {
+            fail("messageReceived");
+        } else if (!this.EUI64Addr.equals((EUI64Addr != null ? EUI64Addr : ""))) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (!Arrays.equals(message, this.message.getBytes(Charset.forName("ISO-8859-1")))) {
+            fail("message: " + this.message);
+        } else if (!type.equals(this.messageType)) {
+            fail("type: " + this.messageType);
+        }
+    }
+
+    /**
+     * Notifies about reception of a message not handled by Telegesis dongle,
+     * providing whole APS frame
+     * @param EUI64Addr Sender address
+     * @param nodeID Sender network address
+     * @param sourceEP Sender EndPoint id
+     * @param destEP Receiver EndPoint id
+     * @param profileID profileID
+     * @param clusterID ClusterID 
+     * @param payload Message received
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void endpointMessageReceived(String EUI64Addr, String nodeID, short sourceEP, short destEP, String profileID, String clusterID, byte[] payload, Gateway gtwy){
+        System.out.println("endpointMessageReceived");
+        lastCommand = "endpointMessageReceived";
+        this.gtwy = gtwy;
+        this.EUI64Addr = (EUI64Addr != null ? EUI64Addr : "");
+        this.nodeID = nodeID;
+        this.sourceEP = sourceEP;
+        this.destEP = destEP;
+        this.profileID = profileID;
+        this.clusterID = clusterID;
+        this.payload = new String(payload,Charset.forName("ISO-8859-1"));
+        
+    }
+
+    public void checkendpointMessageReceived(String EUI64Addr, String nodeID, short sourceEP, short destEP, String profileID, String clusterID, byte[] payload, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("endpointMessageReceived")) {
+            fail("endpointMessageReceived");
+        } else if (!this.EUI64Addr.equals((EUI64Addr != null ? EUI64Addr : ""))) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (!this.nodeID.equals(nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (this.sourceEP !=sourceEP) {
+            fail("sourceEP: " + this.sourceEP + " received: "+ sourceEP);
+        } else if (this.destEP !=destEP) {
+            fail("destEP: " + this.destEP);
+        } else if (!this.profileID.equals(profileID)) {
+            fail("profileID: " + this.profileID);
+        } else if (!this.clusterID.equals(clusterID)) {
+            fail("clusterID: " + this.clusterID);
+        } else if (!this.payload.equals(new String(payload,Charset.forName("ISO-8859-1")))) {
+            fail("payload: " + this.payload + " received: " + new String(payload,Charset.forName("ISO-8859-1")));
+        }
+    }
+
+    /**
+     * Notifies about a node announce
+     * @param messageType DeviceType (COO, FFD...)
+     * @param EUI64Addr Node's address
+     * @param nodeID Node's network address
+     * @param RSSI RSSI level (dBm) of the last hop
+     * @param LQI LQI indicator of the last hop
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void nodeAnnounce(ZigbeeDeviceType type, String EUI64Addr, String nodeID, int RSSI, short LQI, Gateway gtwy) {
+        System.out.println("nodeAnnounce");
+        lastCommand = "nodeAnnounce";
+        this.gtwy = gtwy;
+        this.devType = type;
+        this.EUI64Addr = EUI64Addr;
+        this.nodeID = nodeID;
+        this.RSSI = RSSI;
+        this.LQI = LQI;
+    }
+
+    public void checkNodeAnnounce(ZigbeeDeviceType type, String EUI64Addr, String nodeID, int RSSI, short LQI, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("nodeAnnounce")) {
+            fail("nodeAnnounce");
+        } else if (!type.equals(this.devType)) {
+            fail("type: " + this.devType);
+        } else if (!EUI64Addr.equals(this.EUI64Addr)) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (RSSI != this.RSSI) {
+            fail("RSSI: " + this.RSSI);
+        } else if (LQI != this.LQI) {
+            fail("LQI: " + this.LQI);
+        }
+    }
+
+    /**
+     * Notifies about a new node
+     * @param EUI64Addr Node's address
+     * @param nodeID Node's network address
+     * @param parentID Parent's network address or null
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void newNode(String EUI64Addr, String nodeID, String parentID, Gateway gtwy) {
+        System.out.println("newNode");
+        lastCommand = "newNode";
+        this.gtwy = gtwy;
+        this.EUI64Addr = EUI64Addr;
+        this.nodeID = nodeID;
+        this.parentID = (parentID == null ? "" : parentID);
+    }
+
+    public void checkNewNode(String EUI64Addr, String nodeID, String parentID, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("newNode")) {
+            fail("newNode");
+        } else if (!EUI64Addr.equals(this.EUI64Addr)) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (!this.parentID.equals((parentID == null ? "" : parentID))) {
+            fail("parentID: " + this.parentID);
+        }
+    }
+
+    /**
+     * Notifies about local node left PAN
+     * Note: also notifies about end device losing parent
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void leftPAN(Gateway gtwy) {
+        System.out.println("leftPAN");
+        lastCommand = "leftPAN";
+        this.gtwy = gtwy;
+    }
+
+    public void checkLeftPAN(Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("leftPAN")) {
+            fail("leftPAN");
+        }
+    }
+
+    /**
+     * Notifies about local node joining PAN
+     * @param channel Network channel (ranging from 0x0B to 0x1A)
+     * @param PID Network PID
+     * @param EPID Network EPID
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void joinedPan(int channel, String PID, String EPID, Gateway gtwy) {
+        System.out.println("joinedPan");
+        lastCommand = "joinedPan";
+        this.gtwy = gtwy;
+        this.channel = channel;
+        this.PID = PID;
+        this.EPID = EPID;
+    }
+
+    public void checkJoinedPan(int channel, String PID, String EPID, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("joinedPan")) {
+            fail("joinedPan");
+        } else if (channel != this.channel) {
+            fail("channel: " + this.channel);
+        } else if (!PID.equals(this.PID)) {
+            fail("PID: " + this.PID);
+        } else if (!EPID.equals(this.EPID)) {
+            fail("EPID: " + this.EPID);
+        }
+    }
+
+    /**
+     * Notifies about operation result of writing on a register
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     * @param errorCode Operation result
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void registerWrited(String nodeID, String EUI64Addr, short errorCode, Gateway gtwy) {
+        System.out.println("registerWrited");
+        lastCommand = "registerWrited";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.EUI64Addr = EUI64Addr;
+        this.errorCode = errorCode;
+    }
+
+    public void checkRegisterWrited(String nodeID, String EUI64Addr, short errorCode, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("registerWrited")) {
+            fail("registerWrited");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (!EUI64Addr.equals(this.EUI64Addr)) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        }
+    }
+
+    /**
+     * Notifies about reading of a register
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     * @param register Register readed
+     * @param errorCode Operation result
+     * @param data Register contents
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void registerReaded(String nodeID, String EUI64Addr, short register, short errorCode, String data, Gateway gtwy) {
+        System.out.println("registerReaded");
+        lastCommand = "registerReaded";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.EUI64Addr = EUI64Addr;
+        this.register = register;
+        this.errorCode = errorCode;
+        this.data = (data == null ? "" : data);
+    }
+
+    public void checkRegisterReaded(String nodeID, String EUI64Addr, short register, short errorCode, String data, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("registerReaded")) {
+            fail("registerReaded");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (!EUI64Addr.equals(this.EUI64Addr)) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        } else if (register != this.register) {
+            fail("register: " + this.register);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!this.data.equals((data == null ? "" : data))) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        }
+    }
+
+    /**
+     * Notifies response about an address request to a node
+     * @param errorCode request result
+     * @param nodeID Node's network address
+     * @param EUI64Addr Node's address
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void addrResponse(short errorCode, String nodeID, String EUI64Addr, Gateway gtwy) {
+        System.out.println("addrResponse");
+        lastCommand = "addrResponse";
+        this.gtwy = gtwy;
+        this.errorCode = errorCode;
+        this.nodeID = (nodeID == null ? "" : nodeID);
+        this.EUI64Addr = (EUI64Addr == null ? "" : EUI64Addr);
+    }
+
+    public void checkAddrResponse(short errorCode, String nodeID, String EUI64Addr, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("addrResponse")) {
+            fail("addrResponse");
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!this.nodeID.equals((nodeID == null ? "" : nodeID))) {
+            fail("nodeID: " + this.nodeID);
+        } else if (!this.EUI64Addr.equals((EUI64Addr == null ? "" : EUI64Addr))) {
+            fail("EUI64Addr: " + this.EUI64Addr);
+        }
+    }
+
+    /**
+     * Notifies about a Neighbour table request response.
+     * Note: tableLength != table.length() means there are records pending to 
+     * receive (if requested)
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param tableLength Total neighbour table
+     * @param table received records
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void neighbourTableResponse(String nodeID, short errorCode, int tableLength, NeighbourTableEntry[] table, Gateway gtwy) {
+        System.out.println("neighbourTableResponse");
+        lastCommand = "neighbourTableResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.neighbourTableLength = tableLength;
+        this.neighbourTable = table;
+    }
+
+    public void checkNeighbourTableResponse(String nodeID, short errorCode, int tableLength, NeighbourTableEntry[] table, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("neighbourTableResponse")) {
+            fail("neighbourTableResponse");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!Arrays.equals(table, this.neighbourTable)) {
+            fail("neighbourTable: " + this.neighbourTable);
+        } else if (tableLength != this.neighbourTableLength) {
+            fail("neighbourTableLength: " + this.neighbourTableLength);
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param descriptor Map containig pairs <key,value> of related descriptor
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void nodeDescriptorResponse(String nodeID, short errorCode, Map descriptor, Gateway gtwy) {
+        System.out.println("nodeDescriptorResponse");
+        lastCommand = "nodeDescriptorResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.nodeDescriptor = descriptor;
+    }
+
+    public void checkNodeDescriptorResponse(String nodeID, short errorCode, Map descriptor, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("nodeDescriptorResponse")) {
+            fail("nodeDescriptorResponse: " + lastCommand);
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!descriptor.equals(this.nodeDescriptor)) {
+            fail("nodeDescriptor: " + this.nodeDescriptor);
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param descriptor power descriptor
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void powerDescriptorResponse(String nodeID, short errorCode, String descriptor, Gateway gtwy) {
+        System.out.println("powerDescriptorResponse");
+        lastCommand = "powerDescriptorResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.powerDescriptor = (descriptor == null ? "" : descriptor);
+    }
+
+    public void checkPowerDescriptorResponse(String nodeID, short errorCode, String descriptor, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("powerDescriptorResponse")) {
+            fail("powerDescriptorResponse: " + lastCommand);
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!this.powerDescriptor.equals((descriptor == null ? "" : descriptor))) {
+            fail("powerDescriptor: " + this.powerDescriptor);
+        }
+    }
+
+    /**
+     * Notifies about a node descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EPList EndPoint list
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void nodeActiveEPResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        System.out.println("nodeActiveEPResponse");
+        lastCommand = "nodeActiveEPResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.EPList = EPList;
+    }
+
+    public void checkNodeActiveEPResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("nodeActiveEPResponse")) {
+            fail("nodeActiveEPResponse");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (EPList == null) {
+            if (this.EPList != null) {
+                fail("EPList: " + this.EPList);
+            } else if (!Arrays.equals(EPList, this.EPList)) {
+                fail("EPList: " + this.EPList);
+            }
+        }
+    }
+
+    /**
+     * Notifies about a node EndPoint simple descriptor request response
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EP EndPoint requested
+     * @param profileID
+     * @param DeviceID
+     * @param inClusterList String array containing supported in cluster 
+     * @param outClusterList String array containing supported out cluster 
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void nodeEndPointSimpleDescriptorResponse(String nodeID,
+            short errorCode,
+            short EP, String ProfileID, String DeviceID, String[] inClusterList, String[] outClusterList, Gateway gtwy) {
+        System.out.println("nodeEndPointSimpleDescriptorResponse");
+        lastCommand = "nodeEndPointSimpleDescriptorResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.EP = EP;
+        this.profileID = ProfileID;
+        this.DeviceID = DeviceID;
+        this.inClusterList = inClusterList;
+        this.outClusterList = outClusterList;
+
+    }
+
+    public void checkNodeEndPointSimpleDescriptorResponse(String nodeID, short errorCode, short EP, String ProfileID, String DeviceID, String[] inClusterList, String[] outClusterList, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("nodeEndPointSimpleDescriptorResponse")) {
+            fail("nodeEndPointSimpleDescriptorResponse");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (!ProfileID.equals(this.profileID)) {
+            fail("ProfileID: " + this.profileID);
+        } else if (!DeviceID.equals(this.DeviceID)) {
+            fail("DeviceID: " + this.DeviceID);
+        } else if (!Arrays.equals(inClusterList, this.inClusterList)) {
+            fail("inClusterList: " + this.inClusterList);
+        } else if (!Arrays.equals(outClusterList, this.outClusterList)) {
+            fail("outClusterList: " + this.outClusterList);
+        }
+    }
+
+    /**
+     * Notifies about a node matching a previous descriptor request response
+     * NOTE: profile
+     * @param nodeID Node's network address
+     * @param errorCode request result
+     * @param EPList EndPoint list
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void nodeMatchingDescriptorResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        System.out.println("nodeMatchingDescriptorResponse");
+        lastCommand = "nodeMatchingDescriptorResponse";
+        this.gtwy = gtwy;
+        this.nodeID = nodeID;
+        this.errorCode = errorCode;
+        this.EPList = EPList;
+
+    }
+
+    public void checkNodeMatchingDescriptorResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("nodeMatchingDescriptorResponse")) {
+            fail("nodeMatchingDescriptorResponse");
+        } else if (!nodeID.equals(this.nodeID)) {
+            fail("nodeID: " + this.nodeID);
+        } else if (errorCode != this.errorCode) {
+            fail("errorCode: " + this.errorCode);
+        } else if (EPList == null) {
+            if (this.EPList != null) {
+                fail("EPList: " + this.EPList);
+            } else if (!Arrays.equals(EPList, this.EPList)) {
+                fail("EPList: " + this.EPList);
+            }
+        }
+    }
+
+    /**
+     * Notifies about and unhandled telegesis command:
+     * - SDATA
+     * - FN0130
+     * - SINK
+     * - ADSK
+     * - DataMODE
+     * - OPEN
+     * - CLOSED
+     * - TRACK
+     * - TRACK2
+     * - PWRCHANGE
+     * - RX
+     * - NM
+     * - ENTERING BLOAD
+     * @param command not handled command
+     * @param parameters command parameters list
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void unhandledCommand(String command, String[] parameters, Gateway gtwy) {
+        System.out.println("unhandledCommand");
+        lastCommand = "unhandledCommand";
+        this.gtwy = gtwy;
+        this.command = command;
+        this.parameters = parameters;
+
+    }
+
+    public void checkUnhandledCommand(String command, String[] parameters, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("unhandledCommand")) {
+            fail("unhandledCommand");
+        } else if (!command.equals(this.command)) {
+            fail("command: " + this.command);
+        } else if (!Arrays.equals(parameters, this.parameters)) {
+            fail("parameters: " + this.parameters);
+        }
+    }
+
+    /**
+     * Notifies about unknonwn incomming messages
+     * @param message 
+     * @param gtwy Gateway launching notification
+     */
+    @Override
+    public void unknownMessage(String message, Gateway gtwy) {
+        System.out.println("unknownMessage");
+        lastCommand = "unknownMessage";
+        this.gtwy = gtwy;
+        this.message = message;
+
+    }
+
+    public void checkUnknownMessage(String message, Gateway gtwy) {
+        sleep(); // para dar tiempo a que se procesen los eventos
+        if (!gtwy.equals(this.gtwy)) {
+            fail("gateway");
+        } else if (!lastCommand.equals("unknownMessage")) {
+            fail("unknownMessage (received: " + lastCommand + ")");
+        } else if (!message.equals(this.message)) {
+            fail("message: " + this.message);
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeSerialPort.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeSerialPort.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/FakeSerialPort.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,155 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import es.unizar.howlab.core.io.serial.*;
+import java.nio.charset.Charset;
+import java.util.concurrent.LinkedBlockingDeque;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class FakeSerialPort implements SerialConnection {
+
+    private boolean isPortOpen = false;
+    private boolean isBlocked = false;
+    SerialConnectionConfig config = null;
+    SerialConnectionListener serialListener = null;
+    LinkedBlockingDeque<byte[]> messages = new LinkedBlockingDeque<byte[]>();
+
+    @Override
+    public boolean open() {
+        isPortOpen = true;
+        return true;
+    }
+
+    @Override
+    public boolean close() {
+        isPortOpen = false;
+        return true;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return isPortOpen;
+    }
+
+    @Override
+    public int writeMessage(byte[] bytes) {
+        System.out.println(">>>>" + new String(bytes));
+        String testATI = new String(bytes,Charset.forName("ISO-8859-1"));
+        if (testATI.equals("ATI\r")) {
+            String ATI_RESPONSE = "\r\nTELEGESIS ETRX2\r\nR305X\r\n000D6F0000945F79\r\n\r\nOK\r\n";
+            injectMessage(ATI_RESPONSE.getBytes(Charset.forName("ISO-8859-1")));
+        } else if (testATI.equals("ATS0E=8000\r")) {
+            injectMessage("\r\nOK\r\n".getBytes(Charset.forName("ISO-8859-1")));
+        } else if (testATI.equals("ATS0F=0106\r")) {
+            injectMessage("\r\nOK\r\n".getBytes(Charset.forName("ISO-8859-1")));
+        } else if (testATI.equals("ATS1204=1\r")) {
+            injectMessage("\r\nOK\r\n".getBytes(Charset.forName("ISO-8859-1")));
+        } else {
+            messages.add(bytes);
+        }
+        return 0;
+    }
+
+    @Override
+    public int writeString(String string) {
+        return writeMessage(string.getBytes(Charset.forName("ISO-8859-1")));
+    }
+
+    @Override
+    public void blockWriting(int milliseconds) {
+        isBlocked = true;
+    }
+
+    @Override
+    public boolean unblockWriting() {
+        isBlocked = false;
+        return true;
+    }
+
+    @Override
+    public boolean tryBlockWriting(int milliseconds) {
+        isBlocked = true;
+        return true;
+    }
+
+    @Override
+    public boolean setConfiguration(SerialConnectionConfig scc) {
+        config = scc;
+        return true;
+    }
+
+    @Override
+    public SerialConnectionConfig getConfiguration() {
+        return config;
+    }
+
+    @Override
+    public boolean registerListener(SerialConnectionListener sl) {
+        this.serialListener = sl;
+        return true;
+    }
+
+    @Override
+    public boolean unregisterListener(SerialConnectionListener sl) {
+        this.serialListener = null;
+        return true;
+    }
+
+    public class SerialMessageImpl implements SerialMessage {
+
+        final byte[] message;
+
+        public SerialMessageImpl(byte[] msg) {
+            message = msg;
+        }
+
+        @Override
+        public Type getType() {
+            return Type.messageReceived;
+        }
+
+        @Override
+        public byte[] getBinaryMessage() {
+            return message;
+        }
+
+        @Override
+	public String getMessage(){
+		return new String(message,Charset.forName("ISO-8859-1"));
+        }
+    }
+
+    public void injectMessage(byte[] message) {
+        if (serialListener != null) {
+            System.out.println("<<<<" + new String(message));
+            SerialMessage sm = new SerialMessageImpl(message);
+            serialListener.eventMessage(sm, this);
+        }
+    }
+
+    public String getLastMessageWrited() {
+        return new String(messages.poll(),Charset.forName("ISO-8859-1"));
+    }
+
+    public void clearMessagesWrited() {
+        messages.clear();
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305Test.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305Test.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-gateway-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/gateway/impl/Gateway305Test.java Thu Feb  2 13:18:52 2012
@@ -1,0 +1,1600 @@
+/*
+ * Copyright 2011-2012 HOWLab. http://howlab.unizar.es/
+ * Human OpenWare Research Lab. Universidad Zaragoza
+ * 
+ * Licensed 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 es.unizar.howlab.core.zigbee.telegesis.gateway.impl;
+
+import java.nio.charset.Charset;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.TelegesisErrorException;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.ZigbeeDeviceType;
+import java.util.Map;
+//import es.unizar.howlab.core.zigbee.telegesis.gateway30x.*;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.*;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.Command305;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.impl.protocol.SpecialSequence305;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author alvaro
+ */
+public class Gateway305Test {
+
+    class MessageInjector implements Runnable {
+
+        final FakeSerialPort port;
+        ArrayList messages = new ArrayList();
+        ArrayList delays = new ArrayList();
+
+        public MessageInjector(FakeSerialPort sp) {
+            port = sp;
+        }
+
+        public void addMessage(String message, int delay) {
+            messages.add(message);
+            delays.add(new Long(delay));
+        }
+
+        @Override
+        public void run() {
+
+
+            Iterator itM = messages.iterator();
+            Iterator itD = delays.iterator();
+            while (itM.hasNext()) {
+                Long delay = (Long) itD.next();
+                try {
+                    Thread.sleep(delay);
+                } catch (InterruptedException ex) {
+                    Logger.getLogger(Gateway305Test.class.getName()).log(Level.SEVERE, null, ex);
+                }
+                String message = (String) itM.next();
+                port.injectMessage(message.getBytes(Charset.forName("ISO-8859-1")));
+            }
+        }
+    }
+    static final String ATI_RESPONSE = "\r\nTELEGESIS ETRX2\r\nR305X\r\n000D6F0000945F79\r\n\r\nOK\r\n";
+    static final String PID = "1030";
+    static final String EPID = "1122334455667788";
+    static final String EUI64Addr = "1122334455667788";
+    static final String msgData = "12345";
+    static final String nodeID = "1122";
+    static final int channel = 20;
+    static final String OK_FRAME = "\r\nOK\r\n";
+    static final String SEQ_FRAME_1A = "\r\nSEQ:1A\r\n";
+    static final String SEQ_FRAME_FA = "\r\nSEQ:FA\r\n";
+    Gateway305 testGateway;
+    FakeSerialPort sp;
+
+    public Gateway305Test() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() {
+        // puerto serie virtual
+        sp = new FakeSerialPort();
+        testGateway = new Gateway305(sp);
+        System.out.println("creando gateway...");
+//        MessageInjector mi = new MessageInjector(sp);
+//        mi.addMessage(ATI_RESPONSE, 5);
+//        Thread th = new Thread(mi);
+//        th.start();
+        testGateway.open();
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of open method, of class Gateway305.
+     */
+    @Test
+    public void testOpen() {
+        System.out.println("test open");
+        // comprobamos gateway abierto
+        if (!testGateway.isOpen()) {
+            fail("error al abrir el gateway");
+        }
+    }
+
+    /**
+     * Test of GetProductId method, of class Gateway305.
+     */
+    @Test
+    public void testGetProductId() {
+        System.out.println("test getProductId");
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(ATI_RESPONSE, 10);
+        Thread th = new Thread(mi);
+        th.start();
+        String[] response = testGateway.getProductId();
+        System.out.println("DeviceName: " + response[0]);
+        System.out.println("FirmwareVersion: " + response[1]);
+        System.out.println("EUI64Addr: " + response[2]);
+    }
+
+    /**
+     * Test of reset method, of class Gateway305.
+     */
+    @Test
+    public void testReset() {
+        System.out.println("reset");
+        sp.clearMessagesWrited();
+        testGateway.reset();
+        String msgWrited = sp.getLastMessageWrited();
+        String msgExpected = Command305.SOFTWARE_RESET.getText() + SpecialSequence305.CMD_END.getText();
+        if (!msgWrited.equals(msgExpected)) {
+            fail("Enviado: " + msgWrited + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of restoreFactoryDefaults method, of class Gateway305.
+     */
+    @Test
+    public void testRestoreFactoryDefaults() {
+        System.out.println("restoreFactoryDefaults");
+
+        sp.clearMessagesWrited();
+        testGateway.restoreFactoryDefaults();
+        String msgWrited = sp.getLastMessageWrited();
+        String msgExpected = Command305.RESTORE_FACTORY_DEFAULTS.getText() + SpecialSequence305.CMD_END.getText();
+        if (!msgWrited.equals(msgExpected)) {
+            fail("Enviado: " + msgWrited + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of readRegister method, of class Gateway305.
+     */
+    @Test
+    public void testReadRegister() throws Exception {
+        System.out.println("readRegister");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\n3FFC\r\n\r\nOK\r\n", 10);
+        mi.addMessage("\r\n<hidden>\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short reg = (short) 0xFC;
+        String response = testGateway.readRegister(reg);
+        if (!response.equals("3FFC")) {
+            fail("Enviado: 3FFC Esperado: " + response);
+        }
+        reg = 0x08;
+        response = testGateway.readRegister(reg);
+        if (!response.equals("<hidden>")) {
+            fail("Enviado: <hidden> Esperado: " + response);
+        }
+    }
+
+    /**
+     * Test of writeRegister method, of class Gateway305.
+     */
+    @Test
+    public void testWriteRegister_byte_String() throws Exception {
+        System.out.println("writeRegister");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nOK\r\n", 10);
+        mi.addMessage("\r\nERROR:20\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short reg = 0x0C;
+        try {
+            testGateway.writeRegister(reg, "password");
+        } catch (TelegesisErrorException ex) {
+            fail("excepcion: " + ex.getErrorMessage());
+        }
+        boolean exception = true;
+        try {
+            testGateway.writeRegister(reg, "password");
+        } catch (TelegesisErrorException ex) {
+            exception = false;
+            System.out.println("excepcion error: " + ex.getErrorMessage());
+        }
+        if (exception) {
+            fail("no ha saltado exception");
+        }
+    }
+
+    /**
+     * Test of writeRegister method, of class Gateway305.
+     */
+    @Test
+    public void testWriteRegister_3args() throws Exception {
+        System.out.println("writeRegister");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nOK\r\n", 10);
+        mi.addMessage("\r\nERROR:20\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short reg = 0x0C;
+        try {
+            testGateway.writeRegister(reg, "newpassword", "password");
+        } catch (TelegesisErrorException ex) {
+            fail("excepcion: " + ex.getErrorMessage());
+        }
+        boolean exception = false;
+        try {
+            testGateway.writeRegister(reg, "newpassword", "password");
+        } catch (TelegesisErrorException ex) {
+            exception = true;
+            System.out.println("excepcion error: " + ex.getErrorMessage());
+        }
+        if (!exception) {
+            fail("no ha saltado exception");
+        }
+    }
+
+    /**
+     * Test of readRemoteRegisterRequest method, of class Gateway305.
+     */
+    @Test
+    public void testReadRemoteRegisterRequest() throws Exception {
+        System.out.println("readRemoteRegisterRequest");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nSEQ:A1\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short reg = 0x0C;
+        short response = testGateway.readRemoteRegisterRequest("0025", reg);
+        if (!String.format("%02X", response).equals("A1")) {
+            fail("Enviado: A1 Recibido: " + String.format("%02X", response));
+        }
+    }
+
+    /**
+     * Test of writeRemoteRegisterRequest method, of class Gateway305.
+     */
+    @Test
+    public void testWriteRemoteRegisterRequest_3args() throws Exception {
+        System.out.println("writeRemoteRegisterRequest");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        short regAddress = 0x1A;
+        String regData = "0800";
+        mi.addMessage("\r\nSEQ:A1\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short result = testGateway.writeRemoteRegisterRequest(EUI64Addr, regAddress, regData);
+        short expResult = (short) 0xA1;
+        // comparamos seq recibido
+        if (result != expResult) {
+            fail("recibido: " + result + " Esperado: " + expResult);
+        }
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "ATREMS:" + EUI64Addr + ",1A=0800\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of writeRemoteRegisterRequest method, of class Gateway305.
+     */
+    @Test
+    public void testWriteRemoteRegisterRequest_4args() throws Exception {
+        System.out.println("writeRemoteRegisterRequest");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        String password = "tecnodis";
+        short regAddress = 0x1A;
+        String regData = "0800";
+        mi.addMessage("\r\nSEQ:A1\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short result = testGateway.writeRemoteRegisterRequest(EUI64Addr, regAddress, regData, password);
+        short expResult = (short) 0xA1;
+        // comparamos seq recibido
+        if (result != expResult) {
+            fail("recibido: " + result + " Esperado: " + expResult);
+        }
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "ATREMS:1122334455667788,1A=0800,tecnodis\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of scanEnergy method, of class Gateway305.
+     */
+    @Test
+    public void testScanEnergy() throws Exception {
+        System.out.println("scanEnergy");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\n+ESCAN:\r\n11:AA\r\n12:A9\r\n13:0C\r\n14:0D\r\n26:FF\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        short[] response = testGateway.scanEnergy();
+        short[] expectedResp = new short[16];
+        expectedResp[0] = (short) 0xAA;
+        expectedResp[1] = (short) 0xA9;
+        expectedResp[2] = (short) 0x0C;
+        expectedResp[3] = (short) 0x0D;
+        expectedResp[15] = (short) 0xFF;
+        for (int i = 0; i < 16; i++) {
+            if (response[i] != expectedResp[i]) {
+                fail("Canal " + i + " Recibido: " + response[i] + " Esperado: " + expectedResp[i]);
+            }
+        }
+
+    }
+
+    /**
+     * Test of scanForActivePANs method, of class Gateway305.
+     */
+    @Test
+    public void testScanForActivePANs() throws Exception {
+        System.out.println("scanForActivePANs");
+
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\n+PANSCAN:13,1030,60D52B879671815F,02,01\r\n", 1000);
+        mi.addMessage("\r\n+PANSCAN:20,1702,9261A18566C329AD,02,01\r\n", 1000);
+        mi.addMessage("\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+        PANScanResult[] response = testGateway.scanForActivePANs();
+        PANScanResult[] expectedResp = new PANScanResult[2];
+        expectedResp[0] = new PANScanResult((short) 13, "1030", "60D52B879671815F", (short) 02, true);
+        expectedResp[1] = new PANScanResult((short) 20, "1702", "9261A18566C329AD", (short) 02, true);
+        for (int i = 0; i < 2; i++) {
+            if ((response[i].getChannel() != expectedResp[i].getChannel())
+                    || (response[i].getJoinPermission() != expectedResp[i].getJoinPermission())
+                    || (!response[i].getPANID().equals(expectedResp[i].getPANID()))
+                    || (!response[i].getEPID().equals(expectedResp[i].getEPID()))
+                    || (response[i].getProfile() != expectedResp[i].getProfile())) {
+                fail("Canal " + i + " Recibido: " + response[i] + " Esperado: " + expectedResp[i]);
+            }
+
+        }
+    }
+
+    @Test
+    public void testPrompts() {
+
+        FakeGatewayListener fgl = new FakeGatewayListener();
+        testGateway.registerListener(fgl);
+        String message;
+
+        // ACK, NACK
+        message = "ACK:FF";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkAcknowledgementError((short) 0xFF, true, testGateway);
+        message = "NACK:01";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkAcknowledgementError((short) 0x01, false, testGateway);
+
+        // SR:XX,<EUI64>,<NodeID>,
+        message = "SR:02," + EUI64Addr + ",1001,1002";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkRouteRecordReceived(EUI64Addr, 02, new String[]{"1001", "1002"}, testGateway);
+
+
+        String[] dataArray = new String[]{"1234567890", "=23:4,5,"};
+        for (int j = 0; j < dataArray.length; j++) {
+            String data = dataArray[j];
+            // UCAST:[<EUI64>,]XX=<data>
+            // MCAST:[<EUI64>,]XX=<data>
+            String[] msgType = new String[]{"UCAST", "MCAST"};
+            for (int i = 0; i < 2; i++) {
+                message = String.format("%s:%s,%02X=%s", msgType[i], EUI64Addr, data.length(), data);
+                sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+                fgl.checkMessageReceived(EUI64Addr, data.getBytes(Charset.forName("ISO-8859-1")), msgType[i], testGateway);
+                message = String.format("%s:%02X=%s", msgType[i], data.length(), data);
+                sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+                fgl.checkMessageReceived(null, data.getBytes(Charset.forName("ISO-8859-1")), msgType[i], testGateway);
+
+            }
+            // BCAST:[<EUI64>,]XX=<data>
+            message = String.format("BCAST:%s,%02X=%s", EUI64Addr, data.length(), data);
+            sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+            fgl.checkBroadcastMessageReceived(EUI64Addr, data.getBytes(Charset.forName("ISO-8859-1")), testGateway);
+            message = String.format("BCAST:%02X=%s", data.length(), data);
+            sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+            fgl.checkBroadcastMessageReceived(null, data.getBytes(Charset.forName("ISO-8859-1")), testGateway);
+        }
+
+        //"COO:" + EUI64Addr + "," + nodeID,
+        //"FFD:" + EUI64Addr + "," + nodeID,
+        //"SED:" + EUI64Addr + "," + nodeID,
+        //"MED:" + EUI64Addr + "," + nodeID,
+        //"ZED:" + EUI64Addr + "," + nodeID,
+        short LQI = (short) 0xFF;
+        int RSSI = -70;
+
+        message = String.format("COO:%s,%s,%d,%02X", EUI64Addr, nodeID, RSSI, LQI);
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeAnnounce(ZigbeeDeviceType.Coordinator, EUI64Addr, nodeID, RSSI, LQI, testGateway);
+        message = String.format("FFD:%s,%s,%d,%02X", EUI64Addr, nodeID, RSSI, LQI);
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeAnnounce(ZigbeeDeviceType.Router, EUI64Addr, nodeID, RSSI, LQI, testGateway);
+        message = String.format("ZED:%s,%s,%d,%02X", EUI64Addr, nodeID, RSSI, LQI);
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeAnnounce(ZigbeeDeviceType.EndDevice, EUI64Addr, nodeID, RSSI, LQI, testGateway);
+        message = String.format("SED:%s,%s,%d,%02X", EUI64Addr, nodeID, RSSI, LQI);
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeAnnounce(ZigbeeDeviceType.SleepyEndDevice, EUI64Addr, nodeID, RSSI, LQI, testGateway);
+        message = String.format("MED:%s,%s,%d,%02X", EUI64Addr, nodeID, RSSI, LQI);
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeAnnounce(ZigbeeDeviceType.MobileEndDevice, EUI64Addr, nodeID, RSSI, LQI, testGateway);
+
+        //"NEWNODE:" + EUI64Addr + "," + nodeID + "," + nodeID,
+        message = "NEWNODE:" + nodeID + "," + EUI64Addr + "," + nodeID;
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNewNode(EUI64Addr, nodeID, nodeID, testGateway);
+
+        // LeftPAN
+        message = "LeftPAN";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkLeftPAN(testGateway);
+        message = "LostPAN";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkLeftPAN(testGateway);
+
+        // JPAN:<channel>,<PID>,<EPID>
+        message = "JPAN:" + channel + "," + PID + "," + EPID;
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkJoinedPan(channel, PID, EPID, testGateway);
+
+        //SREAD:<NodeID>,<EUI64>,<Register>, <errorcode>[=<Data>]
+        message = "SREAD:" + nodeID + "," + EUI64Addr + ",0B,00=1234";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkRegisterReaded(nodeID, EUI64Addr, (short) 0x0B, (short) 00, "1234", testGateway);
+        message = "SREAD:" + nodeID + "," + EUI64Addr + ",0B,02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkRegisterReaded(nodeID, EUI64Addr, (short) 0x0B, (short) 02, null, testGateway);
+
+        //SWRITE:<NodeID>,<EUI64>,<errorcode>
+        message = "SWRITE:" + nodeID + "," + EUI64Addr + ",00";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkRegisterWrited(nodeID, EUI64Addr, (short) 00, testGateway);
+        message = "SWRITE:" + nodeID + "," + EUI64Addr + ",02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkRegisterWrited(nodeID, EUI64Addr, (short) 02, testGateway);
+
+        //AddrResp:<errorcode>[,<NodeID>,<EUI64>]
+        message = "AddrResp:00," + nodeID + "," + EUI64Addr;
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkAddrResponse((short) 0, nodeID, EUI64Addr, testGateway);
+        message = "AddrResp:02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkAddrResponse((short) 02, null, null, testGateway);
+
+
+        //NTable...
+        message = "NTable:" + nodeID + ",00\r\n"
+                + "Length:02\r\n"
+                + "No. | Dev |       EUI        |  ID  | LQI\r\n"
+                + "00. | FFD | " + EUI64Addr + " | 1122 | FF\r\n"
+                + "01. | FFD | " + EUI64Addr + " | 1122 | FF";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        NeighbourTableEntry[] nti = new NeighbourTableEntry[2];
+        for (int i = 0; i < 2; i++) {
+            nti[i] = new NeighbourTableEntry((short) i, ZigbeeDeviceType.Router, EUI64Addr, "1122", (short) 0xFF);
+        }
+        fgl.checkNeighbourTableResponse(nodeID, (short) 0, 2, nti, testGateway);
+
+        message = "NTable:" + nodeID + ",02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNeighbourTableResponse(nodeID, (short) 2, 0, null, testGateway);
+
+        //NodeDesc
+        message = "NodeDesc:" + nodeID + ",00\r\n"
+                + "NodeDesc:0D57\r\n"
+                + "Type:FFD\r\n"
+                + "ComplexDesc:No\r\n"
+                + "UserDesc:No\r\n"
+                + "APSFlags:00\r\n"
+                + "FreqBand:40\r\n"
+                + "MacCap:8E\r\n"
+                + "ManufCode:1010\r\n"
+                + "MaxBufSize:52\r\n"
+                + "MaxInSize:0080\r\n"
+                + "SrvMask:0000\r\n"
+                + "MaxOutSize:0080\r\n"
+                + "DescCap:00";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        Map descriptor = new HashMap();
+        descriptor.put("NodeDesc", "0D57");
+        descriptor.put("Type", "FFD");
+        descriptor.put("ComplexDesc", "No");
+        descriptor.put("UserDesc", "No");
+        descriptor.put("APSFlags", "00");
+        descriptor.put("FreqBand", "40");
+        descriptor.put("MacCap", "8E");
+        descriptor.put("ManufCode", "1010");
+        descriptor.put("MaxBufSize", "52");
+        descriptor.put("MaxInSize", "0080");
+        descriptor.put("SrvMask", "0000");
+        descriptor.put("MaxOutSize", "0080");
+        descriptor.put("DescCap", "00");
+        fgl.checkNodeDescriptorResponse(nodeID, (short) 0, descriptor, testGateway);
+
+        //PowerDesc:<NodeID>,<errorcode> [,<PowerDescriptor>]
+        message = "PowerDesc:" + nodeID + ",00,1111";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkPowerDescriptorResponse(nodeID, (short) 0, "1111", testGateway);
+        message = "PowerDesc:" + nodeID + ",02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkPowerDescriptorResponse(nodeID, (short) 02, null, testGateway);
+
+        //ActEpDesc:<NodeID>,<errorcode>[,XX,...]
+        message = "ActEpDesc:" + nodeID + ",00,00,01";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        short[] EPList = new short[]{0, 1};
+        fgl.checkNodeActiveEPResponse(nodeID, (short) 0, EPList, testGateway);
+        message = "ActEpDesc:" + nodeID + ",02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeActiveEPResponse(nodeID, (short) 02, new short[0], testGateway);
+
+        //SimpleDesc:<NodeID>,<errorcode> EP:XX ProfileID:XXXX DeviceID:XXXXvXX InCluster:<Cluster List> OutCluster:<Cluster List>        
+        String profile = "0110";
+        String DeviceId = "0110v32";
+        message = "SimpleDesc:" + nodeID + ",00\r\n"
+                + "EP:01\r\n"
+                + "ProfileID:" + profile + "\r\n"
+                + "DeviceID:" + DeviceId + "\r\n"
+                + "InCluster:0020\r\n"
+                + "OutCluster:0020,0021";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeEndPointSimpleDescriptorResponse(nodeID, (short) 0, (short) 1, profile, DeviceId, new String[]{"0020"}, new String[]{"0020", "0021"}, testGateway);
+
+        message = "SimpleDesc:" + nodeID + ",00\r\n"
+                + "EP:01\r\n"
+                + "ProfileID:" + profile + "\r\n"
+                + "DeviceID:" + DeviceId + "\r\n"
+                + "InCluster:\r\n"
+                + "OutCluster:";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeEndPointSimpleDescriptorResponse(nodeID, (short) 0, (short) 1, profile, DeviceId, null, null, testGateway);
+
+        //MatchDesc:<NodeID>,<errorcode>,XX,…
+        message = "MatchDesc:" + nodeID + ",00,01,02";
+        sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+        fgl.checkNodeMatchingDescriptorResponse(nodeID, (short) 0, new short[]{0, 1}, testGateway);
+
+        //RX:<EUI64>,<NodeID>,<profileID>, <destinationEndpoint>,<SourceEndpoint>,<clusterID>,<length>:<payload>
+        String[] payloads = new String[]{"12345", "123455678901224", "::3,=00"};
+        String profileID = "1002";
+        short sourceEP = 0x01;
+        short destEP = 0x0F;
+        String clusterID = "1002";
+        for (int i = 0; i < payloads.length; i++) {
+            String payload = payloads[i];
+            message = String.format("RX:%s,%s,%s,%02X,%02X,%s,%02X:%s", EUI64Addr, nodeID, profileID, destEP, sourceEP, clusterID, payload.length(), payload);
+//            message = "RX:" + EUI64Addr + "," + nodeID + ",1002,00,F4,1002," + String.format("%02X", payload.length()) + ":" + payload;
+            sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+//            fgl.checkendpointMessageReceived(EUI64Addr, nodeID, (short) 0xF4, (short) 0, "1002", "1002", payload.getBytes(Charset.forName("ISO-8859-1")), testGateway);
+            fgl.checkendpointMessageReceived(EUI64Addr, nodeID, sourceEP, destEP, profileID, clusterID, payload.getBytes(Charset.forName("ISO-8859-1")), testGateway);
+
+        }
+
+        /**
+         * Notifies about and unhandled telegesis command:
+         * - SDATA
+         * - FN0130
+         * - SINK
+         * - ADSK
+         * - DataMODE
+         * - OPEN
+         * - CLOSED
+         * - TRACK
+         * - TRACK2
+         * - PWRCHANGE
+         * - RX
+         * - NM
+         * - ENTERING BLOAD
+         * @param command not handled command
+         * @param parameters command parameters list
+         * @param gtwy Gateway launching notification
+         */
+        String[] unhandledPrompts = new String[]{
+            "SDATA:12341234,12341234,12341234,01,12341234",
+            "SDATA:" + EUI64Addr + ",12341234,12341234,12341234,01,12341234",
+            "FN0130:" + nodeID + ",12341234,01,12341234",
+            "FN0130:" + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "FN0130:" + EUI64Addr + "," + nodeID + ",12341234,01,12341234",
+            "FN0130:" + EUI64Addr + "," + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "SINK:" + EUI64Addr + "," + nodeID,
+            "ADSK:" + EUI64Addr + "," + nodeID,
+            "DataMODE:" + nodeID + "," + EUI64Addr,
+            "DataMODE:" + nodeID + "," + EUI64Addr + ",00",
+            "OPEN",
+            "CLOSED",
+            "TRACK:" + EUI64Addr + "," + EUI64Addr + ",00,12341234,12341234,12341234,12341234,12341234",
+            "TRACK2:" + EUI64Addr + "," + EUI64Addr + ",00,12341234,12341234",
+            "PWRCHANGE:XXXX",
+            "NM:ES REPORT WARNING",
+            "ENTERING BLOAD"
+        };
+        for (int i = 0; i < unhandledPrompts.length; i++) {
+            message = unhandledPrompts[i];
+            String[] messageSplited = message.split(":");
+            String command = messageSplited[0];
+            String[] parameters;
+            if (messageSplited.length == 2) {
+                parameters = messageSplited[1].split(",");
+            } else {
+                parameters = new String[0];
+            }
+            sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+            fgl.checkUnhandledCommand(command, parameters, testGateway);
+
+        }
+
+        /**
+         * Notifies about unknonwn incomming messages
+         * @param message 
+         * @param gtwy Gateway launching notification
+         */
+        String[] unknonwMessages = new String[]{
+            "AA_SDATA:12341234,12341234,12341234,01,12341234",
+            "AA_SDATA:" + EUI64Addr + ",12341234,12341234,12341234,01,12341234",
+            "AA_FN0130:" + nodeID + ",12341234,01,12341234",
+            "AA_FN0130:" + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "AA_FN0130:" + EUI64Addr + "," + nodeID + ",12341234,01,12341234",
+            "AA_FN0130:" + EUI64Addr + "," + nodeID + ",12341234,01,12341234,12341234,12341234,12341234,12341234",
+            "AA_SINK:" + EUI64Addr + "," + nodeID,
+            "AA_ADSK:" + EUI64Addr + "," + nodeID,
+            "AA_DataMODE:" + nodeID + "," + EUI64Addr,
+            "AA_DataMODE:" + nodeID + "," + EUI64Addr + ",00",
+            "AA_OPEN",
+            "AA_CLOSED",
+            "AA_TRACK:" + EUI64Addr + "," + EUI64Addr + ",00,12341234,12341234,12341234,12341234,12341234",
+            "AA_TRACK2:" + EUI64Addr + "," + EUI64Addr + ",00,12341234,12341234",
+            "AA_PWRCHANGE:XXXX",
+            "AA_RX:" + EUI64Addr + "," + nodeID + ",0011,01,01,0123,08:12345678",
+            "AA_NM:ES REPORT WARNING",
+            "AA_ENTERING BLOAD"
+        };
+        for (int i = 0; i < unknonwMessages.length; i++) {
+            message = unknonwMessages[i];
+            sp.injectMessage(("\r\n" + message + "\r\n").getBytes(Charset.forName("ISO-8859-1")));
+            fgl.checkUnknownMessage(message, testGateway);
+        }
+
+
+    }
+
+    /**
+     * Test of createNetwork method, of class Gateway305.
+     */
+    @Test
+    public void testCreateNetwork() throws Exception {
+        System.out.println("createNetwork");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nJPAN:11,011A,1122334455667788\r\n\r\nOK\r\n", 1000);
+        Thread th = new Thread(mi);
+        th.start();
+
+        NetworkJoinedInfo nji = testGateway.createNetwork();
+        if (!nji.getEPID().equals("1122334455667788")) {
+            fail("error EPID " + nji.getEPID());
+        } else if (!nji.getPANID().equals("011A")) {
+            fail("error PANID " + nji.getPANID());
+        } else if (nji.getChannel() != 11) {
+            fail("error channel " + nji.getChannel());
+
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+EN\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of joinNetwork method, of class Gateway305.
+     */
+    @Test
+    public void testJoinNetwork_0args() throws Exception {
+        System.out.println("joinNetwork");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nJPAN:11,011A,1122334455667788\r\n\r\nOK\r\n", 1000);
+        Thread th = new Thread(mi);
+        th.start();
+
+        NetworkJoinedInfo nji = testGateway.joinNetwork();
+        if (!nji.getEPID().equals("1122334455667788")) {
+            fail("error EPID " + nji.getEPID());
+        } else if (!nji.getPANID().equals("011A")) {
+            fail("error PANID " + nji.getPANID());
+        } else if (nji.getChannel() != 11) {
+            fail("error channel " + nji.getChannel());
+
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+JN\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of joinNetwork method, of class Gateway305.
+     */
+    @Test
+    public void testJoinNetwork_String_String() throws Exception {
+        System.out.println("joinNetwork");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nJPAN:20,011A,1122334455667788\r\n\r\nOK\r\n", 1000);
+        Thread th = new Thread(mi);
+        th.start();
+
+        NetworkJoinedInfo nji = testGateway.joinNetwork(20, "011A");
+        if (!nji.getEPID().equals("1122334455667788")) {
+            fail("error EPID " + nji.getEPID());
+        } else if (!nji.getPANID().equals("011A")) {
+            fail("error PANID " + nji.getPANID());
+        } else if (nji.getChannel() != 20) {
+            fail("error channel " + nji.getChannel());
+
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+JPAN:20,011A\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of leaveNetwork method, of class Gateway305.
+     */
+    @Test
+    public void testLeaveNetwork() throws Exception {
+        System.out.println("leaveNetwork");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.leaveNetwork();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+DASSL\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of leaveNetworkRequest method, of class Gateway305.
+     */
+    @Test
+    public void testLeaveNetworkRequest() throws Exception {
+        System.out.println("leaveNetworkRequest");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\nSEQ:1A\r\n\r\nOK\r\n", 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        String address = "112234455667788";
+        short expResult = 0x1A;
+        short result = testGateway.leaveNetworkRequest(address);
+        if (result != expResult) {
+            fail("recibido: " + result + " Esperado: " + expResult);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+DASSR:" + address + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of getNetworkInformation method, of class Gateway305.
+     */
+    @Test
+    public void testGetNetworkInformation() {
+        System.out.println("getNetworkInformation");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage("\r\n+N=COO," + channel + ",A3," + PID + "," + EPID + "\r\n" + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        NetworkInformation expResult =
+                new NetworkInformation(ZigbeeDeviceType.Coordinator, channel, (short) 0xA3, PID, EPID);
+        NetworkInformation result = testGateway.getNetworkInformation();
+        if (result.getChannel() != expResult.getChannel()) {
+            fail("result.getChannel(): " + result.getChannel());
+        } else if (result.getPower() != expResult.getPower()) {
+            fail("result.getPower(): " + result.getPower());
+        } else if (result.getDeviceType() != expResult.getDeviceType()) {
+            fail("result.getDeviceType(): " + result.getDeviceType());
+        } else if (!result.getPID().equals(expResult.getPID())) {
+            fail("result.getPID(): " + result.getPID());
+        } else if (!result.getEPID().equals(expResult.getEPID())) {
+            fail("result.getEPID(): " + result.getEPID());
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+N?\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNeighbourTable method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNeighbourTable_byte_String() throws Exception {
+        System.out.println("requestNeighbourTable");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short index = 0;
+        short expResult = 0x1A;
+        short result = testGateway.requestNeighbourTable(index, EUI64Addr);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+NTABLE:00," + EUI64Addr + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNodeId method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodeId() throws Exception {
+        System.out.println("requestNodeId");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.requestNodeId(EUI64Addr);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+IDREQ:" + EUI64Addr + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNodeEUI64Addr method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodeEUI64Addr() throws Exception {
+        System.out.println("requestNodeEUI64Addr");
+        String nodeId = "1030";
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short expResult = 0x1A;
+        short result = testGateway.requestNodeEUI64Addr(EUI64Addr, nodeId);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+EUIREQ:" + EUI64Addr + "," + nodeId + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of requestNodeDescriptor method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodeDescriptor() throws Exception {
+        System.out.println("requestNodeDescriptor");
+        String nodeId = "1030";
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short expResult = 0x1A;
+        short result = testGateway.requestNodeDescriptor(EUI64Addr, nodeId);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+NODEDESC:" + EUI64Addr + "," + nodeId + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNodePowerDescriptor method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodePowerDescriptor() throws Exception {
+        System.out.println("requestNodePowerDescriptor");
+        String nodeId = "1030";
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short expResult = 0x1A;
+        short result = testGateway.requestNodePowerDescriptor(EUI64Addr, nodeId);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+POWERDESC:" + EUI64Addr + "," + nodeId + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNodeActiveEndPoints method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodeActiveEndPoints() throws Exception {
+        System.out.println("requestNodeActiveEndPoints");
+        String nodeId = "1030";
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short expResult = 0x1A;
+        short result = testGateway.requestNodeActiveEndPoints(EUI64Addr, nodeId);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+ACTEPDESC:" + EUI64Addr + "," + nodeId + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of requestNodeEndPointSimpleDescriptor method, of class Gateway305.
+     */
+    @Test
+    public void testRequestNodeEndPointSimpleDescriptor() throws Exception {
+        System.out.println("requestNodeEndPointSimpleDescriptor");
+        short EP = 0x1A;
+        String nodeId = "1030";
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short expResult = 0x1A;
+        short result = testGateway.requestNodeEndPointSimpleDescriptor(EUI64Addr, nodeId, EP);
+        if (result != expResult) {
+            fail("result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+SIMPLEDESC:" + EUI64Addr + "," + nodeId + ",1A\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of findNodesMatchingDescriptor method, of class Gateway305.
+     */
+    @Test
+    public void testFindNodesMatchingDescriptor() throws Exception {
+        System.out.println("findNodesMatchingDescriptor");
+
+
+        String profileId = "C091";
+        String[] inClusterList = new String[]{"0002"};
+        String[] outClusterList = new String[]{"0004", "000B"};
+
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.findNodesMatchingDescriptor(profileId, inClusterList, outClusterList);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+MATCHREQ:C091,01,0002,02,0004,000B\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of annouceLocalNode method, of class Gateway305.
+     */
+    @Test
+    public void testAnnouceLocalNode() throws Exception {
+        System.out.println("annouceLocalNode");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.annouceLocalNode();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+ANNCE\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of setSourceRoute method, of class Gateway305.
+     */
+    @Test
+    public void testSetSourceRoute() throws Exception {
+        System.out.println("setSourceRoute");
+        String destNode = "0100";
+        String[] route = new String[]{"0101", "0102"};
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.setSourceRoute(destNode, route);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+SR:0100,0101,0102\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of findRoute method, of class Gateway305.
+     */
+    @Test
+    public void testFindRoute() throws Exception {
+        System.out.println("findRoute");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.findRoute(EUI64Addr);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+FNDSR:" + EUI64Addr + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of scanNetwork method, of class Gateway305.
+     */
+    @Test
+    public void testScanNetwork() throws Exception {
+        System.out.println("scanNetwork");
+        int numHops = 02;
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.scanNetwork(numHops);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+SN:02\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of updateNetworkKey method, of class Gateway305.
+     */
+    @Test
+    public void testUpdateNetworkKey() throws Exception {
+        System.out.println("updateNetworkKey");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.updateNetworkKey();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+KEYUPD\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of becomeTrustCenter method, of class Gateway305.
+     */
+    @Test
+    public void testBecomeTrustCenter() throws Exception {
+        System.out.println("becomeTrustCenter");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.becomeTrustCenter();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+BECOMETC\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of becomeNetworkManager method, of class Gateway305.
+     */
+    @Test
+    public void testBecomeNetworkManager() throws Exception {
+        System.out.println("becomeNetworkManager");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.becomeNetworkManager();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+BECOMENM\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of changeNetworkChannel method, of class Gateway305.
+     */
+    @Test
+    public void testChangeNetworkChannel_0args() throws Exception {
+        System.out.println("changeNetworkChannel");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.changeNetworkChannel();
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+CCHANGE\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of changeNetworkChannel method, of class Gateway305.
+     */
+    @Test
+    public void testChangeNetworkChannel_int() throws Exception {
+        System.out.println("changeNetworkChannel");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.changeNetworkChannel(channel);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+CCHANGE:" + String.format("%02d", channel) + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of getAddressTable method, of class Gateway305.
+     */
+    @Test
+    public void testGetAddressTable() {
+        System.out.println("getAddressTable");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        String cmdResponse1 = "\r\n"
+                + "No. | Active |  ID  | EUI\r\n"
+                + "00  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n"
+                + "01  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n"
+                + "02  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n";
+        String cmdResponse2 = "03  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n"
+                + "04  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n"
+                + "05  |   N    | FFFF |FFFFFFFFFFFFFFFF\r\n"
+                + OK_FRAME;
+        mi.addMessage(cmdResponse1, 10);
+        mi.addMessage(cmdResponse2, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+
+        AddressTableEntry[] result = testGateway.getAddressTable();
+        for (int i = 0; i < 6; i++) {
+            if (result[i].getIndex() != i) {
+                fail("AddressTableEntry[" + i + "].getIndex = " + result[i].getIndex());
+            } else if (result[i].getActive() != false) {
+                fail("AddressTableEntry[" + i + "].getActive = " + result[i].getActive());
+            } else if (!result[i].getID().equals("FFFF")) {
+                fail("AddressTableEntry[" + i + "].getID = " + result[i].getID());
+            } else if (!result[i].getEUI64Addr().equals("FFFFFFFFFFFFFFFF")) {
+                fail("AddressTableEntry[" + i + "].getEUI64Addr = " + result[i].getEUI64Addr());
+            }
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+ATABLE\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of setAddressTableEntry method, of class Gateway305.
+     */
+    @Test
+    public void testSetAddressTableEntry() throws Exception {
+        System.out.println("setAddressTableEntry");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short index = 01;
+
+        testGateway.setAddressTableEntry(index, nodeID, EUI64Addr);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+ASET:01," + nodeID + "," + EUI64Addr + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of getMulticastTable method, of class Gateway305.
+     */
+    @Test
+    public void testGetMulticastTable() {
+        System.out.println("getMulticastTable");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        String cmdResponse1 = "\r\n"
+                + "No. |  ID  | EP\r\n"
+                + "00  | 0000 | 01\r\n"
+                + "01  | 0000 | 01\r\n";
+        String cmdResponse2 = "02  | 0000 | 01\r\n"
+                + "03  | 0000 | 01\r\n"
+                + "04  | 0000 | 01\r\n"
+                + OK_FRAME;
+        String cmdResponse = "\r\n"
+                + "No. |  ID  | EP\r\n"
+                + "00  | 0000 | 01\r\n"
+                + "01  | 0000 | 01\r\n"
+                + "02  | 0000 | 01\r\n"
+                + "03  | 0000 | 01\r\n"
+                + "04  | 0000 | 01\r\n"
+                + OK_FRAME;
+//        mi.addMessage(cmdResponse, 10);
+        mi.addMessage(cmdResponse1, 10);
+        mi.addMessage(cmdResponse2, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+
+        MulticastTableEntry[] result = testGateway.getMulticastTable();
+        for (int i = 1; i < 5; i++) {
+            if (result[i].getIndex() != i) {
+                fail("MulticastTableEntry[" + i + "].getIndex = " + result[i].getIndex());
+            } else if (!result[i].getID().equals("0000")) {
+                fail("AddressTableEntry[" + i + "].getID = " + result[i].getID());
+            } else if (result[i].getEP() != (short) 01) {
+                fail("AddressTableEntry[" + i + "].getEP = " + result[i].getEP());
+            }
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+MTABLE\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of setMulticastTableEntry method, of class Gateway305.
+     */
+    @Test
+    public void testSetMulticastTableEntry() throws Exception {
+        System.out.println("setMulticastTableEntry");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.setMulticastTableEntry((short) 01, "1234", (short) 01);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+MSET:01,1234,01\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of sendBroadcast method, of class Gateway305.
+     */
+    @Test
+    public void testSendBroadcast_int_String() throws Exception {
+        System.out.println("sendBroadcast");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.sendBroadcast((short) 01, "1234");
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+BCAST:01,1234\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of sendBroadcast method, of class Gateway305.
+     */
+    @Test
+    public void testSendBroadcast_int_byteArr() throws Exception {
+        System.out.println("sendBroadcast");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        testGateway.sendBroadcast((short) 01, "1234".getBytes(Charset.forName("ISO-8859-1")));
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+BCASTB:04,01\r1234\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+    }
+
+    /**
+     * Test of sendMessageRequest method, of class Gateway305.
+     */
+    @Test
+    public void testSendMessageRequest_String_String() throws Exception {
+        System.out.println("sendMessageRequest");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+//        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        mi.addMessage(SEQ_FRAME_FA + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short result = testGateway.sendMessageRequest(EUI64Addr, "1234");
+        if (result != (short) 0xFA) {
+            fail("recibido result: " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+UCAST:" + EUI64Addr + "=1234\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of sendMessageRequest method, of class Gateway305.
+     */
+    @Test
+    public void testSendMessageRequest_String_byteArr() throws Exception {
+        System.out.println("sendMessageRequest");
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(SEQ_FRAME_1A + OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+
+        short result = testGateway.sendMessageRequest(EUI64Addr, "1234".getBytes(Charset.forName("ISO-8859-1")));
+        if (result != 0x1A) {
+            fail("recibido result : " + result);
+        }
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+UCASTB:04," + EUI64Addr + "\r1234\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of sendMulticastBroadcast method, of class Gateway305.
+     */
+    @Test
+    public void testSendMulticastBroadcast_3args_1() throws Exception {
+        System.out.println("sendMulticastBroadcast");
+
+
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+        String ID = "1030";
+        String data = "12345";
+
+        testGateway.sendMulticastBroadcast(0, ID, data);
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+MCAST:00," + ID + "," + data + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+
+    /**
+     * Test of sendMulticastBroadcast method, of class Gateway305.
+     */
+    @Test
+    public void testSendMulticastBroadcast_3args_2() throws Exception {
+        System.out.println("sendMulticastBroadcast");
+        sp.clearMessagesWrited();
+        MessageInjector mi = new MessageInjector(sp);
+        mi.addMessage(OK_FRAME, 10);
+        Thread th = new Thread(mi);
+        th.start();
+        String ID = "1030";
+        String data = "12345";
+
+        testGateway.sendMulticastBroadcast(0, ID, data.getBytes(Charset.forName("ISO-8859-1")));
+
+        // comparamos mensaje enviado
+        String msgSent = sp.getLastMessageWrited();
+        String msgExpected = "AT+MCASTB:" + String.format("%02X", data.length()) + ",00," + ID + "\r" + data + "\r";
+        if (!msgSent.equals(msgExpected)) {
+            fail("Enviado: " + msgSent + " Esperado: " + msgExpected);
+        }
+
+    }
+}




More information about the Commit mailing list