[zb4osgi-changeset] [scm] ZigBee 4 OSGi repository change: r405 - in /projects/zb4osgi/sandbox/howlab/telegesis-driver-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/driver/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/ src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/ 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/driver/ 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/driver/ src/test/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/

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


Author: alvaro.marco
Date: Thu Feb  2 13:18:42 2012
New Revision: 405

Log:
howlab import

Added:
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/LICENSE
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/config.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.core.zigbee.telegesis.driver.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.io.serial.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/nbactions.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/pom.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/assembly/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/assembly/felix.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/AbstractDriver.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/Driver305.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/DriverFactory.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeDeviceImpl.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeNodeImpl.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/AbstractDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ErrorCheckerDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NeighbourFinderDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NodeRegisterUpdaterDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ParentFinderDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ZigbeeDevicesFinderDriverMaintenanceTask.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/Activator.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/GatewayServiceTracker.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/ZigbeePublisher.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/AbstractGatewayListener.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrACK.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrActiveEndPoints.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrAddrResponse.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrEndPointDescriptor.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrNeighbourTableResponse.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterRead.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterWrited.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrSourceRoute.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/Register305.java
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/LICENSE
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/driver/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/driver/es.unizar.howlab.core.zigbee.telegesis.driver.xml
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/core/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/core/zigbee/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/driver/
    projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/test/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/LICENSE
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/LICENSE (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/LICENSE Thu Feb  2 13:18:42 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-driver-impl/config.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/config.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/config.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : 11 de agosto de 2011, 17:35
+    Author     : alvaro
+    Description:
+        Purpose of the document follows.
+                
+-->
+
+<root>
+    <es.unizar.howlab.core.zigbee.telegesis.driver>
+        <autostart>true</autostart><!-- Arranca el driver al crearlo -->
+        
+        <ack_timeout>3000</ack_timeout><!-- Timeout para respuestas ACK -->
+        <register_read_timeout>3000</register_read_timeout><!-- Timeout para respuestas register_read -->
+        <register_write_timeout>3000</register_write_timeout><!-- Timeout para respuestas regiter_write -->
+        <zdo_response_timeout>3000</zdo_response_timeout><!-- Timeout para respuestas ZDO (ep_list, ep_descriptor) -->
+        <neighbour_response_timeout>10000</neighbour_response_timeout><!-- Timeout para respuestas de tabla de vecinos -->
+
+        <get_neighbours>true</get_neighbours><!-- Incluye la busqueda de vecinos en las tareas periódicas -->
+        <get_neighbours_frame_delay>5</get_neighbours_frame_delay><!-- Tiempo de separación entre nodos para busqueda de vecinos -->
+        <get_neighbours_recovery_period>5</get_neighbours_recovery_period> <!-- Periodo para reintentar las busquedas de vecinos fallidas -->
+        <get_neighbours_maintenance_period>60</get_neighbours_maintenance_period><!-- Periodo para actualizar los vecinos de los nodos -->
+        
+        <get_parent>true</get_parent><!-- Incluye la busqueda del padre en las tareas periódicas -->
+        <get_parent_frame_delay>5</get_parent_frame_delay><!-- Tiempo de separación entre nodos para busqueda de padre -->
+        <get_parent_recovery_period>5</get_parent_recovery_period> <!-- Periodo para reintentar las busquedas de padres fallidas -->
+        <get_parent_maintenance_period>60</get_parent_maintenance_period><!-- Periodo para actualizar los padres de los nodos -->
+        
+        <get_zigbee_devices>true</get_zigbee_devices><!-- Incluye la busqueda de endpoints en las tareas peiódicas -->
+        <get_zigbee_devices_frame_delay>5</get_zigbee_devices_frame_delay><!-- Tiempo de separación entre nodos para busqueda de endpoints -->
+        <get_zigbee_devices_recovery_period>5</get_zigbee_devices_recovery_period><!-- Periodo para reintentar las busquedas de endpoints fallidas -->
+        
+        <update_dongle_s_registers>false</update_dongle_s_registers><!-- Actualiza la configuracion del dongle al conectarlo -->
+        <update_node_s_registers>false</update_node_s_registers><!-- Actualiza la configuracion de los nodos al detectarlos -->
+        <update_node_s_registers_frame_delay>5</update_node_s_registers_frame_delay><!-- Tiempo de separación entre nodos para escritura de registros -->
+        <update_node_s_registers_recovery_period>5</update_node_s_registers_recovery_period><!-- Periodo para reintentar las escrituras de registros fallidas -->
+        
+        <s_register_password>Tormenta</s_register_password><!-- Contraseña para registros protegidos contra escritura -->
+        <s_reg_xcast_source_ep>02</s_reg_xcast_source_ep><!-- End point para mensajes enviados por el ZDO -->
+        <node_registers>
+            <address>dongle</address>    <!-- Registros a escribir en el dongle -->
+            <s_registers>
+                <s_register>
+                    <address>00</address>
+                    <value>3FFC</value>                    
+                </s_register>
+                <s_register>
+                    <address>02</address><!-- PID -->
+                    <value>1234</value>                    
+                </s_register>
+                <s_register>
+                    <address>09</address>
+                    <value>00123400000000000000000000000000</value>                    
+                </s_register>
+                <s_register>
+                    <address>0A</address>
+                    <value>001C</value>                    
+                </s_register>
+                <s_register>
+                    <address>0B</address>
+                    <value>COO_test1</value>                    
+                </s_register>
+                <s_register>
+                    <address>10</address>
+                    <value>159A</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4E</address>
+                    <value>0AE1</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4F</address>
+                    <value>FFFF</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0E</address>
+                    <value>8000</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0F</address>
+                    <value>0006</value>                    
+                </s_register>                
+                <s_register>
+                    <address>11</address>
+                    <value>0300</value>                    
+                </s_register>                
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                
+            </s_registers>
+        </node_registers>
+        <node_registers>  <!-- Registros a escribir en el nodo "0011223344556677" -->
+            <address>0011223344556677</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        <node_registers>  <!-- Registros a escribir en el nodo "8899aabbccddeeff" -->
+            <address>8899aabbccddeeff</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        
+    </es.unizar.howlab.core.zigbee.telegesis.driver>
+
+</root>

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.core.zigbee.telegesis.driver.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.core.zigbee.telegesis.driver.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.core.zigbee.telegesis.driver.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : 11 de agosto de 2011, 17:35
+    Author     : alvaro
+    Description:
+        Purpose of the document follows.
+                
+-->
+
+<root>
+    <es.unizar.howlab.core.zigbee.telegesis.driver>
+        <autostart>true</autostart><!-- Arranca el driver al crearlo -->
+        
+        <ack_timeout>3000</ack_timeout><!-- Timeout para respuestas ACK -->
+        <register_read_timeout>3000</register_read_timeout><!-- Timeout para respuestas register_read -->
+        <register_write_timeout>3000</register_write_timeout><!-- Timeout para respuestas regiter_write -->
+        <zdo_response_timeout>3000</zdo_response_timeout><!-- Timeout para respuestas ZDO (ep_list, ep_descriptor) -->
+        <neighbour_response_timeout>10000</neighbour_response_timeout><!-- Timeout para respuestas de tabla de vecinos -->
+
+        <get_neighbours>true</get_neighbours><!-- Incluye la busqueda de vecinos en las tareas periódicas -->
+        <get_neighbours_frame_delay>5</get_neighbours_frame_delay><!-- Tiempo de separación entre nodos para busqueda de vecinos -->
+        <get_neighbours_recovery_period>5</get_neighbours_recovery_period> <!-- Periodo para reintentar las busquedas de vecinos fallidas -->
+        <get_neighbours_maintenance_period>60</get_neighbours_maintenance_period><!-- Periodo para actualizar los vecinos de los nodos -->
+        
+        <get_parent>true</get_parent><!-- Incluye la busqueda del padre en las tareas periódicas -->
+        <get_parent_frame_delay>5</get_parent_frame_delay><!-- Tiempo de separación entre nodos para busqueda de padre -->
+        <get_parent_recovery_period>5</get_parent_recovery_period> <!-- Periodo para reintentar las busquedas de padres fallidas -->
+        <get_parent_maintenance_period>60</get_parent_maintenance_period><!-- Periodo para actualizar los padres de los nodos -->
+        
+        <get_zigbee_devices>true</get_zigbee_devices><!-- Incluye la busqueda de endpoints en las tareas peiódicas -->
+        <get_zigbee_devices_frame_delay>5</get_zigbee_devices_frame_delay><!-- Tiempo de separación entre nodos para busqueda de endpoints -->
+        <get_zigbee_devices_recovery_period>5</get_zigbee_devices_recovery_period><!-- Periodo para reintentar las busquedas de endpoints fallidas -->
+        
+        <update_dongle_s_registers>false</update_dongle_s_registers><!-- Actualiza la configuracion del dongle al conectarlo -->
+        <update_node_s_registers>false</update_node_s_registers><!-- Actualiza la configuracion de los nodos al detectarlos -->
+        <update_node_s_registers_frame_delay>5</update_node_s_registers_frame_delay><!-- Tiempo de separación entre nodos para escritura de registros -->
+        <update_node_s_registers_recovery_period>5</update_node_s_registers_recovery_period><!-- Periodo para reintentar las escrituras de registros fallidas -->
+        
+        <s_register_password>Tormenta</s_register_password><!-- Contraseña para registros protegidos contra escritura -->
+        <s_reg_xcast_source_ep>02</s_reg_xcast_source_ep><!-- End point para mensajes enviados por el ZDO -->
+        <node_registers>
+            <address>dongle</address>    <!-- Registros a escribir en el dongle -->
+            <s_registers>
+                <s_register>
+                    <address>00</address>
+                    <value>3FFC</value>                    
+                </s_register>
+                <s_register>
+                    <address>02</address><!-- PID -->
+                    <value>1234</value>                    
+                </s_register>
+                <s_register>
+                    <address>09</address>
+                    <value>00123400000000000000000000000000</value>                    
+                </s_register>
+                <s_register>
+                    <address>0A</address>
+                    <value>001C</value>                    
+                </s_register>
+                <s_register>
+                    <address>0B</address>
+                    <value>COO_test1</value>                    
+                </s_register>
+                <s_register>
+                    <address>10</address>
+                    <value>159A</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4E</address>
+                    <value>0AE1</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4F</address>
+                    <value>FFFF</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0E</address>
+                    <value>8000</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0F</address>
+                    <value>0006</value>                    
+                </s_register>                
+                <s_register>
+                    <address>11</address>
+                    <value>0300</value>                    
+                </s_register>                
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                
+            </s_registers>
+        </node_registers>
+        <node_registers>  <!-- Registros a escribir en el nodo "0011223344556677" -->
+            <address>0011223344556677</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        <node_registers>  <!-- Registros a escribir en el nodo "8899aabbccddeeff" -->
+            <address>8899aabbccddeeff</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        
+    </es.unizar.howlab.core.zigbee.telegesis.driver>
+
+</root>

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.io.serial.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.io.serial.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/es.unizar.howlab.io.serial.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : June 8, 2011, 9:15 AM
+    Author     : ciru
+    Description:
+        Purpose of the document follows.
+-->
+
+<config>
+
+    <connections>
+         <connection>
+            <protocol>rs232</protocol>
+            <where>/dev/ttyUSB0</where>
+            <how>19200</how>
+            <connectTime>3000</connectTime>
+            <retry>true</retry>
+        </connection>
+        <!--connection>
+            <protocol>tcp</protocol>
+            <where>192.168.0.3</where>
+            <how>10001</how>
+            <connectTime>1000</connectTime>
+            <retry>false</retry>
+        </connection
+        <connection>
+            <protocol>tcp</protocol>
+            <where>192.168.0.5</where>
+            <how>10001</how>
+            <connectTime>1000</connectTime>
+            <retry>false</retry>
+        </connection>-->
+    </connections>
+</config>

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/nbactions.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/nbactions.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/nbactions.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,78 @@
+<?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>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-driver-impl/pom.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/pom.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/pom.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,286 @@
+
+<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-driver-impl</artifactId>
+    <version>1.5-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>telegesis-driver-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/driver-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>
+        </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.zigbee.telegesis</groupId>
+            <artifactId>telegesis-gateway-api</artifactId>
+            <version>1.3</version>
+            <type>bundle</type>
+        </dependency>
+        <dependency>
+            <groupId>es.unizar.howlab.core.zigbee.telegesis</groupId>
+            <artifactId>telegesis-driver-api</artifactId>
+            <version>1.3</version>
+            <type>bundle</type>
+        </dependency>
+        <dependency>
+            <groupId>es.unizar.howlab.core</groupId>
+            <artifactId>easyJavaLib</artifactId>
+            <version>1.6</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.driver.impl.osgi.Activator</Bundle-Activator>
+<!--                        <Embed-Transitive>true</Embed-Transitive>
+                        <Embed-Dependency>*;artifactId=commons-configuration|commons-beanutils|commons-digester|commons-jxpath|mail|javax.servlet</Embed-Dependency>-->
+                        <Export-Package>es.unizar.howlab.core.zigbee.telegesis.driver,es.unizar.howlab.core.zigbee.telegesis.driver.impl</Export-Package>
+                        <Private-Package>es.unizar.howlab.core.zigbee.telegesis.driver.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>
+                <dependency>
+                    <groupId>es.unizar.howlab.core.io.serial</groupId>
+                    <artifactId>serial-gui</artifactId>
+                    <version>1.0-SNAPSHOT</version>
+                </dependency>
+                <dependency>
+                    <groupId>es.unizar.howlab.core.io.serial</groupId>
+                    <artifactId>serial-imp</artifactId>
+                    <version>1.0-SNAPSHOT</version>
+                </dependency>
+                <dependency>
+                    <groupId>es.unizar.howlab.core.zigbee.telegesis</groupId>
+                    <artifactId>telegesis-gateway-impl</artifactId>
+                    <version>1.0-SNAPSHOT</version>
+                    <type>bundle</type>
+                </dependency>
+                <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-driver-impl/src/main/assembly/felix.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/assembly/felix.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/assembly/felix.xml Thu Feb  2 13:18:42 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-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/AbstractDriver.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/AbstractDriver.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/AbstractDriver.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,1314 @@
+/*
+ * 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.driver.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.DriverListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.EUI64Address;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkAddress;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkInfo;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.ZigbeeNodeType;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+import es.unizar.howlab.easyjavalib.threading.Locker;
+import es.unizar.howlab.easyjavalib.xml.XMLConfiguration;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public abstract class AbstractDriver implements Driver, ManagedService {
+    // Logger
+
+    private Log logger = LogFactory.getLog(this.getClass().getName());
+    // Gateway 
+    protected final Gateway gateway;
+    // nodo conectado al gateway
+    private ZigbeeNode dongle;
+    private DriverStatus status = DriverStatus.Unknown;
+
+    public AbstractDriver(Gateway gtwy) {
+        logger.trace("AbstractDriver::AbstractDriver(gtwy=" + gtwy + ")");
+        // establecemos el gateway
+        gateway = gtwy;
+    }
+    //
+    // <editor-fold defaultstate="collapsed" desc="ESTATUS DE LA RED">    
+    // parámetros de red
+    private int networkChanel;
+    private String networkPID;
+    private String networkEPID;
+    private ZigbeeNode coordinator;
+
+//    @Override
+//    abstract public NetworkInfo readNetworkInfo();
+    @Override
+    public NetworkInfo getNetworkInfo() {
+        logger.trace("Driver::getNetworkInfo()");
+        if (networkPID == null) {
+            return null;
+        } else {
+            return new NetworkInfo(networkChanel, networkPID, networkEPID);
+        }
+    }
+
+    /**
+     * Comprueba si el driver está unido a la red
+     * @return TRUE si el driver está unido a la red
+     */
+    protected boolean isJoinedToNetwork() {
+        return (networkChanel > 0);
+    }
+
+    /**
+     * Establece el driver como conectado a la red
+     * @param channel
+     * @param PID
+     * @param EPID 
+     */
+    protected void setNetworkJoined(int channel, String PID, String EPID) {
+        logger.trace("Driver::setNetworkJoined(channel=" + channel + ", PID=" + PID + ", EPID=" + EPID + ")");
+        // comprobamos si ha cambiado algún parámetro
+        if ((channel != networkChanel)
+                || (!PID.equals(networkPID))
+                || (!EPID.equals(networkEPID))) {
+            networkChanel = channel;
+            networkPID = PID;
+            networkEPID = EPID;
+            logger.info("[ZigbeeDriver] joined to network (channel=" + channel + ", PID=" + PID + ", EPID=" + EPID + ")");
+            fireJoinNetwork(channel, PID, EPID);
+        }
+    }
+
+    /**
+     * Establece el driver como desconectado a la red
+     */
+    protected void setNetworkLeft() {
+        logger.trace("Driver::setNetworkLeft()");
+        // comprobamos si ha cambiado algún parámetro
+        if ((networkChanel != 0)
+                || (networkPID != null)
+                || (networkEPID != null)) {
+            networkChanel = 0;
+            networkPID = null;
+            networkEPID = null;
+            logger.info("[ZigbeeDriver] left network");
+            // eliminamos todos los nodos (salvo el dongle)
+            Iterator<String> it = nodes.keySet().iterator();
+            while (it.hasNext()) {
+                String EUI64Addr = it.next();
+                // comprobamos si coincide con el dongle
+                if (!dongle.getEUI64Addr().toString().equals(EUI64Addr)) {
+                    it.remove();
+                }
+            }
+
+            // eliminamos el coordinador
+            coordinator = null;
+
+            // notificamos abandonamos red
+            fireLeftNetwork();
+        }
+    }
+
+    /**
+     * Establece el coordinador de la red
+     * @param node nodo a comprobar si es el coordinador
+     * @return True si el nodo es coordinador, false en otro caso
+     */
+    protected boolean checkSetCoordinator(ZigbeeNode node) {
+        logger.trace("Driver::checkSetCoordinator(node=" + node + ")");
+        if (node.getType() == ZigbeeNodeType.Coordinator) {
+            this.coordinator = node;
+            logger.info("[ZigbeeDriver] Coordinator set: " + node);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Crea el nodo asociado al dongle a partir de la dirección del nodo
+     * @param EUI64Addr Dirección del nodo
+     * @param nodeID Dirección de red del nodo
+     * @param type tipo de nodo
+     */
+    public void createDongle(String EUI64Addr, String nodeID, ZigbeeNodeType type) {
+        logger.trace("Driver::createDongle(EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", type=" + type + ")");
+
+        // creamos el dongle, 
+        if (nodeID == null) {
+            dongle = createNode(new EUI64Address(EUI64Addr), type);
+        } else {
+            dongle = createNode(new EUI64Address(EUI64Addr), new NetworkAddress(nodeID), type);
+        }
+
+        // actualizamos el coordinador de la red (si fuera el caso)
+        checkSetCoordinator(dongle);
+
+
+
+    }
+    // </editor-fold>    
+//    @Override
+//    abstract public NetworkScanInfo[] findNetworks();
+//
+//    @Override
+//    abstract public boolean createNetwork();
+//
+//    @Override
+//    abstract public boolean createNetwork(int channel, String PID);
+//
+//    @Override
+//    abstract public boolean createNetwork(int channel, String PID, String linkKey);
+//
+//    @Override
+//    abstract public boolean joinNetwork();
+//
+//    @Override
+//    abstract public boolean joinNetwork(String PID);
+//
+//    @Override
+//    abstract public boolean joinNetwork(String PID, String linkKey);
+//
+//    @Override
+//    abstract public boolean leaveNetwork();
+//
+//    @Override
+//    abstract public boolean scanNetwork();
+//
+//    @Override
+//    abstract public boolean leaveNetwork(ZigbeeNode node);
+    //
+    // <editor-fold defaultstate="collapsed" desc="REGISTRO DE NODOS">    
+    private HashMap<String, ZigbeeNode> nodes = new HashMap<String, ZigbeeNode>();
+    private HashMap<String, String> networkAddresses = new HashMap<String, String>();
+
+    @Override
+    public ZigbeeNode getNode(String address) {
+        logger.trace("Driver::getNode(address=" + address + ")");
+
+        // comprobamos dirección
+        if (address == null) {
+            return null;
+        }
+        // limpiamos posibles caracteres no deseados
+        String addr = address.toUpperCase().replaceAll("[^0123456789ABCDEF]", "");
+
+        // comprobamos si se trata de la dirección MAC o la dirección de red
+        String MACAddr;
+        if (addr.length() == 4) {
+            MACAddr = networkAddresses.get(addr);
+        } else {
+            MACAddr = addr;
+        }
+
+        // recuperamos el nodo por la dirección MAC
+        ZigbeeNode node = nodes.get(MACAddr);
+        return node;
+
+    }
+
+    /**
+     * Actualiza la dirección de red de un nodo
+     * @param EUI64Addr Dirección MAC del nodo
+     * @param newNodeID Nueva dirección de red
+     */
+    protected void updateNetworkAddress(ZigbeeNode node, String newNodeID) {
+        logger.trace("Driver::updateNetworkAddress(node=" + node + ", newNodeID=" + newNodeID + ")");
+
+        // comprobamos si el nodo tenía NodeID, y la eliminamos
+        NetworkAddress oldNodeID = node.getNodeID();
+        if (oldNodeID != null) {
+            networkAddresses.remove(oldNodeID.toString());
+        }
+
+        // añadimos la nueva dirección
+        networkAddresses.put(newNodeID, node.getEUI64Addr().toString());
+
+        // actualizamos la dirección del nodo
+        ((ZigbeeNodeImpl) node).setNodeID(new NetworkAddress(newNodeID));
+
+    }
+
+    @Override
+    public ZigbeeNode[] getNodes() {
+        logger.trace("Driver::getNodes()");
+        return nodes.values().toArray(new ZigbeeNode[0]);
+    }
+
+    @Override
+    public ZigbeeNode getNetworkCoordinator() {
+        logger.trace("Driver::getCoordinator()");
+        return coordinator;
+    }
+
+    /**
+     * Recupera el nodo conectado al gateway
+     * @return ZigbeeNode
+     */
+    @Override
+    public ZigbeeNode getDongle() {
+        logger.trace("Driver::getDongle()");
+        return dongle;
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param address direccion del nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(EUI64Address address) {
+        logger.trace("Driver::createNode(address=" + address + ")");
+        // Creamos un nodo con dirección de red y tipo desconocidos
+        return createNode(address, null, ZigbeeNodeType.Unknown);
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param nodeID direccion de red del nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(NetworkAddress nodeID) {
+        logger.trace("Driver::createNode(nodeID=" + nodeID + ")");
+        // Creamos un nodo con dirección y tipo desconocidos
+        return createNode(null, nodeID, ZigbeeNodeType.Unknown);
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param address direccion del nodo
+     * @param nodeID direccion de red del nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(EUI64Address address, NetworkAddress nodeID) {
+        logger.trace("Driver::createNode(address=" + address + ", nodeID=" + nodeID + ")");
+        // Creamos un nodo con tipo desconocido
+        return createNode(address, nodeID, ZigbeeNodeType.Unknown);
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param address direccion del nodo
+     * @param type tipo de nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(EUI64Address address, ZigbeeNodeType type) {
+        logger.trace("Driver::createNode(address=" + address + ", type=" + type + ")");
+        // Creamos un nodo con dirección de red desconocida
+        return createNode(address, null, type);
+
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param nodeID direccion del nodo
+     * @param type tipo de nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(NetworkAddress nodeID, ZigbeeNodeType type) {
+        logger.trace("Driver::createNode(nodeID=" + nodeID + ", type=" + type + ")");
+        // Creamos un nodo con dirección desconocida
+        return createNode(null, nodeID, type);
+    }
+
+    /**
+     * Crea un nodo y lanza los procesos de identificación asociados
+     * @param address direccion del nodo
+     * @param nodeID direccion de red del nodo
+     * @param type tipo de nodo
+     * @return Nodo creado
+     */
+    public ZigbeeNode createNode(EUI64Address address, NetworkAddress nodeID, ZigbeeNodeType type) {
+        logger.trace("Driver::createNode(address=" + address + ", nodeID=" + nodeID + ", type=" + type + ")");
+
+        // creamos el nodo
+        ZigbeeNode newNode = new ZigbeeNodeImpl(this);
+
+        // actualizamos parámetros
+        ((ZigbeeNodeImpl) newNode).setAddress(address);
+        ((ZigbeeNodeImpl) newNode).setNodeID(nodeID);
+        ((ZigbeeNodeImpl) newNode).setType(type);
+        ((ZigbeeNodeImpl) newNode).setStatus(ZigbeeNode.NodeStatus.Ready);
+
+        // Añadimos el nodo a la lista de nodos
+        if (newNode.getEUI64Addr() != null) {
+            nodes.put(newNode.getEUI64Addr().toString(), newNode);
+        }
+
+        // guardamos la dirección de red
+        if (nodeID != null) {
+            updateNetworkAddress(newNode, nodeID.toString());
+        }
+
+        logger.info("[ZigbeeDriver] Node created: " + newNode);
+
+        // notificamos de la creación del nodo
+        fireNewNode(newNode);
+
+        // devolvemos el nodo creado
+        return newNode;
+
+    }
+
+    /**
+     * elimina un nodo del driver
+     * @param node Nodo a eliminar
+     */
+    public void removeNode(ZigbeeNode node) {
+        logger.trace("Driver::removeNode(node=" + node + ")");
+
+        // comprobamos nodo null
+        if (node == null) {
+            logger.warn("[ZigbeeDriver] RemoveNode requested for null node");
+            return;
+        }
+
+
+        // comprobamos si el nodo tiene ZigbeeDevices, y notificamos que son eliminados
+        for (ZigbeeDevice device : node.getZigbeeDevices()) {
+            fireDeviceLeft(device);
+        }
+
+        // notificamos el nodo eliminado
+        fireNodeLeft(node);
+
+        // recuperamos al dirección
+        String EUI64Addr = node.getEUI64Addr().toString();
+
+        // eliminamos el nodo de la lista
+        nodes.remove(EUI64Addr);
+
+        logger.info("[ZigbeeDriver] Node removed: " + node);
+
+
+    }
+
+    /**
+     * Crea un device y lanza los procesos de identificación asociados
+     * @param node nodo que contiene al device
+     * @param endPoint Identificador del device
+     * @return Device creado
+     */
+    protected ZigbeeDevice createDevice(ZigbeeNode node, short endPoint) {
+        logger.trace("Driver::createDevice(node=" + node + ", endPoint=" + endPoint + ")");
+
+        // creamos el device
+        ZigbeeDevice newDevice = new ZigbeeDeviceImpl(this, node, endPoint);
+
+        // añadimos el device al nodo
+        ((ZigbeeNodeImpl) node).addZigbeeDevice(newDevice);
+
+        logger.info("[ZigbeeDriver] Device created: " + newDevice);
+
+        // notificamos de la creación del device
+        fireNewDevice(newDevice);
+
+        // devolvemos el device creado
+        return newDevice;
+
+    }
+
+    /**
+     * elimina un device del driver
+     * @param device Device a eliminar
+     */
+    public void removeDevice(ZigbeeDevice device) {
+        logger.trace("Driver::removeDevice(device=" + device + ")");
+
+        // comprobamos nodo null
+        if (device == null) {
+            logger.warn("[ZigbeeDriver] RemoveDevice requested for null device");
+            return;
+        }
+
+        // recuperamos el nodo
+        ZigbeeNodeImpl node = (ZigbeeNodeImpl) device.getZigbeeNode();
+
+        // eliminamos el device del nodo
+        node.removeZigbeeDevice(device);
+
+        // notificamos device eliminado
+        fireDeviceLeft(device);
+
+        logger.info("[ZigbeeDriver] Device removed: " + device);
+
+
+    }
+
+    // </editor-fold>
+//    @Override
+//    abstract public boolean sendMessage(ZigbeeNode node, byte[] message);
+//
+//    @Override
+//    abstract public boolean sendMessage(ZigbeeDevice device, String profileID, String clusterID, byte[] message);
+//
+//    @Override
+//    abstract public boolean sendBroadcastMessage(byte[] message);
+//
+//    @Override
+//    abstract public String readRegister(ZigbeeNode node, short regAddress);
+//
+//    @Override
+//    abstract public boolean writeRegister(ZigbeeNode node, short regAddress, String data);
+//
+//    @Override
+//    abstract public boolean updateActiveEndPoints(ZigbeeNode node);
+//
+//    @Override
+//    abstract public boolean updateEndPointDescriptor(ZigbeeDevice device);
+//
+//    @Override
+//    abstract public boolean updateNeighbourTable(ZigbeeNode node);
+//
+//    @Override
+//    abstract public boolean init();
+//
+//    @Override
+//    abstract public boolean start();
+//    @Override
+//    abstract public void disable();
+//
+//    @Override
+//    abstract public Gateway getGateway();
+//    
+    @Override
+    public DriverStatus getStatus() {
+        logger.trace("Driver::getStatus()");
+        return status;
+    }
+
+    /**
+     * Actualiza el status, y lanza la notificación correspondiente
+     * @param status 
+     */
+    protected void setStatus(DriverStatus status) {
+        // guardamos el estado anterior y lo actualizamos
+        DriverStatus oldStatus = this.status;
+        this.status = status;
+        // comprobamos para notificar cambio de estado       
+        if (oldStatus != status) {
+            fireStatusChanged(status, oldStatus);
+        }
+    }
+
+    /**
+     * Comprueba si está en un estado que permita ejecutar operaciones
+     */
+    protected boolean isEnabled() {
+        switch (status) {
+            case Unknown:
+            case Disabled:
+                return false;
+            default:
+                return true;
+        }
+    }
+        
+    //
+    // <editor-fold defaultstate="collapsed" desc="CONFIGURATION">
+    /*
+     * La configuración se almacena en un fichero XML, y se accede indicando una 
+     * clave raiz para el nodo a partir del cual está almacenada la 
+     * configuracion: 
+     * CONF_ROOT
+     */
+    private static final String CONF_ROOT = Driver.class.getPackage().getName().toLowerCase();
+    protected XMLConfiguration configuration = new XMLConfiguration(CONF_ROOT);
+    //private static final String CONF_FILENAME = Driver.class.getPackage().getName().toLowerCase() + ".xml";
+    private static final String CONF_FILENAME = CONF_ROOT + ".xml";
+    /*
+     * Nota: sobre los parámetros de configuración, se sigue la convención
+     * CONF_VARIABLE ==> define una variable de configuracion, con acceso protected o public
+     * CONV_VARIABLE_DEFAULT ==> define el valor por defecto de la variable (private)
+     * CONF_VARIABLE_KEY ==> define la clave de la variable (public static final String)
+     */
+    // Autostart del driver al crearlo
+    protected boolean CONF_AUTOSTART;
+    private static final boolean CONF_AUTOSTART_DEFAULT = false;
+    public static final String CONF_AUTOSTART_KEY = "autostart";
+    // Tiempos de espera
+    protected long CONF_ACK_TIMEOUT;
+    private static final long CONF_ACK_TIMEOUT_DEFAULT = 0x0BB8; // MAC TIMEOUT
+    public static final String CONF_ACK_TIMEOUT_KEY = "ack_timeout";
+    protected long CONF_REGISTER_READ_TIMEOUT;
+    private static final long CONF_REGISTER_READ_TIMEOUT_DEFAULT = 0x0BB8; // MAC TIMEOUT
+    public static final String CONF_REGISTER_READ_TIMEOUT_KEY = "register_read_timeout";
+    protected long CONF_REGISTER_WRITE_TIMEOUT;
+    private static final long CONF_REGISTER_WRITE_TIMEOUT_DEFAULT = 0x0BB8; // MAC TIMEOUT
+    public static final String CONF_REGISTER_WRITE_TIMEOUT_KEY = "register_write_timeout";
+    protected long CONF_ZDO_RESPONSE_TIMEOUT;
+    private static final long CONF_ZDO_RESPONSE_TIMEOUT_DEFAULT = 0x0BB8; // MAC TIMEOUT
+    public static final String CONF_ZDO_RESPONSE_TIMEOUT_KEY = "zdo_response_timeout";
+    protected long CONF_NEIGHBOUR_RESPONSE_TIMEOUT;
+    private static final long CONF_NEIGHBOUR_RESPONSE_TIMEOUT_DEFAULT = 0x0BB8; // MAC TIMEOUT
+    public static final String CONF_NEIGHBOUR_RESPONSE_TIMEOUT_KEY = "neighbour_response_timeout";
+    // Register Password
+    protected String CONF_S_REG_PASSWORD;
+    private static final String CONF_S_REG_PASSWORD_DEFAULT = "password";
+    public static final String CONF_S_REG_PASSWORD_KEY = "s_register_password";
+    // endpoint origen para mensajes enviados a endpoints
+    protected String CONF_S_REG_XCAST_SOURCE_EP;
+    private static final String CONF_S_REG_XCAST_SOURCE_EP_DEFAULT = "02";
+    public static final String CONF_S_REG_XCAST_SOURCE_EP_KEY = "s_reg_xcast_source_ep";
+    /*
+     * PARAMETROS DE CONFIGURACION DE TAREAS DE MANTENIMIENTO
+     * Los parámetros de configuracion de las tareas son en general:
+     * - Tarea activa o no (boolean)
+     * - Periodo de mantenimiento de la tarea (long, en minutos)
+     * - Periodo de reintento para tareas fallidas (long, en minutos)
+     * - Periodo de separacion entre nodos/devices (long, en segundos)
+     * - otros parámetros de la tarea
+     */
+    // recuperar Neighbours
+    protected boolean CONF_GET_NEIGHBOURS;
+    private static final boolean CONF_GET_NEIGHBOURS_DEFAULT = true;
+    public static final String CONF_GET_NEIGHBOURS_KEY = "get_neighbours";
+    protected long CONF_GET_NEIGHBOURS_FRAME_DELAY;
+    private static final long CONF_GET_NEIGHBOURS_FRAME_DELAY_DEFAULT = 10;
+    public static final String CONF_GET_NEIGHBOURS_FRAME_DELAY_KEY = "get_neighbours_frame_delay";
+    protected long CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD;
+    private static final long CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_DEFAULT = 60;
+    public static final String CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_KEY = "get_neighbours_maintenance_period";
+    protected long CONF_GET_NEIGHBOURS_RECOVERY_PERIOD;
+    private static final long CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_DEFAULT = 5;
+    public static final String CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_KEY = "get_neighbours_recovery_period";
+    // recuperar padre 
+    protected boolean CONF_GET_PARENT;
+    private static final boolean CONF_GET_PARENT_DEFAULT = true;
+    public static final String CONF_GET_PARENT_KEY = "get_parent";
+    protected long CONF_GET_PARENT_FRAME_DELAY;
+    private static final long CONF_GET_PARENT_FRAME_DELAY_DEFAULT = 10;
+    public static final String CONF_GET_PARENT_FRAME_DELAY_KEY = "get_parent_frame_delay";
+    protected long CONF_GET_PARENT_MAINTENANCE_PERIOD;
+    private static final long CONF_GET_PARENT_MAINTENANCE_PERIOD_DEFAULT = 60;
+    public static final String CONF_GET_PARENT_MAINTENANCE_PERIOD_KEY = "get_parent_maintenance_period";
+    protected long CONF_GET_PARENT_RECOVERY_PERIOD;
+    private static final long CONF_GET_PARENT_RECOVERY_PERIOD_DEFAULT = 5;
+    public static final String CONF_GET_PARENT_RECOVERY_PERIOD_KEY = "get_parent_recovery_period";
+    // recuperar ZigbeeDevices
+    protected boolean CONF_GET_ZIGBEE_DEVICES;
+    private static final boolean CONF_GET_ZIGBEE_DEVICES_DEFAULT = true;
+    public static final String CONF_GET_ZIGBEE_DEVICES_KEY = "get_zigbee_devices";
+    protected long CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY;
+    private static final long CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_DEFAULT = 60;
+    public static final String CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_KEY = "get_zigbee_devices_frame_delay";
+    protected long CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD;
+    private static final long CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_DEFAULT = 5;
+    public static final String CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_KEY = "get_zigbee_devices_recovery_period";
+    // Control de error en dispositivos
+    protected boolean CONF_CHECK_ZIGBEE_ERROR;
+    private static final boolean CONF_CHECK_ZIGBEE_ERROR_DEFAULT = true;
+    public static final String CONF_CHECK_ZIGBEE_ERROR_KEY = "check_zigbee_error";
+    protected long CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY;
+    private static final long CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_DEFAULT = 10;
+    public static final String CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_KEY = "check_zigbee_error_frame_delay";
+    protected long CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD;
+    private static final long CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_DEFAULT = 5;
+    public static final String CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_KEY = "check_zigbee_error_maintenance_period";
+    protected long CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD;
+    private static final long CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_DEFAULT = 1;
+    public static final String CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_KEY = "check_zigbee_error_recovery_period";
+    // Umbrales de error para gestion de dispositivos
+    public long CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1;
+    private static final long CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_DEFAULT = 2;
+    public static final String CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_KEY = "zigbee_error_level_threshold_1";
+    public long CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2;
+    private static final long CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_DEFAULT = 3;
+    public static final String CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_KEY = "zigbee_error_level_threshold_2";
+    // actualizar la configuracion del dongle al conectarlo
+    protected boolean CONF_UPDATE_DONGLE_S_REGISTERS;
+    private static final boolean CONF_UPDATE_DONGLE_S_REGISTERS_DEFAULT = false;
+    public static final String CONF_UPDATE_DONGLE_S_REGISTERS_KEY = "update_dongle_s_registers";
+    // actualizar la configuracion de los nodos al detectarlos
+    protected boolean CONF_UPDATE_NODE_S_REGISTERS;
+    private static final boolean CONF_UPDATE_NODE_S_REGISTERS_DEFAULT = false;
+    public static final String CONF_UPDATE_NODE_S_REGISTERS_KEY = "update_node_s_registers";
+    protected long CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY;
+    private static final long CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_DEFAULT = 10;
+    public static final String CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_KEY = "update_node_s_registers_frame_delay";
+    protected long CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD;
+    private static final long CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_DEFAULT = 5;
+    public static final String CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_KEY = "update_node_s_registers_recovery_period";
+    // registros a escribir en los nodos
+    private HashMap<String, HashMap<String, String>> CONF_NODE_REGISTERS;
+    private static final String CONF_DONGLE_S_REGISTER_ADDR_ID = "dongle";
+    private static final String CONF_NODE_REGISTERS_KEY = "node_registers";
+    private static final String CONF_NODE_ADDRESS_KEY = "address";
+    private static final String CONF_S_REGISTERS_KEY = "s_registers";
+    private static final String CONF_S_REGISTER_KEY = "s_register";
+    private static final String CONF_NODE_S_REGISTERS_ADDR_KEY = "address";
+    private static final String CONF_NODE_S_REGISTERS_VALUE_KEY = "value";
+    // configuracion fija
+    protected static final int GATEWAY_INITIALIZATION_LOCK_TIME = 60000;
+
+    public void loadConfiguration() {
+        logger.trace("Driver::loadConfiguration()");
+
+        // cargamos la configuracion
+        loadConfiguration(CONF_FILENAME);
+    }
+
+    /**
+     * Carga la configuracion desde el fichero indicado
+     * @param file
+     */
+    public void loadConfiguration(String file) {
+        logger.trace(String.format("Driver::loadConfiguration(file=%s)", file));
+
+        // cargamos la configuracion
+        logger.info(String.format("[ZigbeeDriver] Loading configuration from %s", file));
+        if (!configuration.load(file)) {
+            logger.warn(String.format("[ZigbeeDriver] Error loading configuration from %s. Using defaults", file));
+            // generamos configuracion por defecto
+            saveDefaultConfiguration(file);
+        }
+
+        // establecemos la configuracion
+        CONF_AUTOSTART = configuration.getBoolean(CONF_AUTOSTART_KEY, CONF_AUTOSTART_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_AUTOSTART=%s", CONF_AUTOSTART));
+
+        CONF_ACK_TIMEOUT = configuration.getLong(CONF_ACK_TIMEOUT_KEY, CONF_ACK_TIMEOUT_DEFAULT);
+        CONF_REGISTER_READ_TIMEOUT = configuration.getLong(CONF_REGISTER_READ_TIMEOUT_KEY, CONF_REGISTER_READ_TIMEOUT_DEFAULT);
+        CONF_REGISTER_WRITE_TIMEOUT = configuration.getLong(CONF_REGISTER_WRITE_TIMEOUT_KEY, CONF_REGISTER_WRITE_TIMEOUT_DEFAULT);
+        CONF_ZDO_RESPONSE_TIMEOUT = configuration.getLong(CONF_ZDO_RESPONSE_TIMEOUT_KEY, CONF_ZDO_RESPONSE_TIMEOUT_DEFAULT);
+        CONF_NEIGHBOUR_RESPONSE_TIMEOUT = configuration.getLong(CONF_NEIGHBOUR_RESPONSE_TIMEOUT_KEY, CONF_NEIGHBOUR_RESPONSE_TIMEOUT_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_ACK_TIMEOUT=%d milisegundos", CONF_ACK_TIMEOUT));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_REGISTER_READ_TIMEOUT=%d milisegundos", CONF_REGISTER_READ_TIMEOUT));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_REGISTER_WRITE_TIMEOUT=%d milisegundos", CONF_REGISTER_WRITE_TIMEOUT));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_ZDO_RESPONSE_TIMEOUT=%d milisegundos", CONF_ZDO_RESPONSE_TIMEOUT));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_NEIGHBOUR_RESPONSE_TIMEOUT=%d milisegundos", CONF_NEIGHBOUR_RESPONSE_TIMEOUT));
+
+        CONF_S_REG_PASSWORD = configuration.getString(CONF_S_REG_PASSWORD_KEY, CONF_S_REG_PASSWORD_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_S_REG_PASSWORD=%s", CONF_S_REG_PASSWORD));
+
+        CONF_S_REG_XCAST_SOURCE_EP = configuration.getString(CONF_S_REG_XCAST_SOURCE_EP_KEY, CONF_S_REG_XCAST_SOURCE_EP_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_S_REG_XCAST_SOURCE_EP=%s", CONF_S_REG_XCAST_SOURCE_EP));
+
+        CONF_CHECK_ZIGBEE_ERROR = configuration.getBoolean(CONF_CHECK_ZIGBEE_ERROR_KEY, CONF_CHECK_ZIGBEE_ERROR_DEFAULT);
+        CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY = configuration.getLong(CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_KEY, CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_DEFAULT);
+        CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD = configuration.getLong(CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_DEFAULT);
+        CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD = configuration.getLong(CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_DEFAULT);
+        CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1 = configuration.getLong(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_DEFAULT);
+        CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2 = configuration.getLong(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_CHECK_ZIGBEE_ERROR=%s", CONF_CHECK_ZIGBEE_ERROR));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY=%d segundos", CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD=%d minutos", CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD=%d minutos", CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1=%d errores", CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2=%d errores", CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2));
+
+        CONF_GET_NEIGHBOURS = configuration.getBoolean(CONF_GET_NEIGHBOURS_KEY, CONF_GET_NEIGHBOURS_DEFAULT);
+        CONF_GET_NEIGHBOURS_FRAME_DELAY = configuration.getLong(CONF_GET_NEIGHBOURS_FRAME_DELAY_KEY, CONF_GET_NEIGHBOURS_FRAME_DELAY_DEFAULT);
+        CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD = configuration.getLong(CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_KEY, CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_DEFAULT);
+        CONF_GET_NEIGHBOURS_RECOVERY_PERIOD = configuration.getLong(CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_KEY, CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_NEIGHBOURS=%s", CONF_GET_NEIGHBOURS));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_NEIGHBOURS_FRAME_DELAY=%d segundos", CONF_GET_NEIGHBOURS_FRAME_DELAY));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD=%d minutos", CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_NEIGHBOURS_RECOVERY_PERIOD=%d minutos", CONF_GET_NEIGHBOURS_RECOVERY_PERIOD));
+
+        CONF_GET_PARENT = configuration.getBoolean(CONF_GET_PARENT_KEY, CONF_GET_PARENT_DEFAULT);
+        CONF_GET_PARENT_FRAME_DELAY = configuration.getLong(CONF_GET_PARENT_FRAME_DELAY_KEY, CONF_GET_PARENT_FRAME_DELAY_DEFAULT);
+        CONF_GET_PARENT_MAINTENANCE_PERIOD = configuration.getLong(CONF_GET_PARENT_MAINTENANCE_PERIOD_KEY, CONF_GET_PARENT_MAINTENANCE_PERIOD_DEFAULT);
+        CONF_GET_PARENT_RECOVERY_PERIOD = configuration.getLong(CONF_GET_PARENT_RECOVERY_PERIOD_KEY, CONF_GET_PARENT_RECOVERY_PERIOD_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_PARENT=%s", CONF_GET_PARENT));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_PARENT_FRAME_DELAY=%d segundos", CONF_GET_PARENT_FRAME_DELAY));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_PARENT_MAINTENANCE_PERIOD=%d minutos", CONF_GET_PARENT_MAINTENANCE_PERIOD));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_PARENT_RECOVERY_PERIOD=%d minutos", CONF_GET_PARENT_RECOVERY_PERIOD));
+
+        CONF_GET_ZIGBEE_DEVICES = configuration.getBoolean(CONF_GET_ZIGBEE_DEVICES_KEY, CONF_GET_ZIGBEE_DEVICES_DEFAULT);
+        CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY = configuration.getLong(CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_KEY, CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_DEFAULT);
+        CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD = configuration.getLong(CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_KEY, CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_ZIGBEE_DEVICES=%s", CONF_GET_ZIGBEE_DEVICES));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY=%d segundos", CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD=%d minutos", CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD));
+
+        CONF_UPDATE_DONGLE_S_REGISTERS = configuration.getBoolean(CONF_UPDATE_DONGLE_S_REGISTERS_KEY, CONF_UPDATE_DONGLE_S_REGISTERS_DEFAULT);
+        CONF_UPDATE_NODE_S_REGISTERS = configuration.getBoolean(CONF_UPDATE_NODE_S_REGISTERS_KEY, CONF_UPDATE_NODE_S_REGISTERS_DEFAULT);
+        CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY = configuration.getLong(CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_KEY, CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_DEFAULT);
+        CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD = configuration.getLong(CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_KEY, CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_DEFAULT);
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_UPDATE_DONGLE_S_REGISTERS=%s", CONF_UPDATE_DONGLE_S_REGISTERS));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_UPDATE_NODE_S_REGISTERS=%s", CONF_UPDATE_NODE_S_REGISTERS));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY=%d segundos", CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY));
+        logger.debug(String.format("[ZigbeeDriver] Configuration: CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD=%d minutos", CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD));
+
+        CONF_NODE_REGISTERS = loadNodeRegisterConfig(configuration);
+
+    }
+
+    /**
+     * Guarda la configuracion actual en un archivo
+     * @return True si guarda la configuración, false en otro caso
+     */
+    public boolean saveCurrentConfiguration() {
+        logger.trace(String.format("Driver::saveCurrentConfiguration()"));
+
+        // recuperamos la configuracion actual
+        Dictionary properties = getCurrentConfiguration();
+
+        // la guardamos
+        return saveConfiguration(CONF_FILENAME, properties);
+
+    }
+
+    /**
+     * Guarda la configuracion actual en un archivo
+     * @param file nombre del archivo
+     * @return True si guarda la configuración, false en otro caso
+     */
+    public boolean saveCurrentConfiguration(String file) {
+        logger.trace(String.format("Driver::saveCurrentConfiguration(file=%s)", file));
+
+        // recuperamos la configuracion actual
+        Dictionary properties = getCurrentConfiguration();
+
+        // la guardamos
+        return saveConfiguration(file, properties);
+
+    }
+
+    /**
+     * Guarda la configuracion por defecto en un archivo
+     * @param file nombre del archivo
+     * @return True si guarda la configuración, false en otro caso
+     */
+    public boolean saveDefaultConfiguration(String file) {
+        logger.trace(String.format("Driver::saveDefaultConfiguration(file=%s)", file));
+
+        // recuperamos la configuración por defecto
+        Dictionary properties = getDefaultConfiguration();
+
+        // la guardamos
+        return saveConfiguration(file, properties);
+
+    }
+
+    /**
+     * Guarda la configuracion proporcionada en un archivo
+     * @param file Nombre del archivo
+     * @param properties Propiedades a guardar
+     * @return True si guarda la configuracion, false en otro caso
+     */
+    public boolean saveConfiguration(String file, Dictionary properties) {
+        logger.trace(String.format("Driver::saveConfiguration(file=%s, properties=%s)", file, properties));
+
+        logger.info(String.format("[ZigbeeDriver] Saving driver configuration to file %s", file));
+
+        // creamos una configuracion auxiliar
+        XMLConfiguration saveConf = new XMLConfiguration(CONF_ROOT);
+
+        // añadimos las propiedades
+        Enumeration keys = properties.keys();
+        while (keys.hasMoreElements()) {
+            String key = (String) keys.nextElement();
+            Object value = properties.get(key);
+            saveConf.addProperty(key, value.toString());
+        }
+
+        // guardamos el fichero
+        return saveConf.save(file);
+
+    }
+
+    /**
+     * Devuelve la configuración a aplicar a los registros del dongle
+     * @return HashMap con la lista de registros a escribir en el dongle
+     */
+    public HashMap<String, String> getDongleRegisterConfig() {
+        logger.trace("Driver::getDongleRegisterConfig()");
+
+        return CONF_NODE_REGISTERS.get(CONF_DONGLE_S_REGISTER_ADDR_ID);
+
+    }
+
+    /**
+     * Devuelve la configuración a aplicar a los registros de un nodo determinado
+     * @param EUI64Addr direccion del nodo
+     * @return HashMap con la lista de registros a escribir en el dongle
+     */
+    public HashMap<String, String> getNodeRegisterConfig(String EUI64Addr) {
+        logger.trace(String.format("Driver::getNodeRegisterConfig(EUI64Addr=%s)", EUI64Addr));
+
+        return CONF_NODE_REGISTERS.get(EUI64Addr);
+
+    }
+
+    /**
+     * Recupera la configuración a aplicar a los registros de los nodos
+     * @param conf configuración
+     * @return HashMap con la lista de registros a escribir en cada nodo
+     */
+    private HashMap<String, HashMap<String, String>> loadNodeRegisterConfig(XMLConfiguration conf) {
+        logger.trace(String.format("Driver::loadNodeRegisterConfig(conf=%s)", conf));
+
+        // Creamos el resultado
+        HashMap<String, HashMap<String, String>> registers = new HashMap<String, HashMap<String, String>>();
+
+        // recuperamos las configuraciones de los nodos
+        ArrayList<XMLConfiguration> nodeAddrList = conf.getConfigs(CONF_NODE_REGISTERS_KEY);
+
+        // Recuperamos los registros de cada nodo
+        for (int i = 0; i < nodeAddrList.size(); i++) {
+            // recuperamos la configuracion correspondiente al nodo
+            XMLConfiguration nodeConf = nodeAddrList.get(i);
+
+            String nodeAddr = nodeConf.getString(CONF_NODE_ADDRESS_KEY, null);
+            if (nodeAddr != null) { // por si hubiera algún error...
+                HashMap<String, String> registersNode = new HashMap<String, String>();
+                // recuperamos la configuracion de registros
+                XMLConfiguration regConf = nodeConf.getConfig(CONF_S_REGISTERS_KEY);
+
+                // recuperamos las direcciones y valores
+                List regAddrList = regConf.getList(CONF_NODE_S_REGISTERS_ADDR_KEY);
+                List regValueList = regConf.getList(CONF_NODE_S_REGISTERS_VALUE_KEY);
+                // componemos el resultado
+                for (int j = 0; j < regAddrList.size(); j++) {
+                    String regAddr = (String) regAddrList.get(j);
+                    String regValue = (String) regValueList.get(j);
+                    registersNode.put(regAddr, regValue);
+                }
+                registers.put(nodeAddr, registersNode);
+                logger.debug(String.format("[ZigbeeDriver] Configuration: S_Registers Node %s = %s", nodeAddr, registersNode));
+
+            }
+
+        }
+
+        // devolvemos el resultado
+        return registers;
+
+
+    }
+
+    @Override
+    public void updated(Dictionary properties) {
+        logger.trace(String.format("Driver::updated(properties=%s)", properties));
+
+        // recorremos la configuracion
+        Enumeration keys = properties.keys();
+        while (keys.hasMoreElements()) {
+            Object key = keys.nextElement();
+            if (CONF_AUTOSTART_KEY.equals((String) key)) {
+                CONF_AUTOSTART = (Boolean) properties.get(key);
+
+            } else if (CONF_ACK_TIMEOUT_KEY.equals((String) key)) {
+                CONF_ACK_TIMEOUT = (Long) properties.get(key);
+            } else if (CONF_REGISTER_READ_TIMEOUT_KEY.equals((String) key)) {
+                CONF_REGISTER_READ_TIMEOUT = (Long) properties.get(key);
+            } else if (CONF_REGISTER_WRITE_TIMEOUT_KEY.equals((String) key)) {
+                CONF_REGISTER_WRITE_TIMEOUT = (Long) properties.get(key);
+            } else if (CONF_ZDO_RESPONSE_TIMEOUT_KEY.equals((String) key)) {
+                CONF_ZDO_RESPONSE_TIMEOUT = (Long) properties.get(key);
+            } else if (CONF_NEIGHBOUR_RESPONSE_TIMEOUT_KEY.equals((String) key)) {
+                CONF_NEIGHBOUR_RESPONSE_TIMEOUT = (Long) properties.get(key);
+
+            } else if (CONF_S_REG_PASSWORD_KEY.equals((String) key)) {
+                CONF_S_REG_PASSWORD = (String) properties.get(key);
+            } else if (CONF_S_REG_XCAST_SOURCE_EP_KEY.equals((String) key)) {
+                CONF_S_REG_XCAST_SOURCE_EP = (String) properties.get(key);
+
+            } else if (CONF_CHECK_ZIGBEE_ERROR_KEY.equals((String) key)) {
+                CONF_CHECK_ZIGBEE_ERROR = (Boolean) properties.get(key);
+            } else if (CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_KEY.equals((String) key)) {
+                CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY = (Long) properties.get(key);
+            } else if (CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_KEY.equals((String) key)) {
+                CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD = (Long) properties.get(key);
+            } else if (CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_KEY.equals((String) key)) {
+                CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD = (Long) properties.get(key);
+            } else if (CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_KEY.equals((String) key)) {
+                CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1 = (Long) properties.get(key);
+            } else if (CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_KEY.equals((String) key)) {
+                CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2 = (Long) properties.get(key);
+
+            } else if (CONF_GET_NEIGHBOURS_KEY.equals((String) key)) {
+                CONF_GET_NEIGHBOURS = (Boolean) properties.get(key);
+            } else if (CONF_GET_NEIGHBOURS_FRAME_DELAY_KEY.equals((String) key)) {
+                CONF_GET_NEIGHBOURS_FRAME_DELAY = (Long) properties.get(key);
+            } else if (CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_KEY.equals((String) key)) {
+                CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD = (Long) properties.get(key);
+            } else if (CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_KEY.equals((String) key)) {
+                CONF_GET_NEIGHBOURS_RECOVERY_PERIOD = (Long) properties.get(key);
+
+            } else if (CONF_GET_PARENT_KEY.equals((String) key)) {
+                CONF_GET_PARENT = (Boolean) properties.get(key);
+            } else if (CONF_GET_PARENT_FRAME_DELAY_KEY.equals((String) key)) {
+                CONF_GET_PARENT_FRAME_DELAY = (Long) properties.get(key);
+            } else if (CONF_GET_PARENT_MAINTENANCE_PERIOD_KEY.equals((String) key)) {
+                CONF_GET_PARENT_MAINTENANCE_PERIOD = (Long) properties.get(key);
+            } else if (CONF_GET_PARENT_RECOVERY_PERIOD_KEY.equals((String) key)) {
+                CONF_GET_PARENT_RECOVERY_PERIOD = (Long) properties.get(key);
+
+            } else if (CONF_GET_ZIGBEE_DEVICES_KEY.equals((String) key)) {
+                CONF_GET_ZIGBEE_DEVICES = (Boolean) properties.get(key);
+            } else if (CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_KEY.equals((String) key)) {
+                CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY = (Long) properties.get(key);
+            } else if (CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_KEY.equals((String) key)) {
+                CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD = (Long) properties.get(key);
+
+            } else if (CONF_UPDATE_DONGLE_S_REGISTERS_KEY.equals((String) key)) {
+                CONF_UPDATE_DONGLE_S_REGISTERS = (Boolean) properties.get(key);
+            } else if (CONF_UPDATE_NODE_S_REGISTERS_KEY.equals((String) key)) {
+                CONF_UPDATE_NODE_S_REGISTERS = (Boolean) properties.get(key);
+            } else if (CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_KEY.equals((String) key)) {
+                CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY = (Long) properties.get(key);
+            } else if (CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_KEY.equals((String) key)) {
+                CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD = (Long) properties.get(key);
+            }
+
+        }
+        
+        logger.info("[ZigbeeDriver] Configuration updated");
+    }
+
+    public Dictionary getCurrentConfiguration() {
+        logger.trace(String.format("Driver::getCurrentConfiguration()"));
+        Dictionary conf = new Hashtable<String, Object>();
+
+        conf.put(CONF_AUTOSTART_KEY, CONF_AUTOSTART);
+
+        conf.put(CONF_ACK_TIMEOUT_KEY, CONF_ACK_TIMEOUT);
+        conf.put(CONF_REGISTER_READ_TIMEOUT_KEY, CONF_REGISTER_READ_TIMEOUT);
+        conf.put(CONF_REGISTER_WRITE_TIMEOUT_KEY, CONF_REGISTER_WRITE_TIMEOUT);
+        conf.put(CONF_ZDO_RESPONSE_TIMEOUT_KEY, CONF_ZDO_RESPONSE_TIMEOUT);
+        conf.put(CONF_NEIGHBOUR_RESPONSE_TIMEOUT_KEY, CONF_NEIGHBOUR_RESPONSE_TIMEOUT);
+
+        conf.put(CONF_S_REG_PASSWORD_KEY, CONF_S_REG_PASSWORD);
+        conf.put(CONF_S_REG_XCAST_SOURCE_EP_KEY, CONF_S_REG_XCAST_SOURCE_EP);
+
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_KEY, CONF_CHECK_ZIGBEE_ERROR);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_KEY, CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD);
+        conf.put(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1);
+        conf.put(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2);
+
+        conf.put(CONF_GET_NEIGHBOURS_KEY, CONF_GET_NEIGHBOURS);
+        conf.put(CONF_GET_NEIGHBOURS_FRAME_DELAY_KEY, CONF_GET_NEIGHBOURS_FRAME_DELAY);
+        conf.put(CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_KEY, CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD);
+        conf.put(CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_KEY, CONF_GET_NEIGHBOURS_RECOVERY_PERIOD);
+
+        conf.put(CONF_GET_PARENT_KEY, CONF_GET_PARENT);
+        conf.put(CONF_GET_PARENT_FRAME_DELAY_KEY, CONF_GET_PARENT_FRAME_DELAY);
+        conf.put(CONF_GET_PARENT_MAINTENANCE_PERIOD_KEY, CONF_GET_PARENT_MAINTENANCE_PERIOD);
+        conf.put(CONF_GET_PARENT_RECOVERY_PERIOD_KEY, CONF_GET_PARENT_RECOVERY_PERIOD);
+
+        conf.put(CONF_GET_ZIGBEE_DEVICES_KEY, CONF_GET_ZIGBEE_DEVICES);
+        conf.put(CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_KEY, CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY);
+        conf.put(CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_KEY, CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD);
+
+        conf.put(CONF_UPDATE_DONGLE_S_REGISTERS_KEY, CONF_UPDATE_DONGLE_S_REGISTERS);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_KEY, CONF_UPDATE_NODE_S_REGISTERS);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_KEY, CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_KEY, CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD);
+
+        return conf;
+
+    }
+
+    public Dictionary getDefaultConfiguration() {
+        logger.trace(String.format("Driver::getDefaultConfiguration()"));
+        Dictionary conf = new Hashtable<String, Object>();
+
+        conf.put(CONF_AUTOSTART_KEY, CONF_AUTOSTART_DEFAULT);
+
+        conf.put(CONF_ACK_TIMEOUT_KEY, CONF_ACK_TIMEOUT_DEFAULT);
+        conf.put(CONF_REGISTER_READ_TIMEOUT_KEY, CONF_REGISTER_READ_TIMEOUT_DEFAULT);
+        conf.put(CONF_REGISTER_WRITE_TIMEOUT_KEY, CONF_REGISTER_WRITE_TIMEOUT_DEFAULT);
+        conf.put(CONF_ZDO_RESPONSE_TIMEOUT_KEY, CONF_ZDO_RESPONSE_TIMEOUT_DEFAULT);
+        conf.put(CONF_NEIGHBOUR_RESPONSE_TIMEOUT_KEY, CONF_NEIGHBOUR_RESPONSE_TIMEOUT_DEFAULT);
+
+        conf.put(CONF_S_REG_PASSWORD_KEY, CONF_S_REG_PASSWORD_DEFAULT);
+        conf.put(CONF_S_REG_XCAST_SOURCE_EP_KEY, CONF_S_REG_XCAST_SOURCE_EP_DEFAULT);
+
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_KEY, CONF_CHECK_ZIGBEE_ERROR_DEFAULT);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_KEY, CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY_DEFAULT);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD_DEFAULT);
+        conf.put(CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_KEY, CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD_DEFAULT);
+        conf.put(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1_DEFAULT);
+        conf.put(CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_KEY, CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2_DEFAULT);
+
+        conf.put(CONF_GET_NEIGHBOURS_KEY, CONF_GET_NEIGHBOURS_DEFAULT);
+        conf.put(CONF_GET_NEIGHBOURS_FRAME_DELAY_KEY, CONF_GET_NEIGHBOURS_FRAME_DELAY_DEFAULT);
+        conf.put(CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_KEY, CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD_DEFAULT);
+        conf.put(CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_KEY, CONF_GET_NEIGHBOURS_RECOVERY_PERIOD_DEFAULT);
+
+        conf.put(CONF_GET_PARENT_KEY, CONF_GET_PARENT_DEFAULT);
+        conf.put(CONF_GET_PARENT_FRAME_DELAY_KEY, CONF_GET_PARENT_FRAME_DELAY_DEFAULT);
+        conf.put(CONF_GET_PARENT_MAINTENANCE_PERIOD_KEY, CONF_GET_PARENT_MAINTENANCE_PERIOD_DEFAULT);
+        conf.put(CONF_GET_PARENT_RECOVERY_PERIOD_KEY, CONF_GET_PARENT_RECOVERY_PERIOD_DEFAULT);
+
+        conf.put(CONF_GET_ZIGBEE_DEVICES_KEY, CONF_GET_ZIGBEE_DEVICES_DEFAULT);
+        conf.put(CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_KEY, CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY_DEFAULT);
+        conf.put(CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_KEY, CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD_DEFAULT);
+
+        conf.put(CONF_UPDATE_DONGLE_S_REGISTERS_KEY, CONF_UPDATE_DONGLE_S_REGISTERS_DEFAULT);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_KEY, CONF_UPDATE_NODE_S_REGISTERS_DEFAULT);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_KEY, CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY_DEFAULT);
+        conf.put(CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_KEY, CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD_DEFAULT);
+
+        return conf;
+
+    }
+// </editor-fold>
+    //
+    // <editor-fold defaultstate="collapsed" desc="GESTION BLOQUEO">
+    private Locker locker = new Locker(this.getClass().getSimpleName());
+
+    @Override
+    public boolean tryLock(int milliseconds) {
+        logger.trace("Driver::tryLock(milliseconds=" + milliseconds + ")");
+        return locker.tryLock(milliseconds);
+
+    }
+
+    @Override
+    public void lock(int milliseconds) {
+        logger.trace("Driver::lock(milliseconds=" + milliseconds + ")");
+        locker.lock(milliseconds);
+
+    }
+
+    @Override
+    public boolean unlock() {
+        logger.trace("Driver::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">
+    final ArrayList<DriverListener> listeners = new ArrayList<DriverListener>();
+    final HashMap<DriverListener, Executor> executors = new HashMap<DriverListener, Executor>();
+
+    @Override
+    public void registerListener(DriverListener lstnr) {
+        synchronized (listeners) {
+            if (listeners.add(lstnr)) {
+                Executor ex = Executors.newSingleThreadExecutor();
+                executors.put(lstnr, ex);
+            }
+        }
+    }
+
+    @Override
+    public void unregisterListener(DriverListener lstnr) {
+        synchronized (listeners) {
+            if (listeners.remove(lstnr)) {
+                executors.remove(lstnr);
+            }
+        }
+    }
+
+    /**
+     * Notifies about new ZigbeeNode, 
+     * @param node Node discovered
+     */
+    protected void fireNewNode(final ZigbeeNode node) {
+        logger.trace("Driver::fireNewNode(node=" + node + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.newNode(node, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about new ZigbeeNode, 
+     * @param device Node discovered
+     */
+    protected void fireNewDevice(final ZigbeeDevice device) {
+        logger.trace("Driver::fireNewDevice(device=" + device + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.newDevice(device, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies for nodes leaving network (or disconnected)
+     * @param node Node leaving network
+     */
+    protected void fireNodeLeft(final ZigbeeNode node) {
+        logger.trace("Driver::fireNodeLeft(node=" + node + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.nodeLeft(node, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies for devices leaving network (or disconnected)
+     * @param device Device leaving network
+     */
+    protected void fireDeviceLeft(final ZigbeeDevice device) {
+        logger.trace("Driver::fireDeviceLeft(device=" + device + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.deviceLeft(device, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about joining network
+     * @param channel Network channel
+     * @param PANID Network PID
+     * @param EPID Network Extended PID
+     */
+    protected void fireJoinNetwork(final int channel, final String PANID, final String EPID) {
+        logger.trace("Driver::fireJoinNetwork(channel=" + channel + ", PANID=" + PANID + ", EPID=" + EPID + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.joinNetwork(channel, PANID, EPID, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about leaving network
+     */
+    public void fireLeftNetwork() {
+        logger.trace("Driver::fireLeftNetwork()");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.leftNetwork(drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+
+    }
+
+    /**
+     * Notifies about status changed on a Driver, 
+     * @param status current status
+     * @param oldStatus previous status
+     */
+    protected void fireStatusChanged(final DriverStatus status, final DriverStatus oldStatus) {
+        logger.trace("Driver::fireStatusChanged(status=" + status + ", oldStatus=" + oldStatus + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final Driver drv = this;
+            while (it.hasNext()) {
+                final DriverListener lstnr = (DriverListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.statusChanged(status, oldStatus, drv);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+    // </editor-fold>
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/Driver305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/Driver305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/Driver305.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,2109 @@
+/*
+ * 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.driver.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrACK;
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.AbstractDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.ErrorCheckerDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.NeighbourFinderDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.NodeRegisterUpdaterDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.ParentFinderDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.maintenance.ZigbeeDevicesFinderDriverMaintenanceTask;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrActiveEndPoints;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrEndPointDescriptor;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrNeighbourTableResponse;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrRegisterRead;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrRegisterWrited;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.GtwyLstnrSourceRoute;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.Register305;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.EUI64Address;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkAddress;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkInfo;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkScanInfo;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.ZigbeeNodeType;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.ZigbeeDeviceType;
+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.util.NeighbourTableEntry;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.NetworkInformation;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.NetworkJoinedInfo;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.util.PANScanResult;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class Driver305 extends AbstractDriver implements Driver, GatewayListener {
+
+    private final String SYNC_OPS = "SYNC"; // objeto referencia para exclusión mutua entre operaciones (synchronized(SYNC_COMMAND) { ... })
+    // flag para llevar control de mensaje enviado a endPoint (cambiada configuración de registros)
+    private boolean endPointMessageSent;
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    /**
+     * Driver constructor.
+     * Nota: antes de poder utilizarlo, hay que llamar a la función init(), que 
+     * establecera el registro del gateway
+     * @param gtwy Gateway conectado
+     */
+    public Driver305(Gateway gtwy) {
+        super(gtwy);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ZigbeeDriver on %s", gateway.getDongleAddress());
+    }
+    // <editor-fold defaultstate="collapsed" desc="NETWORK CONTROL">
+
+    @Override
+    public NetworkInfo readNetworkInfo() {
+        logger.trace("Driver305::readNetworkInfo()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return null;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            logger.info(String.format("[ZigbeeDriver] Retrieving network information from dongle"));
+            // consultamos al gateway la información de la red
+            NetworkInformation ni = gateway.getNetworkInformation();
+            if (ni != null) {
+                // adaptamos la respuesta al tipo de dato de retorno
+                NetworkInfo nwkI = new NetworkInfo(ni.getChannel(), ni.getPID(), ni.getEPID());
+
+                return nwkI;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public NetworkScanInfo[] findNetworks() {
+        logger.trace("Driver305::findNetworks()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return null;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            // consultamos al gateway la información de la red
+            PANScanResult[] psr;
+            try {
+                logger.info(String.format("[ZigbeeDriver] Performing find network"));
+                psr = gateway.scanForActivePANs();
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error find network. %s", ex.getErrorMessage()), ex);
+                return null;
+            }
+            if (psr == null) {
+                return null;
+            }
+            logger.info(String.format("[ZigbeeDriver] Network scan: found %d networks", psr.length));
+            // convertimos el resultado al tipo de retorno
+            NetworkScanInfo[] nsi = new NetworkScanInfo[psr.length];
+            for (int i = 0; i < psr.length; i++) {
+                PANScanResult psri = psr[i];
+                nsi[i] = new NetworkScanInfo(psri.getChannel(), psri.getPANID(), psri.getEPID(), psri.getProfile(), psri.getJoinPermission());
+            }
+
+            // devolvemos el resultado
+            return nsi;
+        }
+    }
+
+    @Override
+    public boolean createNetwork() {
+        logger.trace("Driver305::createNetwork()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot create network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            // solicitamos la creación de la red
+            try {
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to create network"));
+                NetworkJoinedInfo nji = gateway.createNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Created network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error create network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean createNetwork(String PID) {
+        logger.trace("Driver305::createNetwork(PID=" + PID + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot create network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // Limpiamos la link key
+                if (!clearLinkKey()){
+                    return false;
+                }                    
+                // Establecemos el preferred PANID
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // solicitamos la creación de la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to create network"));
+                NetworkJoinedInfo nji = gateway.createNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Created network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error create network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+
+        }
+    }
+
+    @Override
+    public boolean createNetwork(int channel, String PID) {
+        logger.trace("Driver305::createNetwork(channel=" + channel + ", PID=" + PID + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot create network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos canal
+        String strChannel = checkChannel(channel);
+        if (strChannel == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong channel provided: " + channel);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // Establecemos el preferred PANID
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // establecemos la máscara de canales
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing CHANNEL_MASK %s", strChannel));
+                gateway.writeRegister(Register305.CHANNEL_MASK.getAddress(), strChannel);
+                // Limpiamos la LinkKey 
+                if (!clearLinkKey()){
+                    return false;
+                }                    
+                // solicitamos la creación de la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to create network"));
+                NetworkJoinedInfo nji = gateway.createNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Created network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error create network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+
+        }
+    }
+
+    @Override
+    public boolean createNetwork(String PID, String linkKey) {
+        logger.trace("Driver305::createNetwork(PID=" + PID + ", linkKey=" + linkKey + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot create network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong PID provided: " + PID);
+            return false;
+        }
+        // comprobamos la clave proporcionada
+        String strLinkKey = checkLinkKey(linkKey);
+        if (strLinkKey == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong LinkKey provided: " + linkKey);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // establecemos la testLinkKey corregida
+                if (!setLinkKey(strLinkKey)){
+                    return false;
+                }                    
+                // solicitamos la creación de la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to create network"));
+                NetworkJoinedInfo nji = gateway.createNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Created network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error create network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean createNetwork(int channel, String PID, String linkKey) {
+        logger.trace("Driver305::createNetwork(channel=" + channel + ", PID=" + PID + ", linkKey=" + linkKey + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot create network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong PID provided: " + PID);
+            return false;
+        }
+        // comprobamos canal
+        String strChannel = checkChannel(channel);
+        if (strChannel == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong channel provided: " + channel);
+            return false;
+        }
+
+        // comprobamos la clave proporcionada
+        String strLinkKey = checkLinkKey(linkKey);
+        if (strLinkKey == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong LinkKey provided: " + linkKey);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // establecemos la máscara de canales
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing CHANNEL_MASK %s", strChannel));
+                gateway.writeRegister(Register305.CHANNEL_MASK.getAddress(), strChannel);
+                // establecemos la testLinkKey corregida
+                if (!setLinkKey(strLinkKey)){
+                    return false;
+                }                    
+                // solicitamos la creación de la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to create network"));
+                NetworkJoinedInfo nji = gateway.createNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Created network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error create network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Estalece la configuracion de LinkKey para el gateway, e indica que se usa
+     * @param linkKey Clave de red
+     * @return True si la establece, false en otro caso
+     */
+    private boolean setLinkKey(String linkKey) {
+        logger.trace("Driver305::setLinkKey(linkKey=" + linkKey + ")");
+
+        String donglePassword = ((ZigbeeNodeImpl) this.getDongle()).getRegisterPassword();
+        
+        try {
+            // establecemos la testLinkKey corregida
+            logger.debug(String.format("[ZigbeeDriver] Set LinkKey: writing TRUST_CENTRE_LINK_KEY %s", linkKey));
+            gateway.writeRegister(Register305.TRUST_CENTRE_LINK_KEY.getAddress(), linkKey, CONF_S_REG_PASSWORD);
+            
+            // indicamos que queremos utilizar la linkKey escribiendo el registro S0A
+            String regData = "001C"; // 0000 0000 0001 1100
+            logger.debug(String.format("[ZigbeeDriver] Set LinkKey: writing Main Functon %s", regData));
+            gateway.writeRegister(Register305.MAIN_FUNCTION.getAddress(), regData, CONF_S_REG_PASSWORD);
+        } catch (TelegesisErrorException ex) {
+            logger.warn(String.format("[ZigbeeDriver] Error stabilishing LinKey. %s", ex.getErrorMessage()), ex);
+            return false;
+        }
+
+        return true;
+
+
+    }
+
+    /**
+     * Borra la LinkKey para el gateway, e indica que se no usa
+     * @return True si la establece, false en otro caso
+     */
+    private boolean clearLinkKey() {
+        logger.trace("Driver305::clearLinkKey()");
+
+        String donglePassword = ((ZigbeeNodeImpl) this.getDongle()).getRegisterPassword();
+        String linkKey = "00000000000000000000000000000000";
+
+        try {
+            // establecemos la testLinkKey corregida
+            logger.debug(String.format("[ZigbeeDriver] Set LinkKey: clearing TRUST_CENTRE_LINK_KEY %s", linkKey));
+            gateway.writeRegister(Register305.TRUST_CENTRE_LINK_KEY.getAddress(), linkKey, CONF_S_REG_PASSWORD);
+            
+            // indicamos que NO queremos utilizar la linkKey escribiendo el registro S0A
+            String regData = "0000"; // 0000 0000 0000 0000
+            logger.debug(String.format("[ZigbeeDriver] Set LinkKey: writing Main Functon %s", regData));
+            gateway.writeRegister(Register305.MAIN_FUNCTION.getAddress(), regData, CONF_S_REG_PASSWORD);
+        } catch (TelegesisErrorException ex) {
+            logger.warn(String.format("[ZigbeeDriver] Error stabilishing LinKey. %s", ex.getErrorMessage()), ex);
+            return false;
+        }
+
+        return true;
+
+
+    }
+
+    @Override
+    public boolean joinNetwork() {
+        logger.trace("Driver305::joinNetwork()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot join network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos unirse a la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to join network"));
+                NetworkJoinedInfo nji = gateway.joinNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Joined network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error join network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean joinNetwork(String PID) {
+        logger.trace("Driver305::joinNetwork(PID=" + PID + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot join network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // Limpiamos la LinkKey 
+                if (!clearLinkKey()){
+                    return false;
+                }                    
+                // Establecemos el preferred PANID
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // solicitamos unirse a la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to join network"));
+                NetworkJoinedInfo nji = gateway.joinNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Joined network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error join network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean joinNetwork(int channel, String PID) {
+        logger.trace("Driver305::joinNetwork(channel=" + channel + ", PID=" + PID + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot join network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos canal
+        String strChannel = checkChannel(channel);
+        if (strChannel == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong channel provided: " + channel);
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // Limpiamos la LinkKey 
+                if (!clearLinkKey()){
+                    return false;
+                }                    
+                // solicitamos unirse a la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to join network"));
+                NetworkJoinedInfo nji = gateway.joinNetwork(channel, PID);
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Joined network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error join network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean joinNetwork(String PID, String linkKey) {
+        logger.trace("Driver305::joinNetwork(PID=" + PID + ", linkKey=" + linkKey + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot join network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos la clave proporcionada
+        String strLinkKey = checkLinkKey(linkKey);
+        if (strLinkKey == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong LinkKey provided: " + linkKey);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // Establecemos el preferred PANID
+                logger.debug(String.format("[ZigbeeDriver] Network create: writing Preferred PAN_ID %s", strPID));
+                gateway.writeRegister(Register305.PREFERRED_PAN_ID.getAddress(), strPID);
+                // establecemos la testLinkKey corregida
+                if (!setLinkKey(strLinkKey)){
+                    return false;
+                }                    
+                // solicitamos unirse a la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to join network"));
+                NetworkJoinedInfo nji = gateway.joinNetwork();
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Joined network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error join network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean joinNetwork(int channel, String PID, String linkKey) {
+        logger.trace("Driver305::joinNetwork(channel=" + channel + ", PID=" + PID + ", linkKey=" + linkKey + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot join network while joined to another network.");
+            return false;
+        }
+
+        // comprobamos canal
+        String strChannel = checkChannel(channel);
+        if (strChannel == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong channel provided: " + channel);
+            return false;
+        }
+
+        // comprobamos el PANID
+        String strPID = checkHex4String(PID);
+        if (strPID == null) {
+            logger.warn("[ZigbeeDriver] Error join network. Wrong PID provided: " + PID);
+            return false;
+        }
+
+        // comprobamos la clave proporcionada
+        String strLinkKey = checkLinkKey(linkKey);
+        if (strLinkKey == null) {
+            logger.warn("[ZigbeeDriver] Error create network. Wrong LinkKey provided: " + linkKey);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // establecemos la testLinkKey corregida
+                if (!setLinkKey(strLinkKey)){
+                    return false;
+                }                    
+                // solicitamos unirse a la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to join network"));
+                NetworkJoinedInfo nji = gateway.joinNetwork(channel, PID);
+                if (nji == null) {
+                    return false;
+                } else {
+                    logger.info("[ZigbeeDriver] Joined network: " + nji.toString());
+                    setNetworkJoined(nji.getChannel(), nji.getPANID(), nji.getEPID());
+                    return true;
+                }
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error join network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean leaveNetwork() {
+        logger.trace("Driver305::leaveNetwork()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot leave network (not joined to any network)");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos abandonar la red
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to leave network"));
+                gateway.leaveNetwork();
+                setNetworkLeft();
+                return true;
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error leave network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean scanNetwork() {
+        logger.trace("Driver305::scanNetwork()");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos que el dongle es un FFD               
+        switch (getDongle().getType()) {
+            case EndDevice:
+            case SleepyEndDevice:
+            case MobileEndDevice:
+                logger.warn("[ZigbeeDriver] Dongle is not a FFD, network scan not launched");
+                return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) { // sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos escanear la red completa (numhops = 0)
+                logger.info(String.format("[ZigbeeDriver] Requesting dongle to scan network for nodes"));
+                gateway.scanNetwork(0);
+                return true;
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error scan network. %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean leaveNetwork(ZigbeeNode node) {
+        logger.trace("Driver305::leaveNetwork(node=" + node + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot request node leaving network if not joined to a network.");
+            return false;
+        }
+
+        // comprobamos si el nodo pertenece al driver
+        String EUI64Addr = node.getEUI64Addr().toString();
+        if (getNode(EUI64Addr) == null) {
+            logger.warn("[ZigbeeDriver] Provided node does not belong to network.");
+            return false;
+
+        }
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos el listener para esperar el ACK del mensaje
+        GtwyLstnrACK lstnr = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos abandonar la red
+                logger.info(String.format("[ZigbeeDriver] Requesting node %s to leave network", node));
+                seqNumber = gateway.leaveNetworkRequest(EUI64Addr);
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error requesting node %s leave network: %s", node, ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+
+        // Comprobamos el resultado despues del bloque de sincronización
+        if (lstnr.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            // eliminamos el nodo
+            removeNode(node);
+
+            return true;
+
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error requesting node %s leave network (ACK TIMEOUT)", node));
+            return false;
+        }
+
+    }
+
+    @Override
+    public boolean sendMessage(ZigbeeNode node, byte[] message) {
+        logger.trace("Driver305::sendMessage(node=" + node + ", message=" + message + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot send messages if not joined to a network.");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos el listener para esperar el ACK del mensaje
+        GtwyLstnrACK lstnr = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                if (endPointMessageSent) { // restablecemos la configuración por defecto de telegesis
+                    // Establecemos el profileID por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing PROFILE_ID_FOR_XCASTS=%s on dongle", Register305.PROFILE_ID_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.PROFILE_ID_FOR_XCASTS.getAddress(), Register305.PROFILE_ID_FOR_XCASTS.getDefaultValue());
+                    // Establecemos el clusterID por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing CLUSTER_ID_FOR_XCASTS=%s on dongle", Register305.CLUSTER_ID_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.CLUSTER_ID_FOR_XCASTS.getAddress(), Register305.CLUSTER_ID_FOR_XCASTS.getDefaultValue());
+                    // Establecemos el SourceDestEP por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS=%s on dongle", Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getAddress(), Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getDefaultValue());
+                    // borramos el flag de configuración cambiada
+                    endPointMessageSent = false;
+                }
+                // solicitamos enviar el mensaje
+                logger.info(String.format("[ZigbeeDriver] message sent to node %s", node));
+                seqNumber = gateway.sendMessageRequest(node.getEUI64Addr().toString(), message);
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error sending message to node %s: %s", node, ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+
+        // después del bloque de sincronización, comprobamos la correcta recepción del mensaje
+        // esto lo hacemos así para no bloquear todo el driver mientras se espera la respuesta
+        // del ACK, y devolvemos el resultado de la espera
+        return lstnr.waitForACK(seqNumber, CONF_ACK_TIMEOUT);
+
+    }
+
+    @Override
+    public boolean sendMessage(ZigbeeDevice device, String profileID, String clusterID, byte[] message) {
+        logger.trace("Driver305::sendMessage(device=" + device + ", profileID=" + profileID + ", clusterID=" + clusterID + ", message=" + message + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot send messages if not joined to a network.");
+            return false;
+        }
+
+        // comprobamos profileID == null
+        if (profileID == null) {
+            profileID = device.getProfileId();
+        }
+
+        // componemos EndPoint
+        String strSourceDestEP = String.format("%s%02X", CONF_S_REG_XCAST_SOURCE_EP, device.getEndPoint());
+
+        // comprobamos profileID
+        String strProfileID = checkHex4String(profileID);
+        if (strProfileID == null) {
+            logger.warn("[ZigbeeDriver] Error sending message. Wrong profileID provided: " + profileID);
+            return false;
+        }
+
+        // comprobamos el ClusterID
+        String strClusterID = checkHex4String(clusterID);
+        if (strClusterID == null) {
+            logger.warn("[ZigbeeDriver] Error sending message. Wrong clusterID provided: " + clusterID);
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos el listener para esperar el ACK del mensaje
+        GtwyLstnrACK lstnr = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // Establecemos el profileID
+                logger.debug(String.format("[ZigbeeDriver] Writing PROFILE_ID_FOR_XCASTS=%s on dongle", strProfileID));
+                gateway.writeRegister(Register305.PROFILE_ID_FOR_XCASTS.getAddress(), strProfileID);
+                // Establecemos el clusterID
+                logger.debug(String.format("[ZigbeeDriver] Writing CLUSTER_ID_FOR_XCASTS=%s on dongle", strClusterID));
+                gateway.writeRegister(Register305.CLUSTER_ID_FOR_XCASTS.getAddress(), strClusterID);
+                // Establecemos el SourceDestEP
+                logger.debug(String.format("[ZigbeeDriver] Writing SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS=%s on dongle", strSourceDestEP));
+                gateway.writeRegister(Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getAddress(), strSourceDestEP);
+
+                // marcamos flag de configuracion cambiada                
+                endPointMessageSent = true;
+
+                // solicitamos enviar el mensaje
+                logger.info(String.format("[ZigbeeDriver] Sending message to device %s", device));
+                seqNumber = gateway.sendMessageRequest(device.getZigbeeNode().getEUI64Addr().toString(), message);
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error sending message to device %s: %s", device, ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+
+        // después del bloque de sincronización, comprobamos la correcta recepción del mensaje
+        // esto lo hacemos así para no bloquear todo el driver mientras se espera la respuesta
+        // del ACK, y devolvemos el resultado de la espera
+        return lstnr.waitForACK(seqNumber, CONF_ACK_TIMEOUT);
+
+    }
+
+    @Override
+    public boolean sendBroadcastMessage(byte[] message) {
+        logger.trace("Driver305::sendBroadcastMessage(message=" + message + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot send messages if not joined to a network.");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                if (endPointMessageSent) { // restablecemos la configuración por defecto de telegesis
+                    // Establecemos el profileID por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing PROFILE_ID_FOR_XCASTS=%s on dongle", Register305.PROFILE_ID_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.PROFILE_ID_FOR_XCASTS.getAddress(), Register305.PROFILE_ID_FOR_XCASTS.getDefaultValue());
+                    // Establecemos el clusterID por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing CLUSTER_ID_FOR_XCASTS=%s on dongle", Register305.CLUSTER_ID_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.CLUSTER_ID_FOR_XCASTS.getAddress(), Register305.CLUSTER_ID_FOR_XCASTS.getDefaultValue());
+                    // Establecemos el SourceDestEP por defecto de telegesis
+                    logger.debug(String.format("[ZigbeeDriver] Writing SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS=%s on dongle", Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getDefaultValue()));
+                    gateway.writeRegister(Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getAddress(), Register305.SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS.getDefaultValue());
+                    // borramos el flag de configuración cambiada
+                    endPointMessageSent = false;
+                }
+                // solicitamos enviar el mensaje con numHops = 0 (todos)
+                logger.info("[ZigbeeDriver] Sending broadcast message");
+                gateway.sendBroadcast(0, message);
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error sending broadcast: %s", ex.getErrorMessage()), ex);
+                return false;
+            }
+        }
+
+        // devolvemos OK
+        return true;
+    }
+
+    @Override
+    public String readRegister(ZigbeeNode node, short regAddress) {
+        logger.trace("Driver305::readRegister(node=" + node + ", regAddress=" + regAddress + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return null;
+        }
+
+        // comprobamos nodo != null
+        if (node == null) {
+            logger.debug("[ZigbeeDriver] llamada a read register con node = null");
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // comprobamos si se trata del dongle
+        if (node.equals(getDongle())) {
+            try {
+                logger.info(String.format("[ZigbeeDriver] Reading register %02X on dongle", regAddress));
+                String regData = gateway.readRegister(regAddress);
+                return regData;
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error reading local %02X register: %s", regAddress, ex), ex);
+                return null;
+            }
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot read remote registers if not joined to a network.");
+            return null;
+        }
+
+        // creamos los listeners para esperar el ACK del mensaje y la lectura del registro        
+        GtwyLstnrRegisterRead lstnrRead = new GtwyLstnrRegisterRead(gateway);
+        GtwyLstnrACK lstnrACK = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos leer el registro
+                logger.info(String.format("[ZigbeeDriver] Requesting reading register %02X on node %s", regAddress, node));
+                seqNumber = gateway.readRemoteRegisterRequest(node.getEUI64Addr().toString(), regAddress);
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error reading %02X register on node %s: %s", regAddress, node, ex.getErrorMessage()), ex);
+                lstnrACK.clearListener();
+                lstnrRead.clearListener();
+                return null;
+            }
+        }
+
+        // Esperamos el ACK del nodo, y en caso de error, devolvemos null
+        if (!lstnrACK.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            logger.warn(String.format("[ZigbeeDriver] Error while reading register %02X on node %s (NACK or timeout)", regAddress, node));
+            lstnrRead.clearListener();
+            return null;
+        }
+
+        // Esperamos el resultado de la operación de lectura
+        if (lstnrRead.waitForRegisterReaded(node.getEUI64Addr().toString(), regAddress, CONF_REGISTER_READ_TIMEOUT)) {
+            logger.info(String.format("[ZigbeeDriver] Register %02X on node %s readed ", regAddress, node));
+            return lstnrRead.getRegisterData();
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while reading register %02X on node %s. Error: %s", regAddress, node, lstnrRead.getErrorMessage()));
+            return null;
+        }
+
+    }
+
+    @Override
+    public boolean writeRegister(ZigbeeNode node, short regAddress, String data) {
+        logger.trace("Driver305::writeRegister(node=" + node + ", regAddress=" + regAddress + ", data=" + data + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos nodo != null
+        if (node == null) {
+            logger.debug("[ZigbeeDriver] llamada a write register con node = null");
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        Register305 register = Register305.fromByte(regAddress);
+
+        // comprobamos si se trata del dongle
+        if (node.equals(getDongle())) {
+            try {
+                // comprobamos si hace falta contraseña
+                if (register.requiresPassword()) {
+                    logger.info(String.format("[ZigbeeDriver] Requesting writing password protected register %02X on dongle", regAddress));
+                    gateway.writeRegister(regAddress, data, ((ZigbeeNodeImpl) node).getRegisterPassword());
+                } else {
+                    logger.info(String.format("[ZigbeeDriver] Requesting writing register %02X on dongle", regAddress));
+                    gateway.writeRegister(regAddress, data);
+                }
+                return true;
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error writing local %02X register: %s", regAddress, ex), ex);
+                return false;
+            }
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot write remote registers if not joined to a network.");
+            return false;
+        }
+
+        // creamos los listeners para esperar el ACK del mensaje y la escritura del registro        
+        GtwyLstnrRegisterWrited lstnrWrite = new GtwyLstnrRegisterWrited(gateway);
+        GtwyLstnrACK lstnrACK = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // comprobamos si hace falta contraseña
+                if (register.requiresPassword()) {
+                    // solicitamos escribir el registro conn contraseña
+                    logger.info(String.format("[ZigbeeDriver] Requesting writing password protected register %02X on node %s", regAddress, node));
+                    seqNumber = gateway.writeRemoteRegisterRequest(node.getEUI64Addr().toString(), regAddress, data, ((ZigbeeNodeImpl) node).getRegisterPassword());
+                } else {
+                    // solicitamos escribir el registro sin contraseña
+                    logger.info(String.format("[ZigbeeDriver] Requesting writing register %02X on node %s", regAddress, node));
+                    seqNumber = gateway.writeRemoteRegisterRequest(node.getEUI64Addr().toString(), regAddress, data);
+                }
+
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error writing %02X register on node %s: %s", regAddress, node, ex.getErrorMessage()), ex);
+                lstnrACK.clearListener();
+                lstnrWrite.clearListener();
+                return false;
+            }
+        }
+
+        // Esperamos el ACK del nodo, y en caso de error, devolvemos false
+        if (!lstnrACK.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            logger.warn(String.format("[ZigbeeDriver] Error while writing register %02X on node %s (NACK or timeout)", regAddress, node));
+            lstnrWrite.clearListener();
+            return false;
+        }
+
+        // Esperamos el resultado de la operación de escritura
+        if (lstnrWrite.waitForRegisterWrited(node.getEUI64Addr().toString(), CONF_REGISTER_WRITE_TIMEOUT)) {
+            logger.info(String.format("[ZigbeeDriver] Register %02X on node %s writed", regAddress, node));
+            return true;
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while writing register %02X on node %s. Error: %s ", regAddress, node, lstnrWrite.getErrorMessage()));
+            return false;
+
+        }
+
+    }
+
+    // </editor-fold>
+    //
+    // <editor-fold defaultstate="collapsed" desc="NODE DISCOVERY">
+    @Override
+    public boolean updateActiveEndPoints(ZigbeeNode node) {
+        logger.trace("Driver305::requestActiveEndPoints(node=" + node + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si es el dongle
+        if (!node.equals(getDongle())) {
+            // comprobamos si estamos unidos a la red
+            if (!isJoinedToNetwork()) {
+                logger.warn("[ZigbeeDriver] Cannot access remote devices if not joined to a network.");
+                return false;
+            }
+        }
+
+        // direccion del nodo sobre el que se consulta
+        NetworkAddress nodeID = node.getNodeID();
+        if (nodeID == null) {
+            logger.warn("[ZigbeeDriver] Cannot perform ZDO request for unknown NodeID.");
+            return false;
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos los listeners para esperar el ACK del mensaje y la lista de endPoints
+        GtwyLstnrActiveEndPoints lstnrEPList = new GtwyLstnrActiveEndPoints(gateway);
+        GtwyLstnrACK lstnrACK = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        // direccion del nodo al que se realiza la consulta: dongle
+        String consultingNodeAddr = this.getDongle().getEUI64Addr().toString();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos la lista de endPoints
+                logger.info(String.format("[ZigbeeDriver] Requesting active end points on node %s", node));
+                seqNumber = gateway.requestNodeActiveEndPoints(consultingNodeAddr, nodeID.toString());
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error requesting active end points on node %s: %s", node, ex.getErrorMessage()), ex);
+                lstnrACK.clearListener();
+                lstnrEPList.clearListener();
+                return false;
+            }
+        }
+
+        // Esperamos el ACK del nodo, y en caso de error, devolvemos false
+        if (!lstnrACK.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting active EndPoints on node %s (NACK or timeout)", node));
+            lstnrEPList.clearListener();
+            return false;
+        }
+
+        // Esperamos el resultado de la consulta de endPoints
+        if (lstnrEPList.waitForActiveEndPoints(nodeID.toString(), CONF_ZDO_RESPONSE_TIMEOUT)) {
+            short[] EPList = lstnrEPList.getEndPointList();
+            // comprobamos los device del nodo
+            for (int i = 0; i < EPList.length; i++) {
+                ZigbeeDevice device = node.getZigbeeDevice(EPList[i]);
+                // si no existe lo creamos
+                if (device == null) {
+                    device = createDevice(node, EPList[i]);
+                }
+            }
+            logger.info(String.format("[ZigbeeDriver] EndPoints node %s updated", node));
+            return true;
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting active EndPoints on node %s. Error: %s ", node, lstnrEPList.getErrorMessage()));
+            return false;
+        }
+
+    }
+
+    @Override
+    public boolean updateEndPointDescriptor(ZigbeeDevice device) {
+        logger.trace("Driver305::requestEndPointDescriptor(device=" + device + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+
+        // comprobamos si es el dongle
+        if (!device.getZigbeeNode().equals(getDongle())) {
+            // comprobamos si estamos unidos a la red
+            if (!isJoinedToNetwork()) {
+                logger.warn("[ZigbeeDriver] Cannot access remote devices if not joined to a network.");
+                return false;
+            }
+        }
+
+        // direccion del nodo sobre el que se consulta
+        NetworkAddress nodeID = device.getZigbeeNode().getNodeID();
+        if (nodeID == null) {
+            logger.warn("[ZigbeeDriver] Cannot perform ZDO request for unknown NodeID.");
+            return false;
+        }
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos los listeners para esperar el ACK del mensaje y el descriptor del device
+        GtwyLstnrEndPointDescriptor lstnrEP = new GtwyLstnrEndPointDescriptor(gateway);
+        GtwyLstnrACK lstnrACK = new GtwyLstnrACK(gateway);
+
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        // direccion del nodo al que se realiza la consulta: dongle
+        String consultingNodeAddr = this.getDongle().getEUI64Addr().toString();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos el decriptor del endPoint
+                logger.info(String.format("[ZigbeeDriver] Requesting end point descriptor for device %s", device));
+                seqNumber = gateway.requestNodeEndPointSimpleDescriptor(consultingNodeAddr, nodeID.toString(), device.getEndPoint());
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error requesting descriptor for device %s: %s", device, ex.getErrorMessage()), ex);
+                lstnrACK.clearListener();
+                lstnrEP.clearListener();
+                return false;
+            }
+        }
+
+        // Esperamos el ACK del nodo, y en caso de error, devolvemos false
+        if (!lstnrACK.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting EndPoint descriptor on device %s (NACK or timeout)", device));
+            lstnrEP.clearListener();
+            return false;
+        }
+
+        // Esperamos el resultado de la operación
+        if (lstnrEP.waitForEndPointSimpleDescriptor(nodeID.toString(), device.getEndPoint(), CONF_ZDO_RESPONSE_TIMEOUT)) {
+            ZigbeeDevice auxDevice = lstnrEP.getEndPointDescriptor();
+            // actualizamos el device
+            ((ZigbeeDeviceImpl) device).setProfileID(auxDevice.getProfileId());
+            ((ZigbeeDeviceImpl) device).setDeviceID(auxDevice.getDeviceId());
+            ((ZigbeeDeviceImpl) device).setInClusterList(auxDevice.getInClusterList());
+            ((ZigbeeDeviceImpl) device).setOutClusterList(auxDevice.getOutClusterList());
+            logger.info(String.format("[ZigbeeDriver] EndPoint descriptor on device %s updated", device));
+            // devolvemos resultado OK
+            return true;
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting EndPoint descriptor on device %s. Error: %s", device, lstnrEP.getErrorMessage()));
+            return false;
+        }
+
+    }
+
+    @Override
+    public boolean updateNeighbourTable(ZigbeeNode node) {
+        logger.trace("Driver305::updateNeighbourTable(node=" + node + ")");
+
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si estamos unidos a la red
+        if (!isJoinedToNetwork()) {
+            logger.warn("[ZigbeeDriver] Cannot retreive neighbours if not joined to a network.");
+            return false;
+        }
+
+        // creamos el listener para almacenar resultados de busqueda
+        GtwyLstnrNeighbourTableResponse lstnrNTR = null;
+        // creamos un bucle para recuperar la tabla, usando una variable de control
+        boolean done = false;
+        int nextIndex = 0;
+        while (!done) {
+            // recuperamos el siguiente grupo de vecinos
+            lstnrNTR = launchNeighbourTableRequest(node, nextIndex);
+
+            // comprobamos resultado
+            if (lstnrNTR != null) {
+                NeighbourTableEntry[] table = lstnrNTR.getNeighbourTable();
+                int tableLength = lstnrNTR.getNeighbourTableLength();
+                // Recorremos la tabla de vecinos
+                for (int i = 0; i < table.length; i++) {
+                    NeighbourTableEntry nte = table[i];
+                    // recuperamos el vecino
+                    ZigbeeNode neighbour = getNode(nte.getEUI64Addr());
+                    // si no existe, lo creamos
+                    if (neighbour == null) {
+                        EUI64Address nAddress = new EUI64Address(nte.getEUI64Addr());
+                        NetworkAddress nNodeID = new NetworkAddress(nte.getID());
+                        ZigbeeNodeType nType = ZigbeeNodeType.fromZigbeeDeviceType(nte.getType());
+                        neighbour = createNode(nAddress, nNodeID, nType);
+                    }
+
+                    // guardamos el vecino
+                    ((ZigbeeNodeImpl) node).addNode(neighbour); //TODO: incluir LQI
+
+                    // calculamos el siguiente índice de la tabla para comparar 
+                    // con la longitud de la tabla
+                    nextIndex = nte.getIndex() + 1;
+                }
+
+                // comprobamos si hay que consultar más nodos
+                if (nextIndex == tableLength) {
+                    done = true;
+                }
+
+            } else { //if (lstnrNTR != null) 
+                // devolvemos error
+                return false;
+            }
+        }
+
+        // devolvemos OK, ya que si ha habido un error antes, habremos abandonado ya
+        logger.info(String.format("[ZigbeeDriver] Neighbours on node %s updated", node));
+        return true;
+
+    }
+
+    /**
+     * Lanza una consulta de la tabla de vecinos de un nodo, a partir de un indice determinado
+     * @param node Nodo para consultar vecinos
+     * @param startIndex Índice de acceso a la tabla de vecinos
+     * @return el GtwyLstnrNeighbourTableResponse usado para esperar la 
+     * respuesta si la busqueda se ha realizado correctamente, o null en otro 
+     * caso. Elegimos este tipo de retorno porque ya almacena la tabla de 
+     * vecinos recuperada y la longitud total
+     */
+    private GtwyLstnrNeighbourTableResponse launchNeighbourTableRequest(ZigbeeNode node, int startIndex) {
+        logger.trace("Driver305::launchNeighbourTableRequest(node=" + node + ", startIndex=" + startIndex + ")");
+
+        // comprobamos si estamos unidos a la red
+        if (getNetworkInfo() == null) {
+            return null;
+        }
+
+        // direccion del nodo sobre el que se consulta
+        NetworkAddress nodeID = node.getNodeID();
+        if (nodeID == null) {
+            logger.warn("[ZigbeeDriver] Cannot perform ZDO request for unknown NodeID.");
+            return null;
+        }
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos los listeners para esperar el ACK del mensaje y la tabla de vecinos
+        GtwyLstnrNeighbourTableResponse lstnrNTR = new GtwyLstnrNeighbourTableResponse(gateway);
+        GtwyLstnrACK lstnrACK = new GtwyLstnrACK(gateway);
+        // seqNumber para comprobar envío del mensaje
+        short seqNumber;
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos la tabla de vecinos
+                logger.info(String.format("[ZigbeeDriver] Requesting Neighbour table for node %s (starting index %d)", node, startIndex));
+                seqNumber = gateway.requestNeighbourTable((short) startIndex, node.getEUI64Addr().toString());
+
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error requesting neighbour table for node %s: %s", node, ex.getErrorMessage()), ex);
+                lstnrACK.clearListener();
+                lstnrNTR.clearListener();
+                return null;
+            }
+        }
+
+        // Esperamos el ACK del nodo, y en caso de error, devolvemos false
+        if (!lstnrACK.waitForACK(seqNumber, CONF_ACK_TIMEOUT)) {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting neighbours on node %s (NACK or timeout)", node));
+            lstnrNTR.clearListener();
+            return null;
+        }
+
+        // Esperamos el resultado de la operación
+        if (lstnrNTR.waitForNeighbourTableResponse(nodeID.toString(), CONF_NEIGHBOUR_RESPONSE_TIMEOUT)) {
+            // devolvemos el listener
+            return lstnrNTR;
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting neighbours on node %s. Error: %s", node, lstnrNTR.getErrorMessage()));
+            return null;
+        }
+
+    }
+
+    @Override
+    public boolean findRoute(ZigbeeNode node) {
+        logger.trace("Driver305::findRoute(node=" + node + ")");
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            return false;
+        }
+
+        // comprobamos si es el dongle
+        if (!node.equals(getDongle())) {
+            // comprobamos si estamos unidos a la red
+            if (!isJoinedToNetwork()) {
+                logger.warn("[ZigbeeDriver] Cannot access remote devices if not joined to a network.");
+                return false;
+            }
+        }
+
+        // comprobamos el bloqueo del driver
+        checkLock();
+
+        // creamos el listener para esperar la ruta
+        GtwyLstnrSourceRoute lstnrSR = new GtwyLstnrSourceRoute(gateway);
+        // recuperamos la direccion del nodo
+        String EUI64Addr = node.getEUI64Addr().toString();
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+            try {
+                // solicitamos al gateway la la busqueda de la ruta
+                logger.info(String.format("[ZigbeeDriver] Requesting find route for node %s", node));
+                gateway.findRoute(EUI64Addr);
+            } catch (TelegesisErrorException ex) {
+                logger.warn(String.format("[ZigbeeDriver] Error requesting source route on node %s: %s", node, ex.getErrorMessage()), ex);
+                lstnrSR.clearListener();
+                return false;
+            }
+
+        }
+
+        // Esperamos respuesta del nodo, y en caso de error, devolvemos false
+        if (lstnrSR.waitForSourceRoute(EUI64Addr, CONF_ZDO_RESPONSE_TIMEOUT)) {
+            return true;
+        } else {
+            logger.warn(String.format("[ZigbeeDriver] Error while requesting source route on node %s (Timeout)", node));
+            return false;
+        }
+
+        /*
+         * Nota: no actualizamos la ruta, ya que el driver actualiza 
+         * automáticamente las rutas cuando se recibe el mensaje. usamos el 
+         * listener unicamente para controlar la notificacion
+         */
+
+
+    }
+    // </editor-fold>
+//
+    // <editor-fold defaultstate="collapsed" desc="DRIVER CONTROL">
+// Procedimientos autonomos controlados por el driver
+    AbstractDriverMaintenanceTask errorChecker;
+    AbstractDriverMaintenanceTask neighbourFinder;
+    AbstractDriverMaintenanceTask registerWriter;
+    AbstractDriverMaintenanceTask devicesFinder;
+    AbstractDriverMaintenanceTask parentFinder;
+
+    @Override
+    public void disable() {
+        logger.trace("Driver305::disable()");
+
+        // desregistramos como listener del gateway
+        gateway.unregisterListener(this);
+
+        // actualizamos el estado
+        setStatus(DriverStatus.Disabled);
+
+        logger.info(String.format("[ZigbeeDriver] Driver disabled"));
+
+    }
+
+    @Override
+    public boolean init() {
+        logger.trace("Driver305::init()");
+
+        // comprobamos que tenemos gateway
+        if (gateway == null) {
+            logger.warn(String.format("[ZigbeeDriver] Cannot initialize driver: null gateway"));
+            return false;
+        }
+
+        logger.info(String.format("[ZigbeeDriver] Initializing driver..."));
+        // actualizamos el estado
+        this.setStatus(DriverStatus.Initializing);
+
+        // cargamos la configuracion
+        this.loadConfiguration();
+
+        // Bloqueamos el gateway durante el tiempo de inicializacion
+        gateway.lock(GATEWAY_INITIALIZATION_LOCK_TIME);
+
+        synchronized (SYNC_OPS) {// sincronizamos para evitar solape de comandos
+
+            // consultamos la información de la red
+            NetworkInformation ni = gateway.getNetworkInformation();
+            String dongleNodeID = null;
+            ZigbeeNodeType dongleType = ZigbeeNodeType.Unknown;
+            if (ni != null) {
+                // establecemos la información de la red
+                setNetworkJoined(ni.getChannel(), ni.getPID(), ni.getEPID());
+
+                dongleType = ZigbeeNodeType.fromZigbeeDeviceType(ni.getDeviceType());
+
+                // consultamos el nodeID del dongle
+                try {
+                    dongleNodeID = gateway.readRegister(Register305.LOCAL_NODEID.getAddress());
+                } catch (TelegesisErrorException ex) {
+                    logger.warn(String.format("[ZigbeeDriver] Error initializing driver, error requesting dongle nodeID: %s", ex.getErrorMessage()), ex);
+                }
+            }
+
+
+            //creamos el dongle
+            createDongle(gateway.getDongleAddress(), dongleNodeID, dongleType);
+
+            // establecemos la configuracion de registros del dongle
+            if (CONF_UPDATE_DONGLE_S_REGISTERS) {
+                logger.info(String.format("[ZigbeeDriver] writing register to dongle..."));
+                // recuperamos los registros
+                HashMap<String, String> dongleRegisters = getDongleRegisterConfig();
+                Iterator it = dongleRegisters.keySet().iterator();
+                while (it.hasNext()) {
+                    try {
+                        // recuperamos el registro
+                        String regStrAddr = (String) it.next();
+                        short regAddr = (short) Integer.parseInt(regStrAddr, 16);
+                        String regValue = dongleRegisters.get(regStrAddr);
+                        Register305 reg = Register305.fromByte(regAddr);
+                        if (reg.isWritable()) {
+                            if (reg.requiresPassword()) {
+                                gateway.writeRegister(regAddr, regValue, CONF_S_REG_PASSWORD);
+                            } else {
+                                gateway.writeRegister(regAddr, regValue);
+                            }
+                        }
+                    } catch (TelegesisErrorException ex) {
+                        logger.warn(String.format("[ZigbeeDriver] Error initializing driver: %s", ex.getErrorMessage()), ex);
+                        return false;
+                    }
+                }
+            }
+
+            // registramos el listener
+            gateway.registerListener(this);
+
+            // actualizamos estado del driver
+            this.setStatus(DriverStatus.Ready);
+
+            // liberamos bloqueo del gateway
+            gateway.unlock();
+
+            // comprobamos si hay que arrancar el driver
+            if (CONF_AUTOSTART) {
+                start();
+            }
+
+            // devolvemos OK
+            return true;
+
+        }
+
+    }
+
+    @Override
+    public boolean start() {
+        logger.trace("Driver305::start()");
+
+        logger.info(String.format("[ZigbeeDriver] Driver starting..."));
+
+        // comprobamos el estado del driver
+        if (!isEnabled()) {
+            logger.warn(String.format("[ZigbeeDriver] Cannot start driver (disabled)"));
+            return false;
+        }
+
+        // Comprobacion de errores de nodo
+        if (CONF_CHECK_ZIGBEE_ERROR) {
+            logger.info(String.format("[ZigbeeDriver] Launching ErrorChecker driver maintenance task..."));
+            // creamos el comprobador de errores
+            errorChecker = new ErrorCheckerDriverMaintenanceTask();
+            errorChecker.setFrameDelay(CONF_CHECK_ZIGBEE_ERROR_FRAME_DELAY);
+            errorChecker.setMaintenanceTime(CONF_CHECK_ZIGBEE_ERROR_MAINTENANCE_PERIOD);
+            errorChecker.setRecoveryTime(CONF_CHECK_ZIGBEE_ERROR_RECOVERY_PERIOD);
+            errorChecker.start(this);
+        }
+        // buscador de vecinos
+        if (CONF_GET_NEIGHBOURS) {
+            // creamos el buscador de vecinos de los nodos
+            logger.info(String.format("[ZigbeeDriver] Launching NeighbourFinder driver maintenance task..."));
+            neighbourFinder = new NeighbourFinderDriverMaintenanceTask();
+            neighbourFinder.setFrameDelay(CONF_GET_NEIGHBOURS_FRAME_DELAY);
+            neighbourFinder.setMaintenanceTime(CONF_GET_NEIGHBOURS_MAINTENANCE_PERIOD);
+            neighbourFinder.setRecoveryTime(CONF_GET_NEIGHBOURS_RECOVERY_PERIOD);
+            neighbourFinder.start(this);
+        }
+        // buscador de padres
+        if (CONF_GET_PARENT) {
+            // creamos el buscador de padres de los nodos
+            logger.info(String.format("[ZigbeeDriver] Launching ParentFinder driver maintenance task..."));
+            parentFinder = new ParentFinderDriverMaintenanceTask();
+            parentFinder.setFrameDelay(CONF_GET_PARENT_FRAME_DELAY);
+            parentFinder.setMaintenanceTime(CONF_GET_PARENT_MAINTENANCE_PERIOD);
+            parentFinder.setRecoveryTime(CONF_GET_PARENT_RECOVERY_PERIOD);
+            parentFinder.start(this);
+        }
+        // configurador de registros
+        if (CONF_UPDATE_NODE_S_REGISTERS) {
+            // creamos el configurador de registros de los nodos
+            logger.info(String.format("[ZigbeeDriver] Launching RegisterWriter driver maintenance task..."));
+            registerWriter = new NodeRegisterUpdaterDriverMaintenanceTask();
+            registerWriter.setFrameDelay(CONF_UPDATE_NODE_S_REGISTERS_FRAME_DELAY);
+            registerWriter.setRecoveryTime(CONF_UPDATE_NODE_S_REGISTERS_RECOVERY_PERIOD);
+            registerWriter.start(this);
+        }
+        // buscador de endpoints
+        if (CONF_GET_ZIGBEE_DEVICES) {
+            // creamos el buscador de enpoints de los nodos
+            logger.info(String.format("[ZigbeeDriver] Launching DevicesFinder driver maintenance task..."));
+            devicesFinder = new ZigbeeDevicesFinderDriverMaintenanceTask();
+            devicesFinder.setFrameDelay(CONF_GET_ZIGBEE_DEVICES_FRAME_DELAY);
+            devicesFinder.setRecoveryTime(CONF_GET_ZIGBEE_DEVICES_RECOVERY_PERIOD);
+            devicesFinder.start(this);
+        }
+
+        logger.info(String.format("[ZigbeeDriver] Driver started."));
+
+        // actualizamos el estado
+        setStatus(DriverStatus.Running);
+
+        // devolvemos OK
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        logger.trace("Driver::stop()");
+
+        // establecemos el estado a stopping, y eso hará que el driver se pare
+        this.setStatus(DriverStatus.Stopping);
+        logger.info(String.format("[ZigbeeDriver] Driver stopping..."));
+
+        // paramos las tareas en segundo plano
+        launchStoppingMaintenanceTasks();
+
+        return true;
+
+    }
+
+    protected void launchStoppingMaintenanceTasks() {
+        logger.trace("Driver::launchStoppingMaintenanceTasks()");
+
+        // creamos la tarea para parar las tareas
+        Runnable target = new Runnable() {
+
+            @Override
+            public void run() {
+                // control de errores
+                if (errorChecker != null) {
+                    logger.info("[ZigbeeDriver] Stopping errorChecker maintenance task");
+                    errorChecker.stop();
+                    logger.info("[ZigbeeDriver] errorChecker stopped");
+                }
+                // buscador de vecinos
+                if (neighbourFinder != null) {
+                    logger.info("[ZigbeeDriver] Stopping neighbourFinder maintenance task");
+                    neighbourFinder.stop();
+                    logger.info("[ZigbeeDriver] neighbourFinder stopped");
+                }
+                // buscador de padres
+                if (parentFinder != null) {
+                    logger.info("[ZigbeeDriver] Stopping parentFinder maintenance task");
+                    parentFinder.stop();
+                    logger.info("[ZigbeeDriver] parentFinder stopped");
+                }
+                // configurador de registros
+                if (registerWriter != null) {
+                    logger.info("[ZigbeeDriver] Stopping registerWriter maintenance task");
+                    registerWriter.stop();
+                    logger.info("[ZigbeeDriver] registerWriter stopped");
+                }
+                // buscador de endpoints
+                if (devicesFinder != null) {
+                    logger.info("[ZigbeeDriver] Stopping devicesFinder maintenance task");
+                    devicesFinder.stop();
+                    logger.info("[ZigbeeDriver] devicesFinder stopped");
+                }
+
+                // establecemos el estado a ready
+                setStatus(DriverStatus.Ready);
+            }
+        };
+        // lanzamos la tarea
+        Thread th = new Thread(target);
+        th.start();
+    }
+
+    @Override
+    public Gateway getGateway() {
+        return gateway;
+    }
+
+    // </editor-fold>
+    
+    /**
+     * Comprueba que la cadena proporcionada es válida, y devuelve una cadena 
+     * adecuada para utilizar con el gateway de Telegesis
+     * @param hex4String cadena a comprobar
+     * @return cadena a utilizar o null si no es válida
+     */
+    private String checkHex4String(String hex4String) {
+        logger.trace("Driver305::checkHex4String(hex4String=" + hex4String + ")");
+        // comprobamos que es una cadena hexadecimal
+        String testHex4String = hex4String.toUpperCase().replace("[^0123456789ABCDEF]", "");
+        if (!testHex4String.equals(hex4String.toUpperCase())) {
+            return null;
+        }
+
+        // comprobamos longitud
+        if (testHex4String.length() != 4) {
+            return null;
+        }
+
+        // devolvemos el valor formateado
+        return testHex4String;
+    }
+
+    /**
+     * Comprueba que el canal proporcionado es válido, y devuelve una cadena 
+     * adecuada para utilizar con el gateway de Telegesis
+     * @param channel Canal a comprobar
+     * @return Channel mask a utilizar o null si no es válido
+     */
+    private String checkChannel(int channel) {
+        logger.trace("Driver305::checkChannel(channel=" + channel + ")");
+        if ((channel < 11) || (channel > 26)) {
+            return null;
+        }
+        int channelMask = (1 << (channel - 11)); // desplazamos el 1 tantas veces como el número de canal
+        String strChannelMask = String.format("%04X", channelMask);
+
+        // devolvemos el valor formateado
+        return strChannelMask;
+    }
+
+    /**
+     * Comprueba que la LinkKey proporcionada es válida, y devuelve una cadena 
+     * adecuada para utilizar con el gateway de Telegesis
+     * @param linkKey Link Key a comprobar
+     * @return linkKey a utilizar o null si no es válida
+     */
+    private String checkLinkKey(String linkKey) {
+        logger.trace("Driver305::checkLinkKey(linkKey=" + linkKey + ")");
+        // comprobamos la clave proporcionada
+        String testLinkKey = "";
+        if (linkKey.length() == 32) {
+            // se debe tratar de una clave hexadecimal, comprobamos caracteres no validos
+            testLinkKey = linkKey.toUpperCase().replace("[^0123456789ABCDEF]", "0");
+            if (!testLinkKey.equals(linkKey.toUpperCase())) {
+                return null;
+            }
+        } else { // consideramos una clave textual 
+            if (linkKey.length() > 16) { // clave textual: truncada
+                logger.warn("[ZigbeeDriver] provided link key (" + linkKey + ") is too long, truncating to 16 first characters");
+            }
+            byte[] strCodes = linkKey.getBytes(Charset.forName("ISO-8859-1"));
+            // no modificamos la cadena, porque sólo recorreremos 16 bytes
+            for (int i = 0; i < 16; i++) {
+                String hexCode;
+                if (i <= strCodes.length) {
+                    hexCode = String.format("%02X", strCodes[i]);
+                } else {
+                    hexCode = "00";
+                }
+                // acumulamos la cadena
+                testLinkKey = testLinkKey + hexCode;
+            }
+        }
+        // devolvemos el valor formateado
+        return testLinkKey;
+    }
+
+    // </editor-fold>
+    //
+    
+    // <editor-fold defaultstate="collapsed" desc="GATEWAY LISTENER">
+    @Override
+    public void acknowledgement(short seqNumber, boolean wasACK, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void routeRecordReceived(String EUI64Addr, int numHops, String[] route, Gateway gtwy) {
+        logger.trace("Driver305::routeRecordReceived(EUI64Addr=" + EUI64Addr + ", numHops=" + numHops + ", route=" + route + ", gtwy=" + gtwy + ")");
+
+        logger.info(String.format("[ZigbeeDriver] Route record received for address %s", EUI64Addr));
+
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+        // si el nodo no existe lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr));
+        }
+
+        // recuperamos los nodos de la ruta
+        ZigbeeNode[] nodeRoute = new ZigbeeNode[route.length];
+        for (int i = 0; i < route.length; i++) {
+            String nodeId = route[i];
+            ZigbeeNode routeNode = getNode(nodeId);
+            // si el nodo no existe NO solicitamos la creación
+//            if (routeNode == null) {
+//                routeNode = createNode(new NetworkAddress(nodeId));
+//            }
+            nodeRoute[i] = routeNode;
+        }
+
+        // guardamos la ruta del nodo
+        ((ZigbeeNodeImpl) node).setRoute(nodeRoute);
+
+    }
+
+    @Override
+    public void broadcastMessageReceived(String EUI64Addr, byte[] message, Gateway gtwy) {
+        logger.trace("Driver305::broadcastMessageReceived(EUI64Addr=" + EUI64Addr + ", message=" + message + ", gtwy=" + gtwy + ")");
+
+        logger.info(String.format("[ZigbeeDriver] Received broadcast message from address %s (%d num bytes)", EUI64Addr, message.length));
+
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+        // si el nodo no está registrado, lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr));
+        }
+
+        // notificamos al nodo la recepción del mensaje
+        ((ZigbeeNodeImpl) node).receiveMessage(message);
+
+    }
+
+    @Override
+    public void messageReceived(String EUI64Addr, byte[] message, String type, Gateway gtwy) {
+        logger.trace("Driver305::messageReceived(EUI64Addr=" + EUI64Addr + ", message=" + message + ", type=" + type + ", gtwy=" + gtwy + ")");
+
+        logger.info(String.format("[ZigbeeDriver] Received message from address %s (%d num bytes)", EUI64Addr, message.length));
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+
+        // si el nodo no está registrado, lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr));
+        }
+        // notificamos al nodo la recepción del mensaje
+        ((ZigbeeNodeImpl) node).receiveMessage(message);
+
+    }
+
+    @Override
+    public void endpointMessageReceived(String EUI64Addr, String nodeID, short sourceEP, short destEP, String profileID, String clusterID, byte[] payload, Gateway gtwy) {
+        logger.trace("Driver305::endpointMessageReceived(EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", sourceEP=" + sourceEP + ", destEP=" + destEP + ", profileID=" + profileID + ", payload=" + payload + ", gtwy=" + gtwy + ")");
+
+        logger.info(String.format("[ZigbeeDriver] Received End point message from address %s (%d num bytes)", EUI64Addr, payload.length));
+
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+        // si el nodo no existe lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr));
+        }
+
+        // recuperamos el device
+        ZigbeeDevice device = node.getZigbeeDevice(sourceEP);
+        // si no existe lo creamos
+        if (device == null) {
+            device = createDevice(node, sourceEP);
+        }
+
+        // notificamos al device la recepción del mensaje
+        ((ZigbeeDeviceImpl) device).receiveMessage(profileID, clusterID, payload);
+
+    }
+
+    @Override
+    public void nodeAnnounce(ZigbeeDeviceType type, String EUI64Addr, String nodeID, int RSSI, short LQI, Gateway gtwy) {
+        logger.trace("Driver305::nodeAnnounce(type=" + type + ", EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", RSSI=" + RSSI + ", LQI=" + LQI + ", gtwy=" + gtwy + ")");
+
+        logger.info(String.format("[ZigbeeDriver] Node announce (type: %s) from address %s, nodeID: %s (RSSI: %d, LQI: %02X)", type, EUI64Addr, nodeID, RSSI, LQI));
+
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+        // obtenemos el tipo correspondiente al nodo
+        ZigbeeNodeType ndType = ZigbeeNodeType.fromZigbeeDeviceType(type);
+        // si no existe, lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr), new NetworkAddress(nodeID), ndType);
+        }
+
+        // actualizamos tipo de nodo
+        ((ZigbeeNodeImpl) node).setType(ndType);
+
+        // actualizamos RSSI
+        ((ZigbeeNodeImpl) node).setRSSI(RSSI);
+
+        // actualizamos LQI
+        ((ZigbeeNodeImpl) node).setLQI(LQI);
+
+        // actualizamos el coordinador de la red (si fuera el caso)
+        checkSetCoordinator(node);
+
+        // actualizamos la dirección de red
+        updateNetworkAddress(node, nodeID);
+
+    }
+
+    @Override
+    public void newNode(String EUI64Addr, String nodeID, String parentID, Gateway gtwy) {
+        logger.trace("Driver305::newNode(EUI64Addr=" + EUI64Addr + ", nodeID=" + nodeID + ", parentID=" + parentID + ", gtwy=" + gtwy + ")");
+
+        // loggeamos el mensaje
+        logger.info(String.format("[ZigbeeDriver] New node %s is attempting to join network with nodeId=%s at parentId=%s", EUI64Addr, nodeID, parentID));
+
+        // comprobamos si existiera el nodo para actualizar el padre
+        ZigbeeNode node = getNode(EUI64Addr);
+        // si no existe, abandonamos, no creamos el nodo
+        if (node == null) {
+            return;
+        }
+
+        // actualizamos la dirección de red
+        updateNetworkAddress(node, nodeID);
+
+        // recuperamos el padre
+        ZigbeeNode parent = getNode(parentID);
+        // si no existe, abandonamos
+        if (parent == null) {
+            return;
+        }
+        // actualizamos el padre                
+        ((ZigbeeNodeImpl) node).setParent(parent);
+
+
+    }
+
+    @Override
+    public void leftPAN(Gateway gtwy) {
+        logger.trace("Driver305::leftPAN()");
+        // establecemos abandono de red
+        setNetworkLeft();
+    }
+
+    @Override
+    public void joinedPan(int channel, String PID, String EPID, Gateway gtwy) {
+        logger.trace("Driver305::joinedPAN(channel=" + channel + ", PID=" + PID + ", EPID=" + EPID + ", gtwy=" + gtwy + ")");
+        // establecemos incorporación a la red
+        setNetworkJoined(channel, PID, EPID);
+    }
+
+    @Override
+    public void registerWrited(String nodeID, String EUI64Addr, short errorCode, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void registerReaded(String nodeID, String EUI64Addr, short register, short errorCode, String data, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void addrResponse(short errorCode, String nodeID, String EUI64Addr, Gateway gtwy) {
+        logger.trace("Driver305::addrResponse(errorCode=" + errorCode + ", nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ", gtwy=" + gtwy + ")");
+
+        // comprobamos errorCode
+        if (errorCode != 0) {
+            // abandonamos
+            return;
+        }
+
+        // recuperamos el nodo
+        ZigbeeNode node = getNode(EUI64Addr);
+        // si no existe, lo creamos
+        if (node == null) {
+            node = createNode(new EUI64Address(EUI64Addr), new NetworkAddress(nodeID));
+        }
+        // actualizamos la dirección de red
+        updateNetworkAddress(node, nodeID);
+
+    }
+
+    @Override
+    public void neighbourTableResponse(String nodeID, short errorCode, int tableLength, NeighbourTableEntry[] table, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void nodeDescriptorResponse(String nodeID, short errorCode, Map descriptor, Gateway gtwy) {
+        logger.trace("Driver305::nodeDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", descriptor=" + descriptor + ", gtwy=" + gtwy + ")");
+        // TODO: convertir en función con GtwyLstnr, acumular en atributos del nodo
+    }
+
+    @Override
+    public void powerDescriptorResponse(String nodeID, short errorCode, String descriptor, Gateway gtwy) {
+        logger.trace("Driver305::powerDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", descriptor=" + descriptor + ", gtwy=" + gtwy + ")");
+        // TODO: convertir en función con GtwyLstnr, acumular en atributos del nodo
+    }
+
+    @Override
+    public void nodeActiveEPResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void nodeEndPointSimpleDescriptorResponse(String nodeID, short errorCode, short EP, String ProfileID, String DeviceID, String[] inClusterList, String[] outClusterList, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void nodeMatchingDescriptorResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        logger.trace("Driver305::nodeMatchingDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EPList=" + EPList + ", gtwy=" + gtwy + ")");
+        // TODO: convertir en función con GtwyLstnr
+    }
+
+    @Override
+    public void unhandledCommand(String command, String[] parameters, Gateway gtwy) {
+        // ignoramos
+    }
+
+    @Override
+    public void unknownMessage(String message, Gateway gtwy) {
+        // ignoramos
+    }
+    // </editor-fold>
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/DriverFactory.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/DriverFactory.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/DriverFactory.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,48 @@
+/*
+ * 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.driver.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class DriverFactory {
+    
+    /**
+     * Creates a driver operating the provided gateway, checking communication
+     * to determine right implementation
+     * @param gtwy Gateway to be used by the driver
+     * @return Driver or null if error or not supported Gateway
+     */
+    public static Driver createDriver(Gateway gtwy) {
+        
+        // comprobamos para todas las implementaciones soportadas
+        Driver testDrvr;
+        
+        // comprobamos version R305X
+        testDrvr = new Driver305(gtwy);
+        if (testDrvr.init()){
+            return testDrvr;
+        }
+        
+        // no es un driver valido
+        return null;
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeDeviceImpl.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeDeviceImpl.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeDeviceImpl.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,378 @@
+/*
+ * 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.driver.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDeviceListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class ZigbeeDeviceImpl implements ZigbeeDevice {
+
+    short endPoint;
+    String profileID;
+    String deviceID;
+    ArrayList<String> inClusterList = new ArrayList<String>();
+    ArrayList<String> outClusterList = new ArrayList<String>();
+    final ZigbeeNode node;
+    final Driver driver;
+    private DeviceStatus status = DeviceStatus.Unknown;
+    // Relaciones entre nodos
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public ZigbeeDeviceImpl(Driver driver, ZigbeeNode node, short endPoint) {
+        logger.trace("ZigbeeDeviceImpl::ZigbeeDeviceImpl(driver=" + driver + ", node=" + node + ", endPoint=" + endPoint + ")");
+        this.driver = driver;
+        this.node = node;
+        this.endPoint = endPoint;
+    }
+
+    @Override
+    public boolean discover() {
+        logger.trace("ZigbeeDeviceImpl::discover()");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(DeviceStatus.Discovering);
+
+            // lanzamos la consulta del descriptor del end point
+            boolean requestResult = driver.updateEndPointDescriptor(this);
+
+            // actualizamos el estado
+            setStatus(DeviceStatus.Ready);
+
+            // comprobamos error
+            if (requestResult) {
+                resetErrorCount();
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos el resultado
+            return requestResult;
+
+        }
+
+    }
+
+    /**
+     * Lanza un proceso de recovery en el device
+     * @return True si finaliza el proceso correctamente, false en otro caso
+     */
+    @Override
+    public boolean recover() {
+        logger.trace("ZigbeeDeviceImpl::recover()");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(DeviceStatus.Recovering);
+
+            //TODO: definir proceso de recovery en el device, de momento restablecemos la cuenta de errores
+
+            boolean recovered = true;
+
+            // comprobamos resultado del recovery
+            if (recovered) {
+                resetErrorCount(); // esto actualiza el estado
+            } else {
+                addErrorCount(); // esto actualiza el estado
+            }
+
+            // devolvemos resultado
+            return recovered;
+
+        }
+
+    }
+
+    /**
+     * Lanza un proceso de descubrimiento asíncrono del device
+     */
+    public void launchDiscovery() {
+        logger.trace("ZigbeeDeviceImpl::launchDiscovery()");
+        final ZigbeeDeviceImpl device = this;
+        // creamos tarea a ejecutar
+        Runnable target = new Runnable() {
+
+            @Override
+            public void run() {
+                // lanzamos el proceso de descubrimiento
+                device.discover();
+            }
+        };
+        // creamos el hilo y lo arracamos
+        Thread th = new Thread(target, "Discovery task for device " + this);
+        th.start();
+    }
+
+    /**
+     * Actualiza el status, y lanza la notificación correspondiente
+     * @param status 
+     */
+    public void setStatus(DeviceStatus status) {
+        logger.trace(String.format("ZigbeeDeviceImpl::setStatus(status=%s)", status));
+        // guardamos el estado anterior y lo actualizamos
+        DeviceStatus oldStatus = this.status;
+        this.status = status;
+        // comprobamos para notificar cambio de estado       
+        if (oldStatus != status) {
+            fireStatusChanged(status, oldStatus);
+        }
+    }
+
+    public void setProfileID(String profileID) {
+        logger.trace(String.format("ZigbeeDeviceImpl::setProfileID(profileID=%s)", profileID));
+        this.profileID = profileID;
+    }
+
+    public void setDeviceID(String deviceID) {
+        logger.trace(String.format("ZigbeeDeviceImpl::setDeviceID(deviceID=%s)", deviceID));
+        this.deviceID = deviceID;
+    }
+
+    public void setInClusterList(String[] inCluster) {
+        if (inCluster == null) {
+            logger.trace(String.format("ZigbeeDeviceImpl::setInClusterList(inCluster=%s)", inCluster));
+        } else {
+            logger.trace(String.format("ZigbeeDeviceImpl::setInClusterList(inCluster.length=%d)", inCluster.length));
+        }
+        inClusterList.clear();
+        if (inCluster != null) {
+            inClusterList.addAll(Arrays.asList(inCluster));
+        }
+    }
+
+    public void setOutClusterList(String[] outCluster) {
+        if (outCluster == null) {
+            logger.trace(String.format("ZigbeeDeviceImpl::setInClusterList(inCluster=%s)", outCluster));
+        } else {
+            logger.trace(String.format("ZigbeeDeviceImpl::setInClusterList(inCluster.length=%d)", outCluster.length));
+        }
+        outClusterList.clear();
+        if (outCluster != null) {
+            outClusterList.addAll(Arrays.asList(outCluster));
+        }
+    }
+
+    @Override
+    public short getEndPoint() {
+        return endPoint;
+    }
+
+    @Override
+    public String getProfileId() {
+        return profileID;
+    }
+
+    @Override
+    public String getDeviceId() {
+        return deviceID;
+    }
+
+    @Override
+    public String[] getInClusterList() {
+        return inClusterList.toArray(new String[0]);
+    }
+
+    @Override
+    public String[] getOutClusterList() {
+        return outClusterList.toArray(new String[0]);
+    }
+
+    @Override
+    public ZigbeeNode getZigbeeNode() {
+        return node;
+    }
+
+    @Override
+    public DeviceStatus getStatus() {
+        return status;
+    }
+
+    @Override
+    public boolean sendMessage(String profileID, String clusterID, byte[] message) {
+        logger.trace(String.format("ZigbeeDeviceImpl::sendMessage(profileID=%s, clusterID=%s, message=%s)", profileID, clusterID, message));
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(DeviceStatus.Busy);
+
+            // enviamos el mensaje
+            boolean sendResult = driver.sendMessage(this, profileID, clusterID, message);
+
+            // actualizamos el estado
+            setStatus(DeviceStatus.Ready);
+
+            // comprobamos error
+            if (sendResult) {
+                resetErrorCount();
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos resultado
+            return sendResult;
+
+        }
+
+    }
+
+    @Override
+    public String toString() {
+        return String.format("[%02X@%s]", endPoint, node.getEUI64Addr().toFormattedString());
+    }
+
+    /**
+     * Función para procesar la recepción de un mensaje dirigido al EndPoint
+     * @param profileID  
+     * @param clusterID 
+     * @param message 
+     */
+    public void receiveMessage(String profileID, String clusterID, byte[] message) {
+        logger.trace("ZigbeeDeviceImpl::receiveMessage(message=" + message + ")");
+        // notificamos a los listeners la recepción del mensaje
+        fireMessageReceived(profileID, clusterID, message);
+
+    }
+    // <editor-fold defaultstate="collapsed" desc="GESTION LISTENERS">
+    final ArrayList<ZigbeeDeviceListener> listeners = new ArrayList<ZigbeeDeviceListener>();
+    final HashMap<ZigbeeDeviceListener, Executor> executors = new HashMap<ZigbeeDeviceListener, Executor>();
+
+    @Override
+    public void registerListener(ZigbeeDeviceListener lstnr) {
+        logger.trace(String.format("ZigbeeDeviceImpl::registerListener(lstnr=%s)", lstnr));
+        synchronized (listeners) {
+            if (listeners.add(lstnr)) {
+                Executor ex = Executors.newSingleThreadExecutor();
+                executors.put(lstnr, ex);
+            }
+        }
+    }
+
+    @Override
+    public void unregisterListener(ZigbeeDeviceListener lstnr) {
+        logger.trace(String.format("ZigbeeDeviceImpl::unregisterListener(lstnr=%s)", lstnr));
+        synchronized (listeners) {
+            if (listeners.remove(lstnr)) {
+                executors.remove(lstnr);
+            }
+        }
+    }
+
+    /**
+     * Notifies about message recieved by a ZigbeeDevice, 
+     * @param message Message received
+     */
+    protected void fireMessageReceived(final String profileID, final String clusterID, final byte[] message) {
+        logger.trace("ZigbeeDeviceImpl::fireMessageReceived(profileID=" + profileID + ", clusterID=" + clusterID + ",message=" + message + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final ZigbeeDevice device = this;
+            while (it.hasNext()) {
+                final ZigbeeDeviceListener lstnr = (ZigbeeDeviceListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.messageReceived(profileID, clusterID, message, device);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+
+    /**
+     * Notifies about status changed on a ZigbeeDevice, 
+     * @param status current status
+     * @param oldStatus previous status
+     */
+    protected void fireStatusChanged(final ZigbeeDevice.DeviceStatus status, final ZigbeeDevice.DeviceStatus oldStatus) {
+        logger.trace("ZigbeeDeviceImpl::fireStatusChanged(status=" + status + ", oldStatus=" + oldStatus + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final ZigbeeDevice device = this;
+            while (it.hasNext()) {
+                final ZigbeeDeviceListener lstnr = (ZigbeeDeviceListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.statusChanged(status, oldStatus, device);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                ex.execute(launcher);
+            }
+        }
+    }
+    // </editor-fold>
+    // <editor-fold defaultstate="collapsed" desc="GESTION ERRORES">
+    private int errorCount = 0;
+
+    /**
+     * Incrementa el número de errores del dispositivo
+     */
+    public void addErrorCount() {
+        logger.trace("ZigbeeDeviceImpl::addErrorCount()");
+        errorCount += 1;
+
+        //Si el número de errores supera el umbral de error, marcamos estado de error
+        if (errorCount > ((AbstractDriver) driver).CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1) {
+            setStatus(DeviceStatus.Error);
+        }
+        //NOTA: la gestion de los errores se realiza en una tarea de mantenimiento
+
+    }
+
+    /**
+     * Devuelve el numero de errores del dispositivo
+     * @return 
+     */
+    public int getErrorCount() {
+        logger.trace("ZigbeeDeviceImpl::getErrorCount()");
+        return errorCount;
+    }
+
+    /**
+     * Restablece a cero el número de errores del dispositivo
+     */
+    public void resetErrorCount() {
+        logger.trace("ZigbeeDeviceImpl::resetErrorCount()");
+        errorCount = 0;
+        // restablecemos el estado
+        if (status == DeviceStatus.Error) {
+            setStatus(DeviceStatus.Ready);
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeNodeImpl.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeNodeImpl.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/ZigbeeNodeImpl.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,761 @@
+/*
+ * 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.driver.impl;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNodeListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.util.Register305;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.EUI64Address;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.NetworkAddress;
+import es.unizar.howlab.core.zigbee.telegesis.driver.util.ZigbeeNodeType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Alvaro
+ */
+public class ZigbeeNodeImpl implements ZigbeeNode {
+
+    private ZigbeeNodeType type;
+    private EUI64Address address;
+    private NetworkAddress nodeID;
+    private String regPassword = "password";
+    private NodeStatus status = NodeStatus.Unknown;
+    private int RSSI = 0;
+    private short LQI = 0;
+    // Relaciones entre nodos
+    private ZigbeeNode parent;
+    private ArrayList<ZigbeeNode> childrenList = new ArrayList<ZigbeeNode>();
+    private ArrayList<ZigbeeNode> neighbourList = new ArrayList<ZigbeeNode>();
+    private ArrayList<ZigbeeNode> route = new ArrayList<ZigbeeNode>();
+    // endPoints
+    private ArrayList<ZigbeeDevice> zigbeeDevices = new ArrayList<ZigbeeDevice>();
+    // valores para registros
+    HashMap<String, String> registers = new HashMap<String, String>();
+    final Driver driver;
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public ZigbeeNodeImpl(Driver driver) {
+        logger.trace("ZigbeeNodeImpl::ZigbeeNodeImpl(driver=" + driver + ")");
+        this.driver = driver;
+
+        // inicializamos la lista de registros
+        for (Register305 r : Register305.values()) {
+            registers.put(String.format("%02X", r.getAddress()), null);
+        }
+    }
+
+    /**
+     * Lanza una busqueda de EndPoints del Nodo
+     * @return True si finaliza el proceso correctamente, false en otro caso
+     */
+    @Override
+    public boolean discoverZigbeeDevices() {
+        logger.trace("ZigbeeNodeImpl::discoverZigbeeDevices()");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Discovering);
+
+            // lanzamos la consulta de endPoints del nodo
+            boolean requestResult = driver.updateActiveEndPoints(this);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (requestResult) {
+                resetErrorCount();
+            } else {
+                //addErrorCount();
+                return false;
+            }
+
+            // devolvemos el resultado
+            return requestResult;
+
+        }
+
+    }
+
+    /**
+     * Lanza una busqueda de vecinos del Nodo.
+     * Nota: si el nodo es un RFD, no puede tener vecinos, por lo que no se 
+     * lanza la busqueda, y en este caso se devuelve resultado OK
+     * @return True si finaliza el proceso correctamente, false en otro caso
+     */
+    @Override
+    public boolean discoverNeighbours() {
+        logger.trace("ZigbeeNodeImpl::discoverNeighbours()");
+
+        // comprobamos tipo de nodo
+        switch (this.type) {
+            case EndDevice:
+            case SleepyEndDevice:
+            case MobileEndDevice:
+                return true;
+        }
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Discovering);
+
+            // lanzamos la consulta de endPoints del nodo
+            boolean requestResult = driver.updateNeighbourTable(this);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (requestResult) {
+                resetErrorCount();
+            } else {
+                //addErrorCount();
+                return false;
+            }
+
+            // devolvemos el resultado
+            return requestResult;
+
+        }
+
+    }
+
+    /**
+     * Lanza una busqueda del padre del nodo.
+     * @return True si finaliza el proceso correctamente, false en otro caso
+     */
+    @Override
+    public boolean discoverParent() {
+        logger.trace("ZigbeeNodeImpl::discoverParent()");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Discovering);
+
+            // lanzamos la consulta del padre            
+            String parentEUI = readRegister(Register305.PARENT_EUI.getAddress());
+
+            boolean requestResult;
+            if (parentEUI == null) {
+                requestResult = false;
+            } else {
+                requestResult = true;
+                setParent(driver.getNode(parentEUI));
+            }
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (requestResult) {
+                resetErrorCount();
+            } else {
+                //addErrorCount();
+            }
+
+            // devolvemos el resultado
+            return requestResult;
+
+        }
+
+    }
+
+    /**
+     * Lanza un proceso de recovery en el nodo
+     * @return True si finaliza el proceso correctamente, false en otro caso
+     */
+    @Override
+    public boolean recover() {
+        logger.trace("ZigbeeNodeImpl::recover()");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Recovering);
+
+            //Buscamos la ruta al nodo
+            boolean recovered = driver.findRoute(this);
+
+            // comprobamos resultado del recovery
+            if (recovered) {
+                resetErrorCount(); // esto actualiza el estado
+            } else {
+                addErrorCount(); // esto actualiza el estado
+            }
+
+            // devolvemos resultado
+            return recovered;
+
+        }
+
+    }
+
+    /**
+     * Lanza un proceso de descubrimiento asíncrono de los vecinos del nodo
+     */
+    public void launchNeighbourDiscovery() {
+        logger.trace("ZigbeeNodeImpl::launchNeighbourDiscovery()");
+        final ZigbeeNodeImpl node = this;
+        // creamos tarea a ejecutar
+        Runnable target = new Runnable() {
+
+            @Override
+            public void run() {
+                node.discoverNeighbours();
+            }
+        };
+        // creamos el hilo y lo arracamos
+        Thread th = new Thread(target, "Neighbour update for node " + node);
+        th.start();
+
+    }
+
+    /**
+     * Lanza un proceso de descubrimiento asíncrono del nodo
+     */
+    public void launchDiscovery() {
+        logger.trace("ZigbeeNodeImpl::launchDiscovery()");
+        final ZigbeeNodeImpl node = this;
+        // creamos tarea a ejecutar
+        Runnable target = new Runnable() {
+
+            @Override
+            public void run() {
+                // lanzamos el proceso de descubrimiento
+                node.discoverZigbeeDevices();
+            }
+        };
+        // creamos el hilo y lo arracamos
+        Thread th = new Thread(target, "Discovery task for node " + this);
+        th.start();
+    }
+
+    /**
+     * Actualiza el status, y lanza la notificación correspondiente
+     * @param status 
+     */
+    public void setStatus(NodeStatus status) {
+        logger.trace(String.format("ZigbeeNodeImpl::setStatus(status=%s)", status));
+        // guardamos el estado anterior y lo actualizamos
+        NodeStatus oldStatus = this.status;
+        this.status = status;
+        // comprobamos para notificar cambio de estado       
+        if (oldStatus != status) {
+            fireStatusChanged(status, oldStatus);
+        }
+    }
+
+    public void setType(ZigbeeNodeType type) {
+        logger.trace(String.format("ZigbeeNodeImpl::setType(type=%s)", type));
+        this.type = type;
+    }
+
+    public void setAddress(EUI64Address address) {
+        logger.trace(String.format("ZigbeeNodeImpl::setAddress(address=%s)", address));
+        this.address = address;
+    }
+
+    public void setNodeID(NetworkAddress nodeID) {
+        logger.trace(String.format("ZigbeeNodeImpl::setNodeID(nodeID=%s)", nodeID));
+        this.nodeID = nodeID;
+    }
+
+    public void setParent(ZigbeeNode parent) {
+        logger.trace(String.format("ZigbeeNodeImpl::setParent(parent=%s)", parent));
+        this.parent = parent;
+    }
+
+    public void setRSSI(int RSSI) {
+        logger.trace(String.format("ZigbeeNodeImpl::setRSSI(RSSI=%s)", RSSI));
+        this.RSSI = RSSI;
+    }
+
+    public void setLQI(short LQI){
+        logger.trace(String.format("ZigbeeNodeImpl::setLQI(LQI=%s)", LQI));
+        this.LQI = LQI;        
+    }
+
+    /**
+     * Añade un nodo a la lista de vecinos o hijos según sea FFD o RFD
+     * @param node 
+     */
+    public void addNode(ZigbeeNode node) {
+        logger.trace(String.format("ZigbeeNodeImpl::addNode(node=%s)", node));
+        // comprobamos el tipo de nodo
+        switch (node.getType()) {
+            case Coordinator:
+            case Router:
+                addNeighbour(node);
+                break;
+            default:
+                addChild(node);
+                break;
+        }
+
+    }
+
+    /**
+     * Elimina un nodo de la lista de vecinos o hijos según sea FFD o RFD
+     * @param node 
+     */
+    public void removeNode(ZigbeeNode node) {
+        logger.trace(String.format("ZigbeeNodeImpl::removeNode(node=%s)", node));
+        // comprobamos el tipo de nodo
+        switch (node.getType()) {
+            case Coordinator:
+            case Router:
+                ((ZigbeeNodeImpl) node).removeNeighbour(node);
+                break;
+            default:
+                ((ZigbeeNodeImpl) node).removeChild(node);
+                break;
+        }
+
+    }
+
+    public void setNeighbours(ZigbeeNode[] neighbours) {
+        logger.trace(String.format("ZigbeeNodeImpl::setNeighbours(neighbours=%s)", neighbours));
+        this.neighbourList.clear();
+        this.neighbourList.addAll(Arrays.asList(neighbours));
+    }
+
+    public void addNeighbour(ZigbeeNode neighbour) {
+        logger.trace(String.format("ZigbeeNodeImpl::addNeighbour(neighbour=%s)", neighbour));
+        if (!neighbourList.contains(neighbour)) {
+            neighbourList.add(neighbour);
+        }
+    }
+
+    public void removeNeighbour(ZigbeeNode neighbour) {
+        logger.trace(String.format("ZigbeeNodeImpl::removeNeighbour(neighbour=%s)", neighbour));
+        if (neighbourList.contains(neighbour)) {
+            neighbourList.remove(neighbour);
+        }
+    }
+
+    public void setChildren(ZigbeeNode[] children) {
+        logger.trace(String.format("ZigbeeNodeImpl::setChildren(children=%s)", children));
+        this.childrenList.clear();
+        this.childrenList.addAll(Arrays.asList(children));
+    }
+
+    public void addChild(ZigbeeNode child) {
+        logger.trace(String.format("ZigbeeNodeImpl::addChild(child=%s)", child));
+        if (!childrenList.contains(child)) {
+            childrenList.add(child);
+        }
+    }
+
+    public void removeChild(ZigbeeNode child) {
+        logger.trace(String.format("ZigbeeNodeImpl::removeChild(child=%s)", child));
+        if (childrenList.contains(child)) {
+            childrenList.remove(child);
+        }
+    }
+
+    public void setRoute(ZigbeeNode[] route) {
+        logger.trace(String.format("ZigbeeNodeImpl::setRoute(route=%s)", route));
+        this.route.clear();
+        this.route.addAll(Arrays.asList(route));
+    }
+
+    public void setZigbeeDevices(ZigbeeDevice[] devices) {
+        logger.trace(String.format("ZigbeeNodeImpl::setZigbeeDevices(devices=%s)", devices));
+        this.zigbeeDevices.clear();
+        this.zigbeeDevices.addAll(Arrays.asList(devices));
+    }
+
+    public void addZigbeeDevice(ZigbeeDevice device) {
+        logger.trace(String.format("ZigbeeNodeImpl::addZigbeeDevice(device=%s)", device));
+        this.zigbeeDevices.add(device);
+    }
+
+    public void removeZigbeeDevice(ZigbeeDevice device) {
+        logger.trace(String.format("ZigbeeNodeImpl::removeZigbeeDevice(device=%s)", device));
+        this.zigbeeDevices.remove(device);
+    }
+
+    /**
+     * Establece la contraseña de escritura de registros
+     * @param newPassword 
+     */    
+    public void setRegisterPassword(String newPassword){
+        regPassword = newPassword;
+    }
+    
+    /**
+     * Actualiza la contraseña de escritura de los registros en el nodo
+     * @param newPassword 
+     * @return 
+     */
+    public boolean updateRegisterPassword(String newPassword){
+        logger.trace("ZigbeeNodeImpl::updateRegisterPassword(newPassword=" + newPassword + ")");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Busy);
+            
+            short regAddress = Register305.PASSWORD.getAddress();
+
+            // escribimos el registro
+            boolean writeResult = driver.writeRegister(this,regAddress, newPassword);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (writeResult) {
+                // guardamos el valor del registro
+                registers.put(String.format("%02X", regAddress), newPassword);
+                regPassword = newPassword;
+                resetErrorCount();
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos resultado
+            return writeResult;
+
+        }
+        
+    }
+    
+    public String getRegisterPassword(){
+        return regPassword;
+    }
+    
+    @Override
+    public NodeStatus getStatus() {
+        return status;
+    }
+
+    @Override
+    public ZigbeeNodeType getType() {
+        return type;
+    }
+
+    @Override
+    public EUI64Address getEUI64Addr() {
+        return address;
+    }
+
+    @Override
+    public int getRSSI() {
+        return RSSI;
+    }
+
+    @Override
+    public short getLQI() {
+        return LQI;
+    }
+
+    @Override
+    public NetworkAddress getNodeID() {
+        return nodeID;
+    }
+
+    @Override
+    public ZigbeeDevice[] getZigbeeDevices() {
+        logger.trace(String.format("ZigbeeNodeImpl::getZigbeeDevices()"));
+        return zigbeeDevices.toArray(new ZigbeeDevice[0]);
+    }
+
+    @Override
+    public ZigbeeDevice getZigbeeDevice(short endPoint) {
+        logger.trace(String.format("ZigbeeNodeImpl::getZigbeeDevice(endPoint=%s)", endPoint));
+        for (int i = 0; i < zigbeeDevices.size(); i++) {
+            ZigbeeDevice ep = zigbeeDevices.get(i);
+            if (ep.getEndPoint() == endPoint) {
+                return ep;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ZigbeeNode[] getNeighbours() {
+        return neighbourList.toArray(new ZigbeeNode[0]);
+    }
+
+    @Override
+    public ZigbeeNode getParent() {
+        return parent;
+    }
+
+    @Override
+    public ZigbeeNode[] getChildren() {
+        ZigbeeNode[] nodes = new ZigbeeNode[childrenList.size()];
+        return childrenList.toArray(nodes);
+    }
+
+    @Override
+    public ZigbeeNode[] getRoute() {
+        ZigbeeNode[] nodes = new ZigbeeNode[route.size()];
+        return route.toArray(nodes);
+    }
+
+    @Override
+    public boolean sendMessage(byte[] message) {
+        logger.trace("ZigbeeNodeImpl::sendMessage(message=" + message + ")");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Busy);
+
+            // enviamos el mensaje
+            boolean sendResult = driver.sendMessage(this, message);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (sendResult) {
+                resetErrorCount();
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos resultado
+            return sendResult;
+
+        }
+
+    }
+
+    @Override
+    public String readRegister(short regAddress) {
+        logger.trace("ZigbeeNodeImpl::readRegister(regAddress=" + regAddress + ")");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Busy);
+
+            // Leemos el registro
+            String data = driver.readRegister(this, regAddress);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (data != null) {
+                resetErrorCount();
+                // guardamos el valor del registro
+                registers.put(String.format("%02X", regAddress), data);
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos resultado
+            return data;
+
+        }
+
+    }
+
+    @Override
+    public String getRegister(short regAddress) {
+        logger.trace("ZigbeeNodeImpl::getRegister(regAddress=" + regAddress + ")");
+
+        // devolvemos el valor almacenado del registro
+        return registers.get(String.format("%02X", regAddress));
+
+    }
+
+    @Override
+    public HashMap<String, String> getRegisters() {
+        logger.trace("ZigbeeNodeImpl::getRegisters()");
+
+        // devolvemos una copia de la lista de registros
+        return (HashMap<String, String>) registers.clone();
+
+    }
+
+    @Override
+    public boolean writeRegister(short regAddress, String data) {
+        logger.trace("ZigbeeNodeImpl::writeRegister(regAddress=" + regAddress + ", data=" + data + ")");
+
+        synchronized (this) {
+            // actualizamos el estado
+            setStatus(NodeStatus.Busy);
+
+            // escribimos el registro
+            boolean writeResult = driver.writeRegister(this, regAddress, data);
+
+            // actualizamos el estado
+            setStatus(NodeStatus.Ready);
+
+            // comprobamos error
+            if (writeResult) {
+                // guardamos el valor del registro
+                registers.put(String.format("%02X", regAddress), data);
+                resetErrorCount();
+            } else {
+                addErrorCount();
+            }
+
+            // devolvemos resultado
+            return writeResult;
+
+        }
+
+    }
+
+    @Override
+    public String toString() {
+        return "[" + address.toFormattedString() + "]";
+    }
+
+    /**
+     * Función para procesar la recepción de un mensaje dirigido al EndPoint
+     * @param message 
+     */
+    public void receiveMessage(byte[] message) {
+        logger.trace("ZigbeeNodeImpl::receiveMessage(message=" + message + ")");
+        // notificamos a los listeners la recepción del mensaje
+        fireMessageReceived(message);
+
+    }
+    // <editor-fold defaultstate="collapsed" desc="GESTION LISTENERS">
+    final ArrayList<ZigbeeNodeListener> listeners = new ArrayList<ZigbeeNodeListener>();
+    final HashMap<ZigbeeNodeListener, Executor> executors = new HashMap<ZigbeeNodeListener, Executor>();
+
+    @Override
+    public void registerListener(ZigbeeNodeListener lstnr) {
+        logger.trace(String.format("ZigbeeNodeImpl::registerListener(lstnr=%s)", lstnr));
+        synchronized (listeners) {
+            if (listeners.add(lstnr)) {
+                Executor ex = Executors.newSingleThreadExecutor();
+                executors.put(lstnr, ex);
+            }
+        }
+    }
+
+    @Override
+    public void unregisterListener(ZigbeeNodeListener lstnr) {
+        logger.trace(String.format("ZigbeeNodeImpl::unregisterListener(lstnr=%s)", lstnr));
+        synchronized (listeners) {
+            if (listeners.remove(lstnr)) {
+                executors.remove(lstnr);
+            }
+        }
+    }
+
+    /**
+     * Notifies about message recieved by a ZigbeeNode, 
+     * @param message Message received
+     */
+    protected void fireMessageReceived(final byte[] message) {
+        logger.trace("ZigbeeNodeImpl::fireMessageReceived(message=" + message + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final ZigbeeNode device = this;
+            while (it.hasNext()) {
+                final ZigbeeNodeListener lstnr = (ZigbeeNodeListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.messageReceived(message, device);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                if (ex!= null){
+                    ex.execute(launcher);                    
+                }
+            }
+        }
+    }
+
+    /**
+     * Notifies about status changed on a ZigbeeNode, 
+     * @param status current status
+     * @param oldStatus previous status
+     */
+    protected void fireStatusChanged(final ZigbeeNode.NodeStatus status, final ZigbeeNode.NodeStatus oldStatus) {
+        logger.trace("ZigbeeNodeImpl::fireStatusChanged(status=" + status + ", oldStatus=" + oldStatus + ")");
+        synchronized (listeners) {
+            // declaramos los parámetros como final para poder acceder desde la clase anónima
+            Iterator it = listeners.iterator();
+            final ZigbeeNode node = this;
+            while (it.hasNext()) {
+                final ZigbeeNodeListener lstnr = (ZigbeeNodeListener) it.next();
+                Runnable launcher = new Runnable() {
+
+                    @Override
+                    public void run() {
+                        lstnr.statusChanged(status, oldStatus, node);
+                    }
+                };
+                Executor ex = executors.get(lstnr);
+                if (ex!= null){
+                    ex.execute(launcher);                    
+                }
+            }
+        }
+    }
+    // </editor-fold>
+    // <editor-fold defaultstate="collapsed" desc="GESTION ERRORES">
+    private int errorCount = 0;
+
+    /**
+     * Incrementa el número de errores del dispositivo
+     */
+    public void addErrorCount() {
+        logger.trace("ZigbeeNodeImpl::addErrorCount()");
+        errorCount += 1;
+
+        //Si el número de errores supera el umbral de error, marcamos estado de error
+        if (errorCount > ((AbstractDriver) driver).CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1) {
+            setStatus(NodeStatus.Error);
+        }
+        //NOTA: la gestion de los errores se realiza en una tarea de mantenimiento
+
+    }
+
+    /**
+     * Devuelve el numero de errores del dispositivo
+     * @return 
+     */
+    public int getErrorCount() {
+        logger.trace("ZigbeeNodeImpl::getErrorCount()");
+        return errorCount;
+    }
+
+    /**
+     * Restablece a cero el número de errores del dispositivo
+     */
+    public void resetErrorCount() {
+        logger.trace("ZigbeeNodeImpl::resetErrorCount()");
+        errorCount = 0;
+        // restablecemos el estado
+        if (status == NodeStatus.Error) {
+            setStatus(NodeStatus.Ready);
+        }
+    }
+    // </editor-fold>
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/AbstractDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/AbstractDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/AbstractDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,559 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver.DriverStatus;
+import es.unizar.howlab.core.zigbee.telegesis.driver.DriverListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+abstract public class AbstractDriverMaintenanceTask implements DriverListener {
+
+    Driver driver;
+    boolean enabled = true;
+    ArrayList startTargets = new ArrayList();
+    ArrayList busyTargets = new ArrayList();
+    ArrayList failedTargets = new ArrayList();
+    ArrayList idleTargets = new ArrayList();
+    private final String taskName;
+    // Logger  
+    private Log logger = LogFactory.getLog(this.getClass().getName());
+    long frameDelay;
+    boolean maintenance;
+    long maintenanceTime;
+    boolean recover;
+    long recoveryTime;
+    boolean pauseOnNetworkLeft;
+    boolean wasRunning;
+
+    /**
+     * Constructor
+     * @param taskName Nombre para la tarea (a efectos de logging)
+     * @param maintenance Indica si se crea tarea de mantenimiento
+     * @param recover Indica si se crea tarea de recuperacion (reintentar)
+     * @param pauseOnNetworkLeft Indica si se pausa la tarea al desconectarse de la red
+     */
+    public AbstractDriverMaintenanceTask(String taskName, boolean maintenance, boolean recover, boolean pauseOnNetworkLeft) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask::AbstractDriverMaintenanceTask(taskName=%s, maintenance=%s, recover=%s, pauseOnNetworkLeft=%s)", taskName, maintenance, recover, pauseOnNetworkLeft));
+
+        this.taskName = taskName;
+        this.recover = recover;
+        this.maintenance = maintenance;
+        this.pauseOnNetworkLeft = pauseOnNetworkLeft;
+    }
+
+    /**
+     * Establece el periodo de separacion entre nodos para las operaciones
+     * @param frameDelay Tiempo de separacion, en segundos
+     */
+    public void setFrameDelay(long frameDelay) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::setFrameDelay(frameDelay=%d)", taskName, frameDelay));
+        this.frameDelay = frameDelay * 1000;
+        if (startingTask != null) {
+            startingTask.setTiming(0, this.frameDelay);
+        }
+        if (recoveryTask != null) {
+            recoveryTask.setTiming(this.recoveryTime, this.frameDelay);
+        }
+        if (maintenanceTask != null) {
+            maintenanceTask.setTiming(this.maintenanceTime, this.frameDelay);
+        }
+    }
+
+    /**
+     * Establece el periodo de mantenimiento de la operacion
+     * @param maintenanceTime Periodo de mantenimiento(en minutos)
+     */
+    public void setMaintenanceTime(long maintenanceTime) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::setMaintenanceTime(maintenanceTime=%d)", taskName, maintenanceTime));
+        this.maintenanceTime = maintenanceTime * 60 * 1000;
+        if (maintenanceTask != null) {
+            maintenanceTask.setTiming(this.maintenanceTime, this.frameDelay);
+        }
+    }
+
+    /**
+     * Establece el periodo de reintento para operaciones fallidas
+     * @param recoveryTime Periodo de reintento (en minutos)
+     */
+    public void setRecoveryTime(long recoveryTime) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::setRecoveryTime(recoveryTime=%d)", taskName, recoveryTime));
+        this.recoveryTime = recoveryTime * 60 * 1000;
+        if (recoveryTask != null) {
+            recoveryTask.setTiming(this.recoveryTime, this.frameDelay);
+        }
+    }
+
+    private class MaintenanceTask implements Runnable {
+
+        protected ArrayList targetList;
+        protected long period;
+        protected long frameDelay;
+        protected boolean running = false;
+        protected Thread currentThread = null;
+        protected HashMap<Object, Timer> timers = new HashMap<Object, Timer>();
+        protected final String mTaskName;
+
+        /**
+         * Constructor
+         * @param mTaskName nombre de la tarea (a efectos de logging)
+         * @param period Periodo de ejecución de la tarea
+         * @param frameDelay Periodo de separación entre nodos
+         * @param targetList Lista de nodos a mantener
+         */
+        public MaintenanceTask(String mTaskName, long period, long frameDelay, ArrayList targetList) {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask.MaintenanceTask(mTaskName=%s, period=%d, frameDelay=%d, nodes=%s)", taskName, mTaskName, period, frameDelay, targetList));
+            this.mTaskName = mTaskName;
+            this.targetList = targetList;
+            this.period = period;
+            this.frameDelay = frameDelay;
+        }
+
+        public void setTiming(long period, long frameDelay) {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask[%s].setTiming(period=%d, frameDelay=%d)", taskName, mTaskName, period, frameDelay));
+            this.period = period;
+            this.frameDelay = frameDelay;
+            if (running) {
+                // si estamos en ejecución, interrumpimos el hilo para aplicar configuracion
+                currentThread.interrupt();
+            }
+
+        }
+
+        /**
+         * Detiene la tarea
+         */
+        public void stop() {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask[%s].stop()", taskName, mTaskName));
+            logger.debug(String.format("[Driver Maintenance Task: %s.%s] Stopping maintenance task...", taskName, mTaskName));
+            running = false;
+            currentThread.interrupt();
+            // esperamoas a que termine el hilo
+            try {
+                currentThread.join();
+            } catch (InterruptedException ex) {
+            }
+            logger.debug(String.format("[Driver Maintenance Task: %s.%s] Maintenance task stopped", taskName, mTaskName));
+        }
+
+        /**
+         * Inicia la tarea
+         */
+        public void start() {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask[%s].start()", taskName, mTaskName));
+
+            logger.debug(String.format("[Driver Maintenance Task: %s.%s] Starting maintenance task", taskName, mTaskName));
+            // Creamos el hilo
+            currentThread = new Thread(this, String.format("[Driver Maintenance Task: %s.%s] ", taskName, mTaskName));
+            currentThread.start();
+
+        }
+
+        public void cancelTaskForTarget(Object target) {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask[%s].cancelTaskForTarget(target=%s)", taskName, mTaskName, target));
+
+
+            // recuperamos el timer
+            Timer tm = timers.get(target);
+            if (tm != null) {
+                logger.info(String.format("[Driver Maintenance Task: %s.%s] Cancel task for target %s", taskName, mTaskName, target));
+                tm.cancel();
+            }
+
+        }
+
+        @Override
+        public void run() {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::MaintenanceTask[%s].run()", taskName, mTaskName));
+
+            // Inicializamos los tiempos
+            long wakeUpTime = System.currentTimeMillis() + period;
+
+            // guardamos el thread
+            if (currentThread == null) {
+                currentThread = Thread.currentThread();
+            }
+            // lanzamos un bucle infinito
+            running = true;
+            while (running) {
+                try {
+                    // calculamos el siguiente instante de activacion y paramos el hilo
+                    wakeUpTime = wakeUpTime + period;
+                    long sleepTime = Math.max(wakeUpTime - System.currentTimeMillis(), 0);
+                    logger.debug(String.format("[Driver Maintenance Task: %s.%s] Task loop will resume on %d milliseconds", taskName, mTaskName, sleepTime));
+                    Thread.sleep(sleepTime);
+                    logger.info(String.format("[Driver Maintenance Task: %s.%s] Task loop resumed", taskName, mTaskName));
+
+                    // si hay algún timer corriendo, lo paramos
+                    for (Timer tm : timers.values()) {
+                        tm.cancel();
+                    }
+                    // y borramos la lista
+                    timers.clear();
+
+                    // Recorremos todos los nodos
+                    for (int i = 0; i < targetList.size(); i++) {
+                        // recuperamos el nodo
+                        Object target = targetList.get(i);
+                        // programamos tarea
+                        Timer tm = scheduleTask(target, frameDelay * i);
+                        // guardamos el timer
+                        timers.put(target, tm);
+                    }
+
+                } catch (InterruptedException ex) {
+                    logger.debug(String.format("[Driver Maintenance Task: %s.%s] Task loop interrupted", taskName, mTaskName));
+                    // no hacemos nada, sólo se interrumpe este hilo para pararlo
+                }
+            }
+            logger.debug(String.format("[Driver Maintenance Task: %s.%s] Task loop finished", taskName, mTaskName));
+
+            // si hay algún timer corriendo, lo paramos
+            for (Timer tm : timers.values()) {
+                tm.cancel();
+            }
+            // y borramos la lista
+            timers.clear();
+        }
+    }
+
+    private class StartMaintenanceTask extends MaintenanceTask {
+
+        /**
+         * Constructor
+         * @param frameDelay Periodo de separación entre nodos
+         * @param targetList Lista de nodos a mantener
+         */
+        public StartMaintenanceTask(long frameDelay, ArrayList targetList) {
+            super("InitializacionTask", 1000, frameDelay, targetList);
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::StartMaintenanceTask.StartMaintenanceTask(frameDelay=%d, nodes=%s)", taskName, frameDelay, targetList));
+        }
+
+        @Override
+        public void run() {
+            logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::StartMaintenanceTask.run()", taskName));
+
+            // guardamos el thread
+            if (currentThread == null) {
+                currentThread = Thread.currentThread();
+            }
+            // Recorremos todos los nodos
+            for (int i = 0; i < targetList.size(); i++) {
+                // recuperamos el nodo
+                Object target = targetList.get(i);
+                // programamos tarea
+                Timer tm = scheduleTask(target, frameDelay * i);
+                // guardamos el timer
+                timers.put(target, tm);
+            }
+
+            // solo vamos a ejecutar la tarea una vez, pero damos la posibilidad de
+            // cancelar tareas programadas si no se han ejecutado todavía, deteniendo
+            // este hilo hasta que terminen todas
+            try {
+                long wakeUpTime = System.currentTimeMillis() + frameDelay * targetList.size();
+                long sleepTime = Math.max(wakeUpTime - System.currentTimeMillis(), 0);
+                logger.debug(String.format("[Driver Maintenance Task: %s.%s] Wating for task ends for %d milliseconds", taskName, mTaskName, sleepTime));
+                Thread.sleep(sleepTime);
+            } catch (InterruptedException ex) {
+                logger.info(String.format("[Driver Maintenance Task: %s.%s] Task loop interrupted, cancelling pending tasks", taskName, mTaskName));
+                // si hay algún timer corriendo, lo paramos
+                for (Timer tm : timers.values()) {
+                    tm.cancel();
+                }
+                // borramos la lista
+                timers.clear();
+            }
+
+        }
+    }
+    MaintenanceTask maintenanceTask;
+    MaintenanceTask recoveryTask;
+    StartMaintenanceTask startingTask;
+
+    public synchronized void start(Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::start(drv=%s)", taskName, drv));
+        // por si acaso ya teníamos un driver
+        if (driver != null) {
+            stop();
+        }
+        logger.info(String.format("[Driver Maintenance Task: %s] Starting maintenance task", taskName));
+        // guardamos el driver
+        driver = drv;
+
+        // nos registramos como Listener
+        driver.registerListener(this);
+
+        // marcamos ejecucion
+        wasRunning = true;
+
+        // iniciamos las tareas
+        resume();
+
+    }
+
+    private void resume() {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::resume()", taskName));
+
+        // creamos las tareas
+        if (maintenance) {
+            maintenanceTask = new MaintenanceTask("MaintenanceTask", maintenanceTime, frameDelay, idleTargets);
+            maintenanceTask.start();
+        }
+        if (recover) {
+            recoveryTask = new MaintenanceTask("RecoveryTask", recoveryTime, frameDelay, failedTargets);
+            recoveryTask.start();
+        }
+
+        // arrancamos la tareas con los nodos y devices actuales
+        for (ZigbeeNode node : driver.getNodes()) {
+            startTargets.add(node);
+            startTargets.addAll(Arrays.asList(node.getZigbeeDevices()));
+        }
+        startingTask = new StartMaintenanceTask(frameDelay, startTargets);
+        startingTask.start();
+
+
+    }
+
+    private void pause() {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::pause()", taskName));
+        // paramos las tareas
+        if (maintenance) {
+            maintenanceTask.stop();
+        }
+        if (recover) {
+            recoveryTask.stop();
+        }
+
+    }
+
+    public synchronized void stop() {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::stop()", taskName));
+
+        // comprobamos si teníamos un driver
+        if (driver != null) {
+            logger.info(String.format("[Driver Maintenance Task: %s] Stopping maintenance task", taskName));
+            // marcamos ejecucion
+            wasRunning = false;
+
+            // paramos las tareas
+            pause();
+
+            //desregistramos el driver
+            driver.unregisterListener(this);
+            driver = null;
+        }
+
+    }
+
+    /**
+     * Programa la tarea a ejecutar, retrasada en el tiempo indicado
+     * @param target objetivo de la operacion
+     * @param delay milisegundos de retardo
+     * @return el timer que lanzará la operacion
+     */
+    public synchronized Timer scheduleTask(final Object target, long delay) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::scheduleTask(target=%s, delay=%d)", taskName, target, delay));
+
+        // comprobamos que tenemos un driver para ejecutar la opreacion
+        if (driver == null) {
+            return null;
+        }
+
+        logger.info(String.format("[Driver Maintenance Task: %s] scheduling task execution for %s in %d milliseconds", taskName, target, delay));
+        // creamos una tarea para lanzar la busqueda
+        TimerTask tmTask = new TimerTask() {
+
+            @Override
+            public void run() {
+                // comprobamos si el target está en la lista de target ocupados
+                if (busyTargets.contains(target)) {
+                    logger.debug(String.format("[Driver Maintenance Task: %s] target %s already busy", taskName, target));
+                    // abandonamos la tarea
+                    return;
+                }
+
+                // añadimos el target a la lista de targets ocupados
+                busyTargets.add(target);
+
+                // lo eliminamos de las lista de targets que han finalizado
+                idleTargets.remove(target);
+                failedTargets.remove(target);
+
+                // lanzamos la operacion
+                logger.debug(String.format("[Driver Maintenance Task: %s] executing task for target %s", taskName, target));
+                boolean opRes = executeTask(target);
+                logger.debug(String.format("[Driver Maintenance Task: %s] executing task for target %s reports %s", taskName, target, (opRes ? "OK" : "FAIL")));
+
+                // Eliminamos el target de la lista de ocupados. Comprobamos si
+                // estaba en la lista, ya que si no estaba es porque el target ha
+                // sido eliminado, por lo que no hay que añadirlo al resto de 
+                // listas
+                if (busyTargets.remove(target)) {
+                    // comprobamos el resultado
+                    if (opRes) {
+                        idleTargets.add(target);
+                    } else {
+                        failedTargets.add(target);
+                    }
+                }
+
+            }
+        };
+
+        // creamos un timer para la tarea
+        Timer tm = new Timer();
+        tm.schedule(tmTask, delay);
+        return tm;
+
+    }
+
+    abstract protected boolean executeTask(Object target);
+
+    @Override
+    public void newNode(ZigbeeNode node, Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::newNode(node=%s, drv=%s)", taskName, node, drv));
+        // comprobamos driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // programamos la tarea en el nodo con delay=0
+        scheduleTask(node, 0);
+
+    }
+
+    @Override
+    public void newDevice(ZigbeeDevice device, Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::newDevice(device=%s, drv=%s)", taskName, device, drv));
+        // comprobamos driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // programamos la tarea en el device con delay=0
+        scheduleTask(device, 0);
+
+    }
+
+    @Override
+    public void nodeLeft(ZigbeeNode node, Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::nodeLeft(node=%s, drv=%s)", taskName, node, drv));
+        // comprobamos driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // eliminamos el nodo de la lista de objetivos
+        busyTargets.remove(node);
+        idleTargets.remove(node);
+        failedTargets.remove(node);
+
+        // cancelamos las tareas
+        if (recover) {
+            recoveryTask.cancelTaskForTarget(node);
+        }
+        if (maintenance) {
+            maintenanceTask.cancelTaskForTarget(node);
+        }
+
+    }
+
+    @Override
+    public void deviceLeft(ZigbeeDevice device, Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::deviceLeft(device=%s, drv=%s)", taskName, device, drv));
+        // comprobamos driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // eliminamos el device de la lista de objetivos
+        busyTargets.remove(device);
+        idleTargets.remove(device);
+        failedTargets.remove(device);
+
+        // cancelamos las tareas
+        if (recover) {
+            recoveryTask.cancelTaskForTarget(device);
+        }
+        if (maintenance) {
+            maintenanceTask.cancelTaskForTarget(device);
+        }
+
+
+    }
+
+    @Override
+    public void joinNetwork(int channel, String PANID, String EPID, Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::joinNetwork(channel=%s, PANID=%s, EPID=%s, drv=%s)", taskName, channel, PANID, EPID, drv));
+
+        // comprobamos el driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // comprobamos si hay que reanudar
+        if (wasRunning && pauseOnNetworkLeft) {
+            logger.info(String.format("[Driver Maintenance Task: %s] resuming task due to network join", taskName));
+            resume();
+        }
+    }
+
+    @Override
+    public void leftNetwork(Driver drv) {
+        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::leftNetwork(drv=%s)", taskName, drv));
+        // comprobamos el driver
+        if (!drv.equals(driver)) {
+            return;
+        }
+
+        // comprobamos si hay que parar
+        if (pauseOnNetworkLeft && wasRunning) {
+            logger.info(String.format("[Driver Maintenance Task: %s] pausing task due to network left", taskName));
+            pause();
+        }
+
+    }
+
+    @Override
+    public void statusChanged(DriverStatus status, DriverStatus oldStatus, Driver drv) {
+//        logger.trace(String.format("AbstractDriverMaintenanceTask[%s]::statusChanged(status=%s, oldStatus=%s, drv=%s)", status, oldStatus, drv));
+//        // comprobamos el driver
+//        if (!drv.equals(driver)) {
+//            return;
+//        }
+//
+//        // Si abandonamos el estado Running ==> paramos
+//        if (oldStatus == DriverStatus.Running) {
+//            stop();
+//        }
+        // Ignoramos esto para parar explícitamente las tareas, y tener control de cuando terminan
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ErrorCheckerDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ErrorCheckerDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ErrorCheckerDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,93 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.AbstractDriver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeDeviceImpl;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeNodeImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class ErrorCheckerDriverMaintenanceTask extends AbstractDriverMaintenanceTask {
+
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public ErrorCheckerDriverMaintenanceTask() {
+        // creamos la clase padre
+        super("ErrorChecker", true, true, true);
+        logger.trace(String.format("ErrorCheckerDriverMaintenanceTask::ErrorCheckerDriverMaintenanceTask()"));
+
+    }
+
+    @Override
+    protected boolean executeTask(Object target) {
+        logger.trace(String.format("ErrorCheckerDriverMaintenanceTask::executeTask(target=%s)", target));
+
+        // recuperamos la configuracion de los umbrales de error 
+        long errorThreshold1 = ((AbstractDriver) driver).CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_1;
+        long errorThreshold2 = ((AbstractDriver) driver).CONF_ZIGBEE_ERROR_LEVEL_THRESHOLD_2;
+
+        // comprobamos el tipo de dispositivo
+        if ((target instanceof ZigbeeNodeImpl)) {
+            // recuperamos el nodo
+            ZigbeeNodeImpl node = (ZigbeeNodeImpl) target;
+
+            // comprobamos el nivel de error
+            int errorLevel = node.getErrorCount();
+            if (errorLevel > errorThreshold2) {
+                // eliminamos el nodo
+                logger.info(String.format("[Driver Maintenance] Error level 2 (%d) on node %s. Removing node", errorLevel, target));
+                ((AbstractDriver) driver).removeNode(node);
+                return true; // esto hará que se elimine el nodo de las listas de mantenimiento
+            } else if (errorLevel > errorThreshold1) {
+                // lanzamos la operacion de recovery
+                logger.info(String.format("[Driver Maintenance] Error level 1 (%d) on node %s. Launching recovery", errorLevel, target));
+                return node.recover();
+
+            }
+
+            return true; // esto hará que marque la tarea como completada sin más
+        } else if ((target instanceof ZigbeeDeviceImpl)) {
+            // recuperamos el device
+            ZigbeeDeviceImpl device = (ZigbeeDeviceImpl) target;
+
+            // comprobamos el nivel de error
+            int errorLevel = device.getErrorCount();
+            if (errorLevel > errorThreshold2) {
+                // eliminamos el nodo
+                logger.info(String.format("[Driver Maintenance] Error level 2 (%d) on device %s. Removing device", errorLevel, target));
+                ((AbstractDriver) driver).removeDevice(device);
+                return true; // esto hará que se elimine el device de las listas de mantenimiento
+            } else if (errorLevel > errorThreshold1) {
+                // lanzamos la operacion de recovery
+                logger.info(String.format("[Driver Maintenance] Error level 1 (%d) on device %s. Launching recovery", errorLevel, target));
+                return device.recover();
+
+            }
+
+            return true; // esto hará que marque la tarea como completada sin más
+        } else {
+            return true; // esto hará que marque la tarea como completada sin más
+        }
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NeighbourFinderDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NeighbourFinderDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NeighbourFinderDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,61 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeNodeImpl;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class NeighbourFinderDriverMaintenanceTask extends AbstractDriverMaintenanceTask {
+
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public NeighbourFinderDriverMaintenanceTask() {
+        // creamos la clase padre
+        super("NeighbourFinder", true, true, true);
+        logger.trace(String.format("NeighbourFinderDriverMaintenanceTask::NeighbourFinderDriverMaintenanceTask()"));
+
+    }
+
+    @Override
+    protected boolean executeTask(Object target) {
+        logger.trace(String.format("NeighbourFinderDriverMaintenanceTask::executeTask(target=%s)", target));
+
+        // comprobamos que se trata de un ZigbeeNode
+        if (!(target instanceof ZigbeeNodeImpl)) {
+            return true; // esto hará que marque la tarea como completada sin más
+        }
+
+
+        // comprobamos el tipo de nodo
+        ZigbeeNodeImpl node = (ZigbeeNodeImpl) target;
+        switch (node.getType()) {
+            case Unknown:
+            case Coordinator:
+            case Router:
+                logger.info(String.format("[Driver Maintenance] Discovering neighbours for node %s", node));
+                return node.discoverNeighbours();
+            default:
+                return true;
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NodeRegisterUpdaterDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NodeRegisterUpdaterDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/NodeRegisterUpdaterDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,98 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.AbstractDriver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeNodeImpl;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class NodeRegisterUpdaterDriverMaintenanceTask extends AbstractDriverMaintenanceTask {
+
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+    // lista de reistros para reintentar
+    HashMap<ZigbeeNodeImpl, HashMap<String, String>> nodeRegisters = new HashMap<ZigbeeNodeImpl, HashMap<String, String>>();
+
+    public NodeRegisterUpdaterDriverMaintenanceTask() {
+        // creamos la clase padre
+        super("NodeRegisterUpdater", false, true, true);
+        logger.trace(String.format("NodeRegisterUpdaterDriverMaintenanceTask::NodeRegisterUpdaterDriverMaintenanceTask()"));
+
+    }
+
+    @Override
+    protected boolean executeTask(Object target) {
+        logger.trace(String.format("NodeRegisterUpdaterDriverMaintenanceTask::executeTask(target=%s)", target));
+
+        // comprobamos que se trata de un ZigbeeNode
+        if (!(target instanceof ZigbeeNodeImpl)) {
+            return true; // esto hará que marque la tarea como completada sin más
+        }
+
+        ZigbeeNodeImpl node = (ZigbeeNodeImpl) target;
+
+        logger.info(String.format("[Driver Maintenance] Writing registers for node %s", node));
+
+        // recuperamos la lista de registros
+        HashMap<String, String> registers = nodeRegisters.get(node);
+        if (registers == null) { // se trata de la primera llamada
+            // recuperamos la lista de registros del driver
+            ((AbstractDriver) driver).getNodeRegisterConfig(node.getEUI64Addr().toString());
+        }
+
+        // inicializamos la lista de registros pendientes
+        HashMap<String, String> pendingRegisters = new HashMap<String, String>();
+
+
+        // lanzamos la escritura de registros
+        Iterator it = registers.keySet().iterator();
+        while (it.hasNext()) {
+            // recuperamos el registro
+            String regStrAddr = (String) it.next();
+            String regValue = registers.get(regStrAddr);
+            short regAddr = (short) Integer.parseInt(regStrAddr, 16);
+            logger.info(String.format("[Driver Maintenance] Writing register %02X on node %s with value=%s", regAddr, node, regValue));
+            boolean writeResult = driver.writeRegister(node, regAddr, regValue);
+            // comprobamos resultado
+            if (!writeResult) {
+                logger.info(String.format("[Driver Maintenance] Error writing register %02X on node %s with value=%s. Will retry", regAddr, node, regValue));
+                // añadimos el registro para reintentarlo más tarde
+                pendingRegisters.put(regStrAddr, regValue);
+            }
+        }
+        // comprobamos si ha fallado algún registro
+        if (pendingRegisters.size() > 0) {
+            // guardamos los registros para escribirlos más tarde
+            nodeRegisters.put(node, pendingRegisters);
+
+            // devolvemos error
+            return false;
+        } else {
+            // devolvemos OK
+            return true;
+
+        }
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ParentFinderDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ParentFinderDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ParentFinderDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,53 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeNodeImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class ParentFinderDriverMaintenanceTask extends AbstractDriverMaintenanceTask {
+
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public ParentFinderDriverMaintenanceTask() {
+        // creamos la clase padre
+        super("ParentFinder", true, true, true);
+        logger.trace(String.format("ParentFinderDriverMaintenanceTask::ParentFinderDriverMaintenanceTask()"));
+
+    }
+
+    @Override
+    protected boolean executeTask(Object target) {
+        logger.trace(String.format("ParentFinderDriverMaintenanceTask::executeTask(target=%s)", target));
+
+        // comprobamos que se trata de un ZigbeeNode
+        if (!(target instanceof ZigbeeNodeImpl)) {
+            return true; // esto hará que marque la tarea como completada sin más
+        }
+
+        // lanzamos la busqueda de padres
+        logger.info(String.format("[Driver Maintenance] Discovering parent for node %s", target));
+        return ((ZigbeeNodeImpl) target).discoverParent();
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ZigbeeDevicesFinderDriverMaintenanceTask.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ZigbeeDevicesFinderDriverMaintenanceTask.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/maintenance/ZigbeeDevicesFinderDriverMaintenanceTask.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,57 @@
+/*
+ * 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.driver.impl.maintenance;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeDeviceImpl;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeNodeImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class ZigbeeDevicesFinderDriverMaintenanceTask extends AbstractDriverMaintenanceTask {
+
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public ZigbeeDevicesFinderDriverMaintenanceTask() {
+        // creamos la clase padre
+        super("ZigbeeDevicesFinder", false, true, true);
+        logger.trace(String.format("ZigbeeDevicesFinderDriverMaintenanceTask::ZigbeeDevicesFinderDriverMaintenanceTask()"));
+
+    }
+
+    @Override
+    protected boolean executeTask(Object target) {
+        logger.trace(String.format("ZigbeeDevicesFinderDriverMaintenanceTask::executeTask(target=%s)", target));
+
+        // comprobamos que se trata de un ZigbeeNode
+        if ((target instanceof ZigbeeNodeImpl)) {
+            // lanzamos la busqueda de endpoints
+            logger.info(String.format("[Driver Maintenance] Discovering ZigbeeDevices for node %s", target));
+            return ((ZigbeeNodeImpl) target).discoverZigbeeDevices();
+        } else if ((target instanceof ZigbeeDeviceImpl)) {
+            // lanzamos la busqueda del descriptor del device
+             logger.info(String.format("[Driver Maintenance] Discovering ZigbeeDevice descriptor for device %s", target));
+           return ((ZigbeeDeviceImpl) target).discover();
+        } else {
+            return true;// esto hará que marque la tarea como completada sin más
+        }
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/Activator.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/Activator.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/Activator.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,64 @@
+/*
+ * 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.driver.impl.osgi;
+
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+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.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+    private static BundleContext bc = null;
+    private ServiceTracker st = null;
+    GatewayServiceTracker 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 tracker para el Gateway que se encargará de crear los drivers
+        stc = new GatewayServiceTracker();
+        st = new ServiceTracker(bc, Gateway.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 CNXServiceTracker para despublicar los gateways
+        stc.stop();
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/GatewayServiceTracker.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/GatewayServiceTracker.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/GatewayServiceTracker.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,139 @@
+/*
+ * 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.driver.impl.osgi;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.DriverFactory;
+import es.unizar.howlab.core.zigbee.telegesis.driver.osgi.Constants;
+import es.unizar.howlab.core.zigbee.telegesis.gateway.Gateway;
+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 HowLab, University of Zaragoza (alvaro)
+ */
+public class GatewayServiceTracker implements ServiceTrackerCustomizer {
+
+    HashMap<ServiceReference, ServiceRegistration> gatewaysUsed = new HashMap<ServiceReference, ServiceRegistration>();
+    HashMap<Driver, ZigbeePublisher> zpList = new HashMap<Driver, ZigbeePublisher>();
+
+    /**
+     * Ejecuta las operaciones de detencion del tracker
+     */
+    public void stop() {
+
+        // Despublicamos los drivers publicados
+        Iterator<ServiceReference> it = gatewaysUsed.keySet().iterator();
+        BundleContext bc = Activator.getBundleContext();
+        while (it.hasNext()) {
+            ServiceReference srefGtwy = it.next();
+            // recuperamos el driver
+            ServiceRegistration sregDriver = gatewaysUsed.get(srefGtwy);
+            Driver drv = (Driver) bc.getService(sregDriver.getReference());
+            
+            // despublicamos los dispositivos asociados al driver
+            ZigbeePublisher zp = zpList.get(drv);
+            zp.stop();
+            
+            // paramos el driver
+            drv.stop();
+
+            // desregistramos el driver
+            sregDriver.unregister();
+            
+            // liberamos la referencia del gateway
+            bc.ungetService(srefGtwy);
+        }
+
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+
+        BundleContext bc = Activator.getBundleContext();
+
+        // recuperamos el gateway
+        Gateway gtwy = (Gateway) bc.getService(reference);
+
+        // intentamos crear un driver con el gateway
+        Driver drv = DriverFactory.createDriver(gtwy);
+        if (drv == null) {
+            // soltamos el gateway
+            bc.ungetService(reference);
+            gtwy = null;
+        } else {
+            // registramos el driver en OSGi
+            Dictionary properties = new Hashtable();
+            properties.put(Constants.DRIVER_DEVICE_NAME, gtwy.getDeviceName());
+            properties.put(Constants.DRIVER_DONGLE_ADDRESS, gtwy.getDongleAddress());
+            properties.put(Constants.DRIVER_FIRMWARE_REVISION, gtwy.getFirmwareRevision());
+            ServiceRegistration srDriver = bc.registerService(Driver.class.getName(), drv, properties);
+            // lo añadimos a la lista de gateways
+            gatewaysUsed.put(reference, srDriver);
+            
+            // creamos un ZigbeePublisher para el driver
+            ZigbeePublisher zp = new ZigbeePublisher(drv);
+            zp.start();
+            zpList.put(drv, zp);
+                        
+        }
+
+        // devolvemos el gateway (será null si no hemos abierto un gateway
+        return gtwy;
+
+    }
+
+    @Override
+    public void modifiedService(ServiceReference reference, Object service) {
+        // no hacemos nada
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        // Comprobamos si es un gateway asociado a un driver
+        if (gatewaysUsed.containsKey(reference)) {
+            BundleContext bc = Activator.getBundleContext();
+            // Recuperamos el driver
+            ServiceRegistration sregDriver = gatewaysUsed.get(reference);
+            Driver drv = (Driver) bc.getService(sregDriver.getReference());
+
+            // despublicamos los dispositivos asociados al driver
+            ZigbeePublisher zp = zpList.get(drv);
+            zp.stop();
+            
+            // paramos el driver
+            drv.stop();
+            // despublicamos el driver
+            sregDriver.unregister();
+
+            // Soltamos el gateway
+            bc.ungetService(reference);
+
+            // los eliminamos de la lista
+            gatewaysUsed.remove(reference);
+
+        }
+
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/ZigbeePublisher.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/ZigbeePublisher.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/osgi/ZigbeePublisher.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,342 @@
+/*
+ * 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.driver.impl.osgi;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver;
+import es.unizar.howlab.core.zigbee.telegesis.driver.Driver.DriverStatus;
+import es.unizar.howlab.core.zigbee.telegesis.driver.DriverListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice.DeviceStatus;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDeviceListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNode.NodeStatus;
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeNodeListener;
+import es.unizar.howlab.core.zigbee.telegesis.driver.osgi.Constants;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Clase para registrar servicios en OSGi, conforme a los cambios de estado 
+ * de los nodos y devices
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class ZigbeePublisher implements DriverListener, ZigbeeNodeListener, ZigbeeDeviceListener {
+
+    private final HashMap<ZigbeeNode, ServiceRegistration> nodesRegistered = new HashMap<ZigbeeNode, ServiceRegistration>();
+    private final HashMap<ZigbeeDevice, ServiceRegistration> devicesRegistered = new HashMap<ZigbeeDevice, ServiceRegistration>();
+    // Logger
+    static Log logger = LogFactory.getLog(ZigbeePublisher.class.getName());
+    final Driver driver;
+
+    public ZigbeePublisher(Driver drv) {
+        logger.trace("ZigbeePublisher::ZigbeePublisher(drv=" + drv + ")");
+        // guardamos el driver
+        driver = drv;
+    }
+
+    /**
+     * Registra el listener y publica los dispositivos descubiertos hasta ahora
+     */
+    public void start() {
+        logger.trace("ZigbeePublisher::start()");
+        // nos registramos como listener
+        driver.registerListener(this);
+
+        // publicamos los servicios
+        publishAllServices();
+
+    }
+
+    /**
+     * Publica los sercicios asociados a los dispositivos del driver
+     */
+    private void publishAllServices() {
+        logger.trace("ZigbeePublisher::publishAllServices()");
+
+        // recuperamos los nodos
+        ZigbeeNode[] nodes = driver.getNodes();
+        for (int i = 0; i < nodes.length; i++) {
+            ZigbeeNode nd = nodes[i];
+
+            // registramos listener del nodo
+            nd.registerListener(this);
+
+            // publicamos el nodo
+            registerNode(nd);
+
+            // recuperamos devices
+            ZigbeeDevice[] devices = nd.getZigbeeDevices();
+            for (int j = 0; j < devices.length; j++) {
+                ZigbeeDevice zb = devices[j];
+                // registramos listener del device
+                zb.registerListener(this);
+                // publicamos el device
+                registerDevice(zb);
+            }
+        }
+
+    }
+
+    /**
+     * Elimina el registro de todos los dispositivos publicados
+     */
+    public void stop() {
+        logger.trace("ZigbeePublisher::stop()");
+
+        // despublicamos los servicios
+        unpublishAllServices();
+
+        // nos desregistramos como listener del driver
+        driver.unregisterListener(this);
+
+    }
+
+    /**
+     * Elimina el registro de todos los servicios publicados
+     */
+    private void unpublishAllServices() {
+        logger.trace("ZigbeePublisher::unpublishAllServices()");
+
+        synchronized (devicesRegistered) {
+            // Desregistramos devices
+            Iterator itDevices = devicesRegistered.keySet().iterator();
+            while (itDevices.hasNext()) {
+                // recuperamos el ZigbeeDevice            
+                ZigbeeDevice zb = (ZigbeeDevice) itDevices.next();
+                logger.info("Unregistering service for ZigbeeDevice: " + zb);
+
+                // nos desregistramos como listener
+                zb.unregisterListener(this);
+
+                // despublicamos el ZigbeeDevice
+                ServiceRegistration sr = (ServiceRegistration) devicesRegistered.get(zb);
+                sr.unregister();
+            }
+            devicesRegistered.clear();
+        }
+
+        synchronized (nodesRegistered) {
+            // Desregistramos nodos
+            Iterator itNodes = nodesRegistered.keySet().iterator();
+            while (itNodes.hasNext()) {
+                // recuperamos el ZigbeeNode            
+                ZigbeeNode zn = (ZigbeeNode) itNodes.next();
+                logger.info("Unregistering service for ZigbeeNode: " + zn);
+
+                // nos desregistramos como listener
+                zn.unregisterListener(this);
+
+                // despublicamos el ZigbeeNode            
+                ServiceRegistration sr = (ServiceRegistration) nodesRegistered.get(zn);
+                sr.unregister();
+            }
+            nodesRegistered.clear();
+
+        }
+    }
+
+    /**
+     * Registra el dispositivo en OSGi 
+     * @param zb
+     */
+    protected void registerDevice(ZigbeeDevice zb) {
+        logger.trace("ZigbeePublisher::registerDevice(zb=" + zb + ")");
+        synchronized (devicesRegistered) {
+            // comprobamos si lo hemos registrado ya
+            if (!devicesRegistered.containsKey(zb)) {
+                // recuperamos el bundle context
+                BundleContext bc = Activator.getBundleContext();
+
+                // registramos el ZigbeeDevice
+                Dictionary properties = new Hashtable();
+                properties.put(Constants.DRIVER_ZIGBEE_DEVICE_ADDRESS, zb.getZigbeeNode().getEUI64Addr());
+                properties.put(Constants.DRIVER_ZIGBEE_DEVICE_ENDPOINT, zb.getEndPoint());
+                if (zb.getDeviceId() != null){
+                    properties.put(Constants.DRIVER_ZIGBEE_DEVICE_ID, zb.getDeviceId());
+                }
+                if (zb.getProfileId() != null){
+                    properties.put(Constants.DRIVER_ZIGBEE_DEVICE_PROFILE_ID, zb.getProfileId());
+                }
+                ServiceRegistration sr = bc.registerService(ZigbeeDevice.class.getName(), zb, properties);
+                logger.info("Registered service for ZigbeeDevice: " + zb);
+
+                // guardamos la referencia del registro
+                devicesRegistered.put(zb, sr);
+            }
+        }
+    }
+
+    /**
+     * Desregistra un nodo en OSGi
+     * @param zn
+     */
+    protected void unregisterNode(ZigbeeNode zn) {
+        logger.trace("ZigbeePublisher::unregisterNode(zn=" + zn + ")");
+        synchronized (nodesRegistered) {
+            // comprobamos si está registrado
+            if (nodesRegistered.containsKey(zn)) {
+                // recuperamos la referencia del servicio
+                ServiceRegistration sr = nodesRegistered.get(zn);
+
+                // desregistramos el ZigbeNode
+                sr.unregister();
+                logger.info("Unregistered service for ZigbeeNode: " + zn);
+
+                // eliminamos la referencia del registro
+                nodesRegistered.remove(zn);
+            }
+        }
+    }
+
+    /**
+     * Desregistra un device en OSGi
+     * @param zb
+     */
+    protected void unregisterDevice(ZigbeeDevice zb) {
+        logger.trace("ZigbeePublisher::unregisterDevice(zb=" + zb + ")");
+        // comprobamos si está registrado
+        synchronized (devicesRegistered) {
+            if (devicesRegistered.containsKey(zb)) {
+                // recuperamos la referencia del servicio
+                ServiceRegistration sr = devicesRegistered.get(zb);
+
+                // desregistramos el ZigbeeDevice
+                sr.unregister();
+                logger.info("Unregistered service for ZigbeeDevice: " + zb);
+
+                // eliminamos la referencia del registro
+                devicesRegistered.remove(zb);
+            }
+        }
+    }
+
+    /**
+     * Registra el nodo en OSGi
+     * @param zn
+     */
+    protected void registerNode(ZigbeeNode zn) {
+        logger.trace("ZigbeePublisher::registerNode(zn=" + zn + ")");
+        synchronized (nodesRegistered) {
+            // comprobamos si lo hemos registrado ya
+            if (!nodesRegistered.containsKey(zn)) {
+                // recuperamos el bundle context
+                BundleContext bc = Activator.getBundleContext();
+
+                // registramos el ZigbeeNode
+                Dictionary properties = new Hashtable();
+                properties.put(Constants.DRIVER_ZIGBEE_NODE_ADDRESS, zn.getEUI64Addr());
+                properties.put(Constants.DRIVER_ZIGBEE_NODE_TYPE, zn.getType());
+                ServiceRegistration sr = bc.registerService(ZigbeeNode.class.getName(), zn, properties);
+                logger.info("Registered service for ZigbeeNode: " + zn);
+
+                // guardamos la referencia del registro
+                nodesRegistered.put(zn, sr);
+            }
+        }
+    }
+
+    @Override
+    public void newNode(ZigbeeNode node, Driver drv) {
+        logger.trace("ZigbeePublisher::newNode(node=" + node + ", drv=" + drv + ")");
+        // nos registramos como listener del Nodo
+        node.registerListener(this);
+
+        // registramos el nodo
+        registerNode(node);
+    }
+
+    @Override
+    public void nodeLeft(ZigbeeNode node, Driver drv) {
+        logger.trace("ZigbeePublisher::nodeLeft(node=" + node + ", drv=" + drv + ")");
+
+        // nos desregistramos como listener
+        node.unregisterListener(this);
+
+        // desregistramos el nodo
+        unregisterNode(node);
+
+    }
+
+    @Override
+    public void newDevice(ZigbeeDevice device, Driver drv) {
+        logger.trace("ZigbeePublisher::newDevice(device=" + device + ", drv=" + drv + ")");
+        // nos registramos como listener del device
+        device.registerListener(this);
+        // registramos el device
+        registerDevice(device);
+    }
+
+    @Override
+    public void deviceLeft(ZigbeeDevice device, Driver drv) {
+        logger.trace("ZigbeePublisher::deviceLeft(device=" + device + ", drv=" + drv + ")");
+        // nos desregistramos como listener
+        device.unregisterListener(this);
+
+        // desregistramos el device
+        unregisterDevice(device);
+    }
+
+    @Override
+    public void joinNetwork(int channel, String PANID, String EPID, Driver drv) {
+        logger.trace("ZigbeePublisher::joinNetwork(channel=" + channel + ", PANID=" + PANID + ", EPID=" + EPID + ", drv=" + drv + ")");
+
+        // publicamos todos los dispositivos 
+        publishAllServices();
+    }
+
+    @Override
+    public void leftNetwork(Driver drv) {
+        logger.trace("ZigbeePublisher::leftNetwork(drv=" + drv + ")");
+
+        // despublicamos todos los dispositivos 
+        unpublishAllServices();
+
+    }
+
+    @Override
+    public void statusChanged(DriverStatus status, DriverStatus oldStatus, Driver drv) {
+        // ignoramos
+    }
+
+    @Override
+    public void messageReceived(String profileID, String clusterID, byte[] message, ZigbeeDevice zb) {
+        // ignoramos
+    }
+
+    @Override
+    public void statusChanged(DeviceStatus status, DeviceStatus oldStatus, ZigbeeDevice zb) {
+        logger.trace("ZigbeePublisher::statusChanged(status=" + status + ", oldStatus=" + oldStatus + ", zb=" + zb + ")");
+        registerDevice(zb);
+    }
+
+    @Override
+    public void messageReceived(byte[] message, ZigbeeNode zn) {
+        // ignoramos
+    }
+
+    @Override
+    public void statusChanged(NodeStatus status, NodeStatus oldStatus, ZigbeeNode zn) {
+        logger.trace("ZigbeePublisher::statusChanged(status=" + status + ", oldStatus=" + oldStatus + ", zn=" + zn + ")");
+        registerNode(zn);
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/AbstractGatewayListener.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/AbstractGatewayListener.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/AbstractGatewayListener.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,117 @@
+/*
+ * 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.driver.impl.util;
+
+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.Map;
+
+/**
+ * Clase abstracta para que la extiendan los listeners específicos sin tener que 
+ * implementar todos los métodos
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public abstract class AbstractGatewayListener implements GatewayListener {
+    
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    abstract public void clearListener();
+
+    @Override
+    public void acknowledgement(short seqNumber, boolean wasACK, Gateway gtwy) {
+    }
+
+    @Override
+    public void routeRecordReceived(String EUI64Addr, int numHops, String[] route, Gateway gtwy) {
+    }
+
+    @Override
+    public void broadcastMessageReceived(String EUI64Addr, byte[] message, Gateway gtwy) {
+    }
+
+    @Override
+    public void messageReceived(String EUI64Addr, byte[] message, String type, Gateway gtwy) {
+    }
+
+    @Override
+    public void endpointMessageReceived(String EUI64Addr, String nodeID, short sourceEP, short destEP, String profileID, String clusterID, byte[] payload, Gateway gtwy) {
+    }
+
+    @Override
+    public void nodeAnnounce(ZigbeeDeviceType type, String EUI64Addr, String nodeID, int RSSI, short LQI, Gateway gtwy) {
+    }
+
+    @Override
+    public void newNode(String EUI64Addr, String nodeID, String parentID, Gateway gtwy) {
+    }
+
+    @Override
+    public void leftPAN(Gateway gtwy) {
+    }
+
+    @Override
+    public void joinedPan(int channel, String PID, String EPID, Gateway gtwy) {
+    }
+
+    @Override
+    public void registerWrited(String nodeID, String EUI64Addr, short errorCode, Gateway gtwy) {
+    }
+
+    @Override
+    public void registerReaded(String nodeID, String EUI64Addr, short register, short errorCode, String data, Gateway gtwy) {
+    }
+
+    @Override
+    public void addrResponse(short errorCode, String nodeID, String EUI64Addr, Gateway gtwy) {
+    }
+
+    @Override
+    public void neighbourTableResponse(String nodeID, short errorCode, int tableLength, NeighbourTableEntry[] table, Gateway gtwy) {
+    }
+
+    @Override
+    public void nodeDescriptorResponse(String nodeID, short errorCode, Map descriptor, Gateway gtwy) {
+    }
+
+    @Override
+    public void powerDescriptorResponse(String nodeID, short errorCode, String descriptor, Gateway gtwy) {
+    }
+
+    @Override
+    public void nodeActiveEPResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+    }
+
+    @Override
+    public void nodeEndPointSimpleDescriptorResponse(String nodeID, short errorCode, short EP, String ProfileID, String DeviceID, String[] inClusterList, String[] outClusterList, Gateway gtwy) {
+    }
+
+    @Override
+    public void nodeMatchingDescriptorResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+    }
+
+    @Override
+    public void unhandledCommand(String command, String[] parameters, Gateway gtwy) {
+    }
+
+    @Override
+    public void unknownMessage(String message, Gateway gtwy) {
+    }
+    
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrACK.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrACK.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrACK.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,131 @@
+/*
+ * 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.driver.impl.util;
+
+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.ArrayList;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle ACK/NACK notifications
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class GtwyLstnrACK extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    ArrayList<String> ACKList = new ArrayList<String>();
+    ArrayList<String> NACKList = new ArrayList<String>();
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrACK(Gateway gtwy) {
+        logger.trace("GtwyLstnrACK::GtwyLstnrACK(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación de ACK
+     * para el SeqNumber indicado, o hasta que transcurra el tiempo máximo 
+     * indicado
+     * @param seqNumber SeqNumber de referencia
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe el ACK, o false si se recibe NACK o pasa el tiempo
+     * indicado
+     */
+    public boolean waitForACK(short seqNumber, long milliseconds) {
+        logger.trace("GtwyLstnrACK::waitForACK(seqNumber=" + seqNumber + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting ACK] waiting for ACK:%02X for %d milliseconds", seqNumber, milliseconds));
+            // obtenemos una representación del SeqNumber para usar en el control
+            String SEQ = String.format("%02X", seqNumber);
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+            // iniciamos bucle de espera
+            while (!ACKList.contains(SEQ)) {
+                try {
+                    // esperamos notificación de ACK
+                    this.wait(wakeUpDelay);
+                    // comprobamos si ha llegado el ACK
+                    if (ACKList.contains(SEQ)) {
+                        logger.info(String.format("[Waiting ACK] ACK:%02X received", seqNumber));
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado un NACK
+                    if (NACKList.contains(SEQ)) {
+                        logger.warn(String.format("[Waiting ACK] NACK:%02X received", seqNumber));
+                        clearListener();
+                        return false;
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting ACK] Timeout awaiting ACK:%02X", seqNumber));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+            // si hemos llegado aquí, es porque el SEQ había llegado antes de empezar a esperar, devolvemos OK
+            logger.info(String.format("[Waiting ACK] ACK:%02X received", seqNumber));
+            clearListener();
+            return true;
+        }
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrACK::clearListener()");
+        gateway.unregisterListener(this);
+        ACKList.clear();
+        NACKList.clear();
+    }
+
+    @Override
+    public void acknowledgement(short seqNumber, boolean wasACK, Gateway gtwy) {
+        logger.trace("GtwyLstnrACK::acknowledgement(seqNumber=" + seqNumber + ", wasACK=" + wasACK + ", gtwy=" + gtwy + ")");
+        if (ACKList == null) {
+            return;
+        }
+        synchronized (this) {
+            // guardamos el ACK/NACK
+            String SEQ = String.format("%02X", seqNumber);
+            if (wasACK) {
+                ACKList.add(SEQ);
+            } else {
+                NACKList.add(SEQ);
+            }
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrActiveEndPoints.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrActiveEndPoints.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrActiveEndPoints.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,150 @@
+/*
+ * 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.driver.impl.util;
+
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle NeighbourTableResponse notifications
+ * @author Alvaro
+ */
+public class GtwyLstnrActiveEndPoints extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    // variables para almacenar resultados de eventos
+    HashMap<String, short[]> nodesActiveEPList = new HashMap<String, short[]>();
+    HashMap<String, String> nodesErrorCodeList = new HashMap<String, String>();
+    // variables para consultar resultados de espera
+    short[] nodeActiveEPList = null;
+    String errorMessage = "";
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrActiveEndPoints(Gateway gtwy) {
+        logger.trace("GtwyLstnrActiveEndPoints::GtwyLstnrActiveEndPoints(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación para
+     * el nodo indicado, o hasta que transcurra el tiempo máximo
+     * @param nodeID Dirección del nodo
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe la respuesta OK, o false si se recibe respuesta
+     * NOK o pasa el tiempo indicado
+     */
+    public boolean waitForActiveEndPoints(String nodeID, long milliseconds) {
+        logger.trace("GtwyLstnrActiveEndPoints::waitForActiveEndPoints(nodeID=" + nodeID + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting ActiveEndPoints] waiting for EPList of nodeID %s for %d milliseconds", nodeID, milliseconds));
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // iniciamos bucle de espera
+            while (!nodesActiveEPList.containsKey(nodeID)) {
+                try {
+                    // esperamos notificación
+                    this.wait(wakeUpDelay);
+                    // comprobamos si ha llegado la tabla
+                    if (nodesActiveEPList.containsKey(nodeID)) {
+                        logger.info(String.format("[Waiting ActiveEndPoints] EPList of nodeID %s received", nodeID));
+                        // guardamos los resultados
+                        nodeActiveEPList = nodesActiveEPList.get(nodeID);
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado un NOK
+                    if (nodesErrorCodeList.containsKey(nodeID)) {
+                        errorMessage = nodesErrorCodeList.get(nodeID);
+                        logger.warn(String.format("[Waiting ActiveEndPoints] Error awaiting EPList of nodeID %s. Error code: %s", nodeID, errorMessage));
+                        clearListener();
+                        return false;
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting ActiveEndPoints] Timeout awaiting EPList of nodeID %s", nodeID));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+            // si hemos llegado aquí, es porque la tabla había llegado antes de empezar a esperar, devolvemos OK
+            nodeActiveEPList = nodesActiveEPList.get(nodeID);
+            logger.info(String.format("[Waiting ActiveEndPoints] EPList of nodeID %s received", nodeID));
+            clearListener();
+            return true;
+        }
+    }
+
+    /**
+     * Recupera la lista de EndPoints despues de esperar
+     * @return NeighbourTable
+     */
+    public short[] getEndPointList() {
+        return nodeActiveEPList;
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrActiveEndPoints::clearListener()");
+        gateway.unregisterListener(this);
+        nodesActiveEPList.clear();
+        nodesErrorCodeList.clear();
+    }
+
+    @Override
+    public void nodeActiveEPResponse(String nodeID, short errorCode, short[] EPList, Gateway gtwy) {
+        logger.trace("GtwyLstnrActiveEndPoints::nodeActiveEPResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EPList=" + EPList + ", gtwy=" + gtwy + ")");
+        synchronized (this) {
+            // comprobamos el resultado
+            if (errorCode == 0) { // resultado correcto
+                nodesActiveEPList.put(nodeID, EPList);
+            } else { // resultado incorrecto
+                nodesErrorCodeList.put(nodeID, String.format("%02X", errorCode));
+            }
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrAddrResponse.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrAddrResponse.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrAddrResponse.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,151 @@
+/*
+ * 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.driver.impl.util;
+
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle AddrResponse notifications
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class GtwyLstnrAddrResponse extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    // variables para almacenar resultados de eventos
+    HashMap<String, String> nodesIdList = new HashMap<String, String>();
+    HashMap<String, Integer> nodesNeighbourTablesLength = new HashMap<String, Integer>();
+    HashMap<String, String> nodesErrorCodeList = new HashMap<String, String>();
+    // variables para consultar resultados de espera
+    String nodeID = null;
+    String errorMessage = "";
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrAddrResponse(Gateway gtwy) {
+        logger.trace("GtwyLstnrAddrResponse::GtwyLstnrAddrResponse(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación para
+     * el nodo indicado, o hasta que transcurra el tiempo máximo
+     * @param EUI64Addr Dirección del nodo
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe la respuesta OK, o false si se recibe respuesta
+     * NOK o pasa el tiempo indicado
+     */
+    public boolean waitForAddrResponse(String EUI64Addr, long milliseconds) {
+        logger.trace("GtwyLstnrAddrResponse::waitForAddrResponse(seqNumber=" + EUI64Addr + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting AddrResponse] waiting AddrResponse for node %s for %d milliseconds", EUI64Addr, milliseconds));
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // iniciamos bucle de espera
+            while (!nodesIdList.containsKey(EUI64Addr)) {
+                try {
+                    // esperamos notificación
+                    this.wait(wakeUpDelay);
+                    // comprobamos si ha llegado la tabla
+                    if (nodesIdList.containsKey(EUI64Addr)) {
+                        logger.info(String.format("[Waiting AddrResponse] AddrResponse of nodeID %s received", nodeID));
+                        // guardamos los resultados
+                        this.nodeID = nodesIdList.get(EUI64Addr);
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado un NOK
+                    if (nodesErrorCodeList.containsKey(EUI64Addr)) {
+                        errorMessage = nodesErrorCodeList.get(EUI64Addr);
+                        clearListener();
+                        logger.warn(String.format("[Waiting AddrResponse] Error awaiting AddrResponse of nodeID %s. Error code: %s", nodeID, errorMessage));
+                        return false;
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting AddrResponse] Timeout awaiting AddrResponse of nodeID %s", nodeID));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+            // si hemos llegado aquí, es porque la tabla había llegado antes de empezar a esperar, devolvemos OK
+            logger.info(String.format("[Waiting AddrResponse] AddrResponse of nodeID %s received", nodeID));
+            this.nodeID = nodesIdList.get(EUI64Addr);
+            clearListener();
+            return true;
+        }
+    }
+
+    /**
+     * Recupera el NodeID despues de esperar
+     * @return NodeID
+     */
+    public String getNodeID() {
+        return nodeID;
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrAddrResponse::clearListener()");
+        gateway.unregisterListener(this);
+        nodesIdList.clear();
+        nodesErrorCodeList.clear();
+    }
+
+    @Override
+    public void addrResponse(short errorCode, String nodeID, String EUI64Addr, Gateway gtwy) {
+        logger.trace("GtwyLstnrAddrResponse::neighbourTableResponse(errorCode=" + errorCode + ", nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + gtwy + ")");
+        synchronized (this) {
+            // comprobamos el resultado
+            if (errorCode == 0) { // resultado correcto
+                nodesIdList.put(EUI64Addr, nodeID);
+            } else { // resultado incorrecto
+                nodesErrorCodeList.put(EUI64Addr, String.format("%02X", errorCode));
+            }
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrEndPointDescriptor.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrEndPointDescriptor.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrEndPointDescriptor.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,250 @@
+/*
+ * 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.driver.impl.util;
+
+import es.unizar.howlab.core.zigbee.telegesis.driver.ZigbeeDevice;
+import es.unizar.howlab.core.zigbee.telegesis.driver.impl.ZigbeeDeviceImpl;
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle EndPointDescriptor notifications
+ * @author Alvaro
+ */
+public class GtwyLstnrEndPointDescriptor extends AbstractGatewayListener {
+
+    Gateway gateway;
+    // variables para almacenar resultados de eventos
+    HashMap<String, HashMap<String, ZigbeeDevice>> endPointDescriptorsNodeList = new HashMap<String, HashMap<String, ZigbeeDevice>>();
+    HashMap<String, HashMap<String, String>> endPointDescriptorsErrorNodeList = new HashMap<String, HashMap<String, String>>();
+    // variables para consultar resultados de espera
+    ZigbeeDevice endPointDescriptor = null;
+    String errorMessage = "";
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrEndPointDescriptor(Gateway gtwy) {
+        logger.trace("GtwyLstnrEndPointDescriptor::GtwyLstnrEndPointDescriptor(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación 
+     * EndPointSimpleDescriptor para el nodo indicado y el endPoint solicitado, 
+     * o hasta que transcurra el tiempo máximo indicado
+     * @param nodeID Dirección del nodo
+     * @param endPoint Dirección del endPoint
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe la respuesta OK, o false si se recibe respuesta
+     * NOK o pasa el tiempo indicado
+     */
+    public boolean waitForEndPointSimpleDescriptor(String nodeID, short endPoint, long milliseconds) {
+        logger.trace("GtwyLstnrEndPointDescriptor::waitForEndPointSimpleDescriptor(nodeID=" + nodeID + ", regAddress=" + endPoint + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting EndPointDescriptor] waiting for EPDescriptor of nodeID %s, EP:%02X for %d milliseconds", nodeID, endPoint, milliseconds));
+            // obtenemos una representación del endPoint para usar en el control
+            String strEP = String.format("%02X", endPoint);
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // comprobamos primero si ya ha llegado la respuesta antes de esperar
+            // comprobamos si ha llegado el descriptor OK
+            endPointDescriptor = getDescriptor(nodeID, endPoint);
+            if (endPointDescriptor != null) {
+                logger.info(String.format("[Waiting EndPointDescriptor] EPDescriptor of nodeID %s, EP:%02X received", nodeID, endPoint));
+                clearListener();
+                return true;
+            }
+
+            // comprobamos si ha llegado descriptor NOK
+            if (getErrorCode(nodeID, endPoint) != null) {
+                errorMessage = getErrorCode(nodeID, endPoint);
+                logger.warn(String.format("[Waiting EndPointDescriptor] Error awaiting EPDescriptor of nodeID %s, EP:%02X. Error code: %s", nodeID, endPoint, errorMessage));
+                clearListener();
+                return false;
+            }
+
+            // iniciamos bucle de espera con una variable de control
+            boolean done = false;
+            while (!done) {
+                try {
+                    // esperamos notificación de lectura de registro
+                    this.wait(wakeUpDelay);
+
+                    // comprobamos si ha llegado el descriptor OK
+                    endPointDescriptor = getDescriptor(nodeID, endPoint);
+                    if (endPointDescriptor != null) {
+                        logger.info(String.format("[Waiting EndPointDescriptor] EPDescriptor of nodeID %s, EP:%02X received", nodeID, endPoint));
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado descriptor NOK
+                    if (getErrorCode(nodeID, endPoint) != null) {
+                        errorMessage = getErrorCode(nodeID, endPoint);
+                        logger.warn(String.format("[Waiting EndPointDescriptor] Error awaiting EPDescriptor of nodeID %s, EP:%02X. Error code: %s", nodeID, endPoint, errorMessage));
+                        clearListener();
+                        return false;
+                    }
+
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting EndPointDescriptor] Timeout awaiting EPDescriptor of nodeID %s, EP:%02X", nodeID, endPoint));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+        }
+
+        // no deberíamos llegar a este punto de ejecución
+        return false;
+    }
+
+    /**
+     * Recupera el valor del registro y nodo en la lista combinada
+     * @param nodeID dirección de red del nodo
+     * @param endPoint dirección del endPoint
+     * @return ZigbeeDevice conteniendo el descriptor, o null si no existe
+     */
+    private ZigbeeDevice getDescriptor(String nodeID, short endPoint) {
+        // obtenemos una representación del endPoint para usar en el control
+        String strEP = String.format("%02X", endPoint);
+
+        if (endPointDescriptorsNodeList.containsKey(nodeID)) {
+            HashMap<String, ZigbeeDevice> endPointDescriptorList = endPointDescriptorsNodeList.get(nodeID);
+            // comprobamos si ha llegado el valor del registro
+            if (endPointDescriptorList.containsKey(strEP)) {
+                return endPointDescriptorList.get(strEP);
+            } else {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Recupera la condición de error del registro y nodo en la lista combinada
+     * @param nodeID dirección del nodo
+     * @param endPoint dirección del endPoint
+     * @return valor correspondiente, o null si no existe
+     */
+    private String getErrorCode(String nodeID, short endPoint) {
+        // obtenemos una representación del endPoint para usar en el control
+        String strEP = String.format("%02X", endPoint);
+
+        if (endPointDescriptorsErrorNodeList.containsKey(nodeID)) {
+            HashMap<String, String> endPointList = endPointDescriptorsErrorNodeList.get(nodeID);
+            // comprobamos si ha llegado el codigo de error
+            if (endPointList.containsKey(strEP)) {
+                return endPointList.get(strEP);
+            } else {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Recupera el endPointDescriptor despues de esperar
+     * @return ZigbeeDevice auxiliar conteniendo el descriptor
+     */
+    public ZigbeeDevice getEndPointDescriptor() {
+        return endPointDescriptor;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrEndPointDescriptor::clearListener()");
+        gateway.unregisterListener(this);
+        gateway = null;
+        endPointDescriptorsNodeList.clear();
+        endPointDescriptorsErrorNodeList.clear();
+    }
+
+    @Override
+    public void nodeEndPointSimpleDescriptorResponse(String nodeID, short errorCode, short EP, String ProfileID, String DeviceID, String[] inClusterList, String[] outClusterList, Gateway gtwy) {
+        logger.trace("GtwyLstnrEndPointDescriptor::nodeEndPointSimpleDescriptorResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", EP=" + EP + ", profileID=" + ProfileID + ", DeviceID=" + DeviceID + ", inClusterList=" + inClusterList + ", outClusterList=" + outClusterList + ", gtwy=" + gtwy + ")");
+        synchronized (this) {
+            // comprobamos el resultado
+            if (errorCode == 0) { // resultado OK
+                // recuperamos la lista de endPoints del nodo
+                HashMap<String, ZigbeeDevice> endPointDescriptorsList = endPointDescriptorsNodeList.get(nodeID);
+                if (endPointDescriptorsList == null) {
+                    endPointDescriptorsList = new HashMap<String, ZigbeeDevice>();
+                }
+
+                // creamos un zigbeeDevice temporal
+                ZigbeeDeviceImpl auxDevice = new ZigbeeDeviceImpl(null, null, EP);
+                // actualizamos los datos
+                ((ZigbeeDeviceImpl) auxDevice).setProfileID(ProfileID);
+                ((ZigbeeDeviceImpl) auxDevice).setDeviceID(DeviceID);
+                ((ZigbeeDeviceImpl) auxDevice).setInClusterList(inClusterList);
+                ((ZigbeeDeviceImpl) auxDevice).setOutClusterList(outClusterList);
+
+                // guardamos el valor del descriptor
+                endPointDescriptorsList.put(String.format("%02X", EP), auxDevice);
+
+                // guardamos la lista de descriptores
+                endPointDescriptorsNodeList.put(nodeID, endPointDescriptorsList);
+
+            } else { // resultado NOK
+                // recuperamos la lista de endPoints del nodo
+                HashMap<String, String> endPointDescriptorsList = endPointDescriptorsErrorNodeList.get(nodeID);
+                if (endPointDescriptorsList == null) {
+                    endPointDescriptorsList = new HashMap<String, String>();
+                }
+
+                // guardamos el código de error
+                endPointDescriptorsList.put(String.format("%02X", EP), String.format("%02X", errorCode));
+
+                // guardamos la lista errores
+                endPointDescriptorsErrorNodeList.put(nodeID, endPointDescriptorsList);
+
+            }
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrNeighbourTableResponse.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrNeighbourTableResponse.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrNeighbourTableResponse.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,164 @@
+/*
+ * 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.driver.impl.util;
+
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle NeighbourTableResponse notifications
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class GtwyLstnrNeighbourTableResponse extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    // variables para almacenar resultados de eventos
+    HashMap<String, NeighbourTableEntry[]> nodesNeighbourTablesList = new HashMap<String, NeighbourTableEntry[]>();
+    HashMap<String, Integer> nodesNeighbourTablesLength = new HashMap<String, Integer>();
+    HashMap<String, String> nodesErrorCodeList = new HashMap<String, String>();
+    // variables para consultar resultados de espera
+    NeighbourTableEntry[] neighbourTableEntries = null;
+    int neighbourTableLength = 0;
+    String errorMessage = "";
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrNeighbourTableResponse(Gateway gtwy) {
+        logger.trace("GtwyLstnrNeighbourTableResponse::GtwyLstnrNeighbourTableResponse(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación para
+     * el nodo indicado, o hasta que transcurra el tiempo máximo
+     * @param nodeID Dirección del nodo
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe la respuesta OK, o false si se recibe respuesta
+     * NOK o pasa el tiempo indicado
+     */
+    public boolean waitForNeighbourTableResponse(String nodeID, long milliseconds) {
+        logger.trace("GtwyLstnrNeighbourTableResponse::waitForNeighbourTableResponse(seqNumber=" + nodeID + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting Neighbour table] waiting for NTable of nodeID %s for %d milliseconds", nodeID, milliseconds));
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // iniciamos bucle de espera
+            while (!nodesNeighbourTablesList.containsKey(nodeID)) {
+                try {
+                    // esperamos notificación
+                    this.wait(wakeUpDelay);
+                    // comprobamos si ha llegado la tabla
+                    if (nodesNeighbourTablesList.containsKey(nodeID)) {
+                        logger.info(String.format("[Waiting Neighbour table] NTable of nodeID %s received", nodeID));
+                        // guardamos los resultados
+                        neighbourTableEntries = nodesNeighbourTablesList.get(nodeID);
+                        neighbourTableLength = nodesNeighbourTablesLength.get(nodeID);
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado un NOK
+                    if (nodesErrorCodeList.containsKey(nodeID)) {
+                        logger.warn(String.format("[Waiting Neighbour table] Error awaiting NTable of nodeID %s. Error code: %s", nodeID, errorMessage));
+                        errorMessage = nodesErrorCodeList.get(nodeID);
+                        clearListener();
+                        return false;
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting Neighbour table] Timeout awaiting NTable of nodeID %s", nodeID));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+            // si hemos llegado aquí, es porque la tabla había llegado antes de empezar a esperar, devolvemos OK
+            logger.info(String.format("[Waiting Neighbour table] NTable of nodeID %s received", nodeID));
+            neighbourTableEntries = nodesNeighbourTablesList.get(nodeID);
+            neighbourTableLength = nodesNeighbourTablesLength.get(nodeID);
+            clearListener();
+            return true;
+        }
+    }
+
+    /**
+     * Recupera la tabla de vecinos despues de esperar
+     * @return NeighbourTable
+     */
+    public NeighbourTableEntry[] getNeighbourTable() {
+        return neighbourTableEntries;
+    }
+
+    /**
+     * Recupera la longitud de la tabla de vecinos despues de esperar
+     * @return NeighbourTableLength
+     */
+    public int getNeighbourTableLength() {
+        return neighbourTableLength;
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrNeighbourTableResponse::clearListener()");
+        gateway.unregisterListener(this);
+        nodesNeighbourTablesList.clear();
+        nodesNeighbourTablesLength.clear();
+        nodesErrorCodeList.clear();
+    }
+
+    @Override
+    public void neighbourTableResponse(String nodeID, short errorCode, int tableLength, NeighbourTableEntry[] table, Gateway gtwy) {
+        logger.trace("GtwyLstnrNeighbourTableResponse::neighbourTableResponse(nodeID=" + nodeID + ", errorCode=" + errorCode + ", tableLength=" + tableLength + ", table=" + table + ", gtwy=" + gtwy + ")");
+        synchronized (this) {
+            // comprobamos el resultado
+            if (errorCode == 0) { // resultado correcto
+                nodesNeighbourTablesList.put(nodeID, table);
+                nodesNeighbourTablesLength.put(nodeID, tableLength);
+            } else { // resultado incorrecto
+                nodesErrorCodeList.put(nodeID, String.format("%02X", errorCode));
+            }
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterRead.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterRead.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterRead.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,239 @@
+/*
+ * 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.driver.impl.util;
+
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle RegisterRead notifications
+ * @author Alvaro
+ */
+public class GtwyLstnrRegisterRead extends AbstractGatewayListener {
+
+    Gateway gateway;
+    // variables para almacenar resultados de eventos
+    HashMap<String, HashMap<String, String>> registersDataNodeList = new HashMap<String, HashMap<String, String>>();
+    HashMap<String, HashMap<String, String>> registersErrorNodeList = new HashMap<String, HashMap<String, String>>();
+    // variables para consultar resultados de espera
+    String registerData = null;
+    String errorMessage = "";
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrRegisterRead(Gateway gtwy) {
+        logger.trace("GtwyLstnrRegisterRead::GtwyLstnrRegisterRead(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación de 
+     * registro leido para el nodo indicado y el registro solicitado, o hasta que 
+     * transcurra el tiempo máximo indicado
+     * @param EUI64Addr Dirección del nodo
+     * @param regAddress Dirección del registro
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe la respuesta OK, o false si se recibe respuesta
+     * NOK o pasa el tiempo indicado
+     */
+    public boolean waitForRegisterReaded(String EUI64Addr, short regAddress, long milliseconds) {
+        logger.trace("GtwyLstnrRegisterRead::waitForRegisterReaded(EUI64Addr=" + EUI64Addr + ", reqAddress=" + regAddress + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting RegisterReaded] waiting for SREAD of node %s, address %02X, for %d milliseconds", EUI64Addr, regAddress, milliseconds));
+            // obtenemos una representación del SeqNumber para usar en el control
+            String REG = String.format("%02X", regAddress);
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // comprobamos primero si ya ha llegado la respuesta antes de esperar
+            registerData = getData(EUI64Addr, regAddress);
+            if (registerData != null) {
+                logger.info(String.format("[Waiting RegisterReaded] SREAD of node %s, address %02X received", EUI64Addr, regAddress));
+                clearListener();
+                return true;
+            }
+
+            // comprobamos si ha llegado la lectura del registro NOK
+            if (getErrorCode(EUI64Addr, regAddress) != null) {
+                errorMessage = getErrorCode(EUI64Addr, regAddress);
+                logger.warn(String.format("[Waiting RegisterReaded] Error awaiting SREAD of node %s, address %02X. Error code: %s", EUI64Addr, regAddress, errorMessage));
+                clearListener();
+                return false;
+            }
+
+            // iniciamos bucle de espera con una variable de control
+            boolean done = false;
+            while (!done) {
+                try {
+                    // esperamos notificación de lectura de registro
+                    this.wait(wakeUpDelay);
+
+                    // comprobamos si ha llegado la lectura del registro OK
+                    registerData = getData(EUI64Addr, regAddress);
+                    if (registerData != null) {
+                        logger.info(String.format("[Waiting RegisterReaded] SREAD of node %s, address %02X received", EUI64Addr, regAddress));
+                        clearListener();
+                        return true;
+                    }
+                    // comprobamos si ha llegado la lectura del registro NOK
+                    if (getErrorCode(EUI64Addr, regAddress) != null) {
+                        errorMessage = getErrorCode(EUI64Addr, regAddress);
+                        logger.warn(String.format("[Waiting RegisterReaded] Error awaiting SREAD of node %s, address %02X. Error code: %s", EUI64Addr, regAddress, errorMessage));
+                        clearListener();
+                        return false;
+                    }
+
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting RegisterReaded] Timeout awaiting SREAD of node %s, address %02X", EUI64Addr, regAddress));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+        }
+
+        // no deberíamos llegar a este punto de ejecución
+        return false;
+    }
+
+    /**
+     * Recupera el valor del registro y nodo en la lista combinada
+     * @param EUI64Addr dirección del nodo
+     * @param regAddress dirección del registro
+     * @return valor correspondiente, o null si no existe
+     */
+    private String getData(String EUI64Addr, short regAddress) {
+        // obtenemos una representación del SeqNumber para usar en el control
+        String REG = String.format("%02X", regAddress);
+
+        if (registersDataNodeList.containsKey(EUI64Addr)) {
+            HashMap<String, String> registerList = registersDataNodeList.get(EUI64Addr);
+            // comprobamos si ha llegado el valor del registro
+            if (registerList.containsKey(REG)) {
+                return registerList.get(REG);
+            } else {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Recupera la condición de error del registro y nodo en la lista combinada
+     * @param EUI64Addr dirección del nodo
+     * @param regAddress dirección del registro
+     * @return valor correspondiente, o null si no existe
+     */
+    private String getErrorCode(String EUI64Addr, short regAddress) {
+        // obtenemos una representación del SeqNumber para usar en el control
+        String REG = String.format("%02X", regAddress);
+
+        if (registersErrorNodeList.containsKey(EUI64Addr)) {
+            HashMap<String, String> registerList = registersErrorNodeList.get(EUI64Addr);
+            // comprobamos si ha llegado el codigo de error
+            if (registerList.containsKey(REG)) {
+                return registerList.get(REG);
+            } else {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Recupera el contenido del registro despues de esperar
+     * @return RegisterData
+     */
+    public String getRegisterData() {
+        return registerData;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrRegisterRead::clearListener()");
+        gateway.unregisterListener(this);
+        gateway = null;
+        registersDataNodeList.clear();
+        registersErrorNodeList.clear();
+    }
+
+    @Override
+    public void registerReaded(String nodeID, String EUI64Addr, short register, short errorCode, String data, Gateway gtwy) {
+        logger.trace("GtwyLstnrRegisterRead::registerReaded(nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ", register=" + register + ", errorCode=" + errorCode + ", data=" + data + ", gtwy=" + gtwy + ")");
+        synchronized (this) {
+            // comprobamos el resultado
+            if (errorCode == 0) { // resultado OK
+                // recuperamos la lista de registros del nodo
+                HashMap<String, String> registerList = registersDataNodeList.get(EUI64Addr);
+                if (registerList == null) {
+                    registerList = new HashMap<String, String>();
+                }
+
+                // guardamos el valor del registro
+                registerList.put(String.format("%02X", register), data);
+
+                // guardamos la lista de registros
+                registersDataNodeList.put(EUI64Addr, registerList);
+
+            } else { // resultado NOK
+                // recuperamos la lista de registros del nodo
+                HashMap<String, String> registerList = registersErrorNodeList.get(EUI64Addr);
+                if (registerList == null) {
+                    registerList = new HashMap<String, String>();
+                }
+
+                // guardamos el código de error
+                registerList.put(String.format("%02X", register), String.format("%02X", errorCode));
+
+                // guardamos la lista de registros
+                registersErrorNodeList.put(EUI64Addr, registerList);
+
+            }
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterWrited.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterWrited.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrRegisterWrited.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,140 @@
+/*
+ * 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.driver.impl.util;
+
+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.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle RegisterWrited notifications
+ * @author Alvaro
+ */
+public class GtwyLstnrRegisterWrited extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    HashMap<String, String> errorCodeNodeList = new HashMap<String, String>();
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+    // variables para consultar resultado despues de espera
+    String errorMessage = "";
+
+    public GtwyLstnrRegisterWrited(Gateway gtwy) {
+        logger.trace("GtwyLstnrRegisterWrited::GtwyLstnrRegisterWrited(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación de 
+     * registro escrito para el nodo indicado, o hasta que transcurra el tiempo 
+     * máximo indicado
+     * @param EUI64Addr Dirección del nodo
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si la operación de escritura ha ido OK, y False si se recibe
+     * erroCode distinto de 0 o pasa el tiempo máximo
+     */
+    public boolean waitForRegisterWrited(String EUI64Addr, long milliseconds) {
+        logger.trace("GatewayRegisterReadListener::waitForRegisterWrited(EUI64Addr=" + EUI64Addr + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+
+            // iniciamos bucle de espera
+            while (!errorCodeNodeList.containsKey(EUI64Addr)) {
+                try {
+                    // esperamos notificación de lectura de registro
+                    this.wait(wakeUpDelay);
+
+                    // comprobamos si hemos recibido resultado de escritura
+                    if (errorCodeNodeList.containsKey(EUI64Addr)) {
+                        String errorCode = errorCodeNodeList.get(EUI64Addr);
+                        errorMessage = errorCode;
+                        clearListener();
+                        if (errorCode.equals("00")) {
+                            logger.info(String.format("[Waiting RegisterWrited] SWRITE of node %s received", EUI64Addr));
+                            return true;
+                        } else {
+                            logger.warn(String.format("[Waiting RegisterWrited] Error awaiting SWRITE of node %s. Error code: %s", EUI64Addr, errorMessage));
+                            return false;
+                        }
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting RegisterWrited] Timeout awaiting SWRITE of node %s", EUI64Addr));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+        }
+
+        // si hemos llegado a este punto, es porque el resutlado ha llegado antes de esperar
+        String errorCode = errorCodeNodeList.get(EUI64Addr);
+        errorMessage = errorCode;
+        clearListener();
+        if (errorCode.equals("00")) {
+            logger.info(String.format("[Waiting RegisterWrited] SWRITE of node %s received", EUI64Addr));
+            return true;
+        } else {
+            logger.warn(String.format("[Waiting RegisterWrited] Error retrieving SWRITE of node %s. Error code: %s", EUI64Addr, errorMessage));
+            return false;
+        }
+    }
+
+    /**
+     * Recupera el código de error despues de esperar
+     * @return errorMessage
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GatewayRegisterReadListener::clearListener()");
+        gateway.unregisterListener(this);
+        errorCodeNodeList.clear();
+    }
+
+    @Override
+    public void registerWrited(String nodeID, String EUI64Addr, short errorCode, Gateway gtwy) {
+        logger.trace("GatewayRegisterReadListener::registerWrited(nodeID=" + nodeID + ", EUI64Addr=" + EUI64Addr + ", errorCode=" + errorCode + ", gtwy=" + gtwy + ")");
+        synchronized (this) {
+            // guardamos el resultado
+            errorCodeNodeList.put(EUI64Addr, String.format("%02X", errorCode));
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrSourceRoute.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrSourceRoute.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/GtwyLstnrSourceRoute.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,118 @@
+/*
+ * 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.driver.impl.util;
+
+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.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * GatewayListener to handle SourceRoute notifications
+ * @author HowLab, University of Zaragoza (alvaro)
+ */
+public class GtwyLstnrSourceRoute extends AbstractGatewayListener {
+
+    final Gateway gateway;
+    HashMap<String, String[]> SRList = new HashMap<String, String[]>();
+    // Logger  
+    Log logger = LogFactory.getLog(this.getClass().getName());
+
+    public GtwyLstnrSourceRoute(Gateway gtwy) {
+        logger.trace("GtwyLstnrSourceRoute::GtwyLstnrSourceRoute(gtwy=" + gtwy + ")");
+        gateway = gtwy;
+        gateway.registerListener(this);
+    }
+
+    /**
+     * Bloquea la ejecución hasta que el listener reciba una notificación de SR 
+     * para la direccion indicada, o hasta que transcurra el tiempo máximo 
+     * indicado
+     * @param EUI64Addr Direccion del nodo
+     * @param milliseconds Tiempo máximo de bloqueo
+     * @return True si se recibe el SR, o false si pasa el tiempo indicado
+     */
+    public boolean waitForSourceRoute(String EUI64Addr, long milliseconds) {
+        logger.trace("GtwyLstnrSourceRoute::waitForSourceRoute(EUI64Addr=" + EUI64Addr + ", milliseconds=" + milliseconds + ")");
+
+        synchronized (this) {
+            logger.info(String.format("[Waiting SourceRoute] waiting SR:XX,%s... for %d milliseconds", EUI64Addr, milliseconds));
+            // preparamos tiempos de espera
+            long endWaitTime = System.currentTimeMillis() + milliseconds;
+            long wakeUpDelay = milliseconds;
+            // iniciamos bucle de espera
+            while (!SRList.containsKey(EUI64Addr)) {
+                try {
+                    // esperamos notificación de SR
+                    this.wait(wakeUpDelay);
+                    // comprobamos si ha llegado el SR
+                    if (SRList.containsKey(EUI64Addr)) {
+                        logger.info(String.format("[Waiting SourceRoute] SR:XX,%s... received", EUI64Addr));
+                        clearListener();
+                        return true;
+                    }
+                    // Calculamos tiempo restante
+                    wakeUpDelay = endWaitTime - System.currentTimeMillis();
+                    // comprobamos timeout
+                    if (wakeUpDelay <= 0) {
+                        logger.warn(String.format("[Waiting SourceRoute] Timeout awaiting SR:XX,%s", EUI64Addr));
+                        clearListener();
+                        return false;
+                    }
+                } catch (InterruptedException ex) {
+                    // no hacemos nada
+                }
+            }
+            // si hemos llegado aquí, es porque el SR había llegado antes de empezar a esperar, devolvemos OK
+            logger.info(String.format("[Waiting SourceRoute] SR:XX,%s... received", EUI64Addr));
+            clearListener();
+            return true;
+        }
+    }
+
+    /**
+     * Función para operaciones de cierre del listener
+     */
+    @Override
+    public void clearListener() {
+        logger.trace("GtwyLstnrSourceRoute::clearListener()");
+        gateway.unregisterListener(this);
+        SRList.clear();
+    }
+
+    @Override
+    public void routeRecordReceived(String EUI64Addr, int numHops, String[] route, Gateway gtwy) {
+        logger.trace("GtwyLstnrSourceRoute::routeRecordReceived(EUI64Addr=" + EUI64Addr + ", numHops=" + numHops + ", route=" + route + ", gtwy=" + gtwy + ")");
+        if (SRList == null) {
+            return;
+        }
+        synchronized (this) {
+            // guardamos el SR
+            SRList.put(EUI64Addr, route);
+
+            // notificamos procesos en espera
+            this.notifyAll();
+        }
+
+    }
+
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/Register305.java
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/Register305.java (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/java/es/unizar/howlab/core/zigbee/telegesis/driver/impl/util/Register305.java Thu Feb  2 13:18:42 2012
@@ -1,0 +1,203 @@
+/*
+ * 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.driver.impl.util;
+
+/**
+ *
+ * @author Alvaro
+ */
+public enum Register305 {
+
+    CHANNEL_MASK((short) 0x00, false, "FFFF", true, true, false, false),
+    TRANSMIT_POWER_LEVEL((short) 0x01, false, "3", true, true, false, false),
+    PREFERRED_PAN_ID((short) 0x02, false, "0000", true, true, false, false),
+    PREFERRED_EXTENDED_PAN_ID((short) 0x03, false, "0000000000000000", true, true, false, false),
+    LOCAL_EUI((short) 0x04, false, "null", true, false, false, false),
+    LOCAL_NODEID((short) 0x05, false, "null", true, false, false, false),
+    PARENT_EUI((short) 0x06, false, "null", true, false, false, false),
+    PARENT_NODEID((short) 0x07, false, "null", true, false, false, false),
+    NETWORK_KEY((short) 0x08, true, "00000000000000000000000000000000", false, true, false, false),
+    TRUST_CENTRE_LINK_KEY((short) 0x09, true, "00000000000000000000000000000000", false, true, false, false),
+    MAIN_FUNCTION((short) 0x0A, true, "0000", true, true, false, false),
+    USER_READABLE_NAME((short) 0x0B, true, "Telegesis", true, true, false, false),
+    PASSWORD((short) 0x0C, true, "password", true, true, false, false),
+    DEVICE_INFORMATION((short) 0x0D, false, "null", true, false, false, false),
+    PROMPT_ENABLE_1((short) 0x0E, false, "0000", true, true, false, false),
+    PROMPT_ENABLE_2((short) 0x0F, false, "0006", true, true, false, false),
+    EXTENDED_FUNCTION((short) 0x10, false, "0000", true, true, false, false),
+    DEVICE_SPECIFIC((short) 0x11, false, "0005", true, true, false, false),
+    UART_SETUP((short) 0x12, false, "0500", true, true, false, false),
+    PULL_UP_ENABLE((short) 0x13, false, "0000", true, true, false, true),
+    PULL_DOWN_ENABLE((short) 0x14, false, "0000", true, true, false, true),
+    IO_CONFIGURATION((short) 0x15, false, "00000600", true, true, false, true),
+    DATA_DIRECTION_OF_IO_PORT((short) 0x16, false, "00F8", true, true, true, false),
+    INITIAL_VALUE_OF_S16((short) 0x17, false, "00F8", true, true, false, true),
+    OUTPUT_BUFFER_OF_IO_PORT((short) 0x18, false, "00F0", true, true, true, false),
+    INITIAL_VALUE_OF_S18((short) 0x19, false, "00F0", true, true, false, true),
+    INPUT_BUFFER_OF_IO_PORT((short) 0x1A, false, "null", true, false, true, false),
+    SPECIAL_FUNCTION_PIN_1((short) 0x1B, false, "3A98", true, true, true, false),
+    INITIAL_VALUE_OF_S1B((short) 0x1C, false, "3A98", true, true, false, true),
+    SPECIAL_FUNCTION_PIN_2((short) 0x1D, false, "1D4C", true, true, true, false),
+    INITIAL_VALUE_OF_S1D((short) 0x1E, false, "1D4C", true, true, false, true),
+    A_D1((short) 0x1F, false, "null", true, false, false, false),
+    A_D2((short) 0x20, false, "null", true, false, false, false),
+    A_D3((short) 0x21, false, "null", true, false, false, false),
+    A_D4((short) 0x22, false, "null", true, false, false, false),
+    IMMEDIATE_FUNCTIONALITY_AT_IRQ0((short) 0x23, false, "0001", true, true, false, false),
+    IMMEDIATE_FUNCTIONALITY_AT_IRQ1((short) 0x24, false, "0000", true, true, false, false),
+    IMMEDIATE_FUNCTIONALITY_AT_IRQ2((short) 0x25, false, "0000", true, true, false, false),
+    IMMEDIATE_FUNCTIONALITY_AT_IRQ3((short) 0x26, false, "0000", true, true, false, false),
+    FUNCTIONALITY_1_AT_BOOT_UP((short) 0x27, false, "0000", true, true, false, false),
+    FUNCTIONALITY_AT_NETWORK_JOIN((short) 0x28, false, "0000", true, true, false, false),
+    TIMER_COUNTER_0((short) 0x29, false, "0004", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_0((short) 0x2A, false, "8010", true, true, false, false),
+    TIMER_COUNTER_1((short) 0x2B, false, "00F0", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_1((short) 0x2C, false, "821E", true, true, false, false),
+    TIMER_COUNTER_2((short) 0x2D, false, "00F4", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_2((short) 0x2E, false, "8014", true, true, false, false),
+    TIMER_COUNTER_3((short) 0x2F, false, "00F2", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_3((short) 0x30, false, "8015", true, true, false, false),
+    TIMER_COUNTER_4((short) 0x31, false, "0000", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_4((short) 0x32, false, "0000", true, true, false, false),
+    TIMER_COUNTER_5((short) 0x33, false, "0000", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_5((short) 0x34, false, "0000", true, true, false, false),
+    TIMER_COUNTER_6((short) 0x35, false, "0000", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_6((short) 0x36, false, "0000", true, true, false, false),
+    TIMER_COUNTER_7((short) 0x37, false, "0000", true, true, false, false),
+    FUNCTIONALITY_FOR_TIMER_COUNTER_7((short) 0x38, false, "0000", true, true, false, false),
+    POWER_MODE((short) 0x39, false, "0000", true, true, true, false),
+    INITIAL_POWER_MODE((short) 0x3A, false, "0000", true, true, false, true),
+    START_UP_FUNCTIONALITY_PLAINTEXT_A((short) 0x3B, false, "BUTTON3", true, true, false, false),
+    START_UP_FUNCTIONALITY_PLAINTEXT_B((short) 0x3C, false, "BUTTON4", true, true, false, false),
+    SUPPLY_VOLTAGE((short) 0x3D, false, "null", true, false, false, false),
+    MULTICAST_TABLE_ENTRY_00((short) 0x3E, false, "0000", true, true, false, false),
+    MULTICAST_TABLE_ENTRY_01((short) 0x3F, false, "0000", true, true, false, false),
+    SOURCE_AND_DESTINATION_ENDPOINTS_FOR_XCASTS((short) 0x40, false, "0101", true, true, true, false),
+    INITIAL_VALUE_OF_S40((short) 0x41, false, "0101", true, true, false, true),
+    CLUSTER_ID_FOR_XCASTS((short) 0x42, false, "0002", true, true, true, false),
+    INITIAL_VALUE_OF_S42((short) 0x43, false, "0002", true, true, false, true),
+    PROFILE_ID_FOR_XCASTS((short) 0x44, false, "C091", true, true, true, false),
+    INITIAL_VALUE_OF_S44((short) 0x45, false, "C091", true, true, false, true),
+    START_UP_FUNCTIONALITY_32_BIT_NUMBER((short) 0x46, false, "00000000", true, true, true, false),
+    POWER_DESCRIPTOR((short) 0x47, false, "C110", true, true, false, false),
+    ENDPOINT_2_PROFILE_ID((short) 0x48, false, "C091", true, true, false, false),
+    ENDPOINT_2_DEVICE_ID((short) 0x49, false, "0000", true, true, false, false),
+    ENDPOINT_2_DEVICE_VERSION((short) 0x4A, false, "0000", true, true, false, false),
+    ENDPOINT_2_INPUT_CLUSTER_LIST((short) 0x4B, false, "0000", true, true, false, false),
+    ENDPOINT_2_OUTPUT_CLUSTER_LIST((short) 0x4C, false, "0000", true, true, false, false),
+    MOBILE_END_DEVICE_POLL_TIMEOUT((short) 0x4D, false, "0014", true, true, false, true),
+    END_DEVICE_POLL_TIMEOUT((short) 0x4E, false, "0605", true, true, false, true),
+    MAC_TIMEOUT((short) 0x4F, false, "0BB8", true, true, false, true);
+    private final short address;
+    private final boolean password;
+    private final String defaultValue;
+    private final boolean writable;
+    private final boolean readable;
+    private final boolean volatil;
+    private final boolean reset;
+
+    /**
+     * 
+     * @param address
+     * @param password
+     * @param defaultValue
+     * @param writable
+     * @param readable
+     * @param volatil
+     * @param reset 
+     */
+    Register305(short address, boolean password, String defaultValue, boolean writable, boolean readable, boolean volatil, boolean reset) {
+        this.address = address;
+        this.password = password;
+        this.defaultValue = defaultValue;
+        this.writable = writable;
+        this.readable = readable;
+        this.volatil = volatil;
+        this.reset = reset;
+    }
+
+    /**
+     * Recupera la dirección asociada al registro
+     * @return 
+     */
+    public short getAddress() {
+        return address;
+    }
+
+    /**
+     * Indica si el registro está protegido por contraseña
+     * @return 
+     */
+    public boolean requiresPassword() {
+        return password;
+    }
+
+    /**
+     * Devuelve el valor por defecto del registro
+     * @return Valor, o null si no procede
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Indica si el registro se puede escribir
+     * @return 
+     */
+    public boolean isWritable() {
+        return writable;
+    }
+
+    /**
+     * Indica si el registro se puede leer
+     * @return 
+     */
+    public boolean isReadable() {
+        return readable;
+    }
+
+    /**
+     * Indica si el valor del registro se pierde al hacer un reset
+     * @return 
+     */
+    public boolean isVolatile() {
+        return volatil;
+    }
+    /**
+     * Indica si se requiere un reset para que el valor se actualice
+     * @return 
+     */
+    public boolean requiresReset() {
+        return reset;
+    }
+    
+    /**
+     * Devuelve el valor correspondiente a la dirección proporcionada
+     * @param address dirección del registro
+     * @return 
+     */
+    public static Register305 fromByte(short address){
+        Register305[] regs = Register305.values();
+        // recorremos todos los posibles valores
+        for (int i = 0; i < regs.length; i ++){
+            if (regs[i].getAddress() == address){
+                return regs[i];
+            }
+        }
+        return null;
+    }
+}

Added: projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/LICENSE
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/LICENSE (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/LICENSE Thu Feb  2 13:18:42 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-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/driver/es.unizar.howlab.core.zigbee.telegesis.driver.xml
==============================================================================
--- projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/driver/es.unizar.howlab.core.zigbee.telegesis.driver.xml (added)
+++ projects/zb4osgi/sandbox/howlab/telegesis-driver-impl/src/main/resources/es/unizar/howlab/core/zigbee/telegesis/driver/es.unizar.howlab.core.zigbee.telegesis.driver.xml Thu Feb  2 13:18:42 2012
@@ -1,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : 11 de agosto de 2011, 17:35
+    Author     : alvaro
+    Description:
+        Purpose of the document follows.
+                
+-->
+
+<root>
+    <es.unizar.howlab.core.zigbee.telegesis.driver>
+        <autostart>true</autostart><!-- Arranca el driver al crearlo -->
+        
+        <ack_timeout>3000</ack_timeout><!-- Timeout para respuestas ACK -->
+        <register_read_timeout>3000</register_read_timeout><!-- Timeout para respuestas register_read -->
+        <register_write_timeout>3000</register_write_timeout><!-- Timeout para respuestas regiter_write -->
+        <zdo_response_timeout>3000</zdo_response_timeout><!-- Timeout para respuestas ZDO (ep_list, ep_descriptor) -->
+        <neighbour_response_timeout>10000</neighbour_response_timeout><!-- Timeout para respuestas de tabla de vecinos -->
+
+        <check_zigbee_error>true</check_zigbee_error><!-- Comprueba los errores zigbee -->
+        
+        <check_zigbee_error_frame_delay>10</check_zigbee_error_frame_delay><!-- Tiempo de separación entre nodos para comprobacion de errores -->
+        <check_zigbee_error_maintenance_period>5</check_zigbee_error_maintenance_period><!-- Periodo para reintentar las comprobaciones de errores fallidas -->
+        <check_zigbee_error_recovery_period>1</check_zigbee_error_recovery_period><!-- Periodo para ejecutar la comprobación de errores en los nodos-->
+        <zigbee_error_level_threshold_1>2</zigbee_error_level_threshold_1><!-- Umbral de error para intentar recuperacion del nodo -->
+        <zigbee_error_level_threshold_2>3</zigbee_error_level_threshold_2><!-- Umbral de error para remover el nodo -->
+
+
+        <get_neighbours>true</get_neighbours><!-- Incluye la busqueda de vecinos en las tareas periódicas -->
+        <get_neighbours_frame_delay>5</get_neighbours_frame_delay><!-- Tiempo de separación entre nodos para busqueda de vecinos -->
+        <get_neighbours_recovery_period>5</get_neighbours_recovery_period> <!-- Periodo para reintentar las busquedas de vecinos fallidas -->
+        <get_neighbours_maintenance_period>60</get_neighbours_maintenance_period><!-- Periodo para actualizar los vecinos de los nodos -->
+        
+        <get_parent>true</get_parent><!-- Incluye la busqueda del padre en las tareas periódicas -->
+        <get_parent_frame_delay>5</get_parent_frame_delay><!-- Tiempo de separación entre nodos para busqueda de padre -->
+        <get_parent_recovery_period>5</get_parent_recovery_period> <!-- Periodo para reintentar las busquedas de padres fallidas -->
+        <get_parent_maintenance_period>60</get_parent_maintenance_period><!-- Periodo para actualizar los padres de los nodos -->
+        
+        <get_zigbee_devices>true</get_zigbee_devices><!-- Incluye la busqueda de endpoints en las tareas peiódicas -->
+        <get_zigbee_devices_frame_delay>5</get_zigbee_devices_frame_delay><!-- Tiempo de separación entre nodos para busqueda de endpoints -->
+        <get_zigbee_devices_recovery_period>5</get_zigbee_devices_recovery_period><!-- Periodo para reintentar las busquedas de endpoints fallidas -->
+        
+        <update_dongle_s_registers>false</update_dongle_s_registers><!-- Actualiza la configuracion del dongle al conectarlo -->
+        <update_node_s_registers>false</update_node_s_registers><!-- Actualiza la configuracion de los nodos al detectarlos -->
+        <update_node_s_registers_frame_delay>5</update_node_s_registers_frame_delay><!-- Tiempo de separación entre nodos para escritura de registros -->
+        <update_node_s_registers_recovery_period>5</update_node_s_registers_recovery_period><!-- Periodo para reintentar las escrituras de registros fallidas -->
+        
+        <s_register_password>Tormenta</s_register_password><!-- Contraseña para registros protegidos contra escritura -->
+        <s_reg_xcast_source_ep>02</s_reg_xcast_source_ep><!-- End point para mensajes enviados por el ZDO -->
+        <node_registers>
+            <address>dongle</address>    <!-- Registros a escribir en el dongle -->
+            <s_registers>
+                <s_register>
+                    <address>00</address>
+                    <value>3FFC</value>                    
+                </s_register>
+                <s_register>
+                    <address>02</address><!-- PID -->
+                    <value>1234</value>                    
+                </s_register>
+                <s_register>
+                    <address>09</address>
+                    <value>00123400000000000000000000000000</value>                    
+                </s_register>
+                <s_register>
+                    <address>0A</address>
+                    <value>001C</value>                    
+                </s_register>
+                <s_register>
+                    <address>0B</address>
+                    <value>COO_test1</value>                    
+                </s_register>
+                <s_register>
+                    <address>10</address>
+                    <value>159A</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4E</address>
+                    <value>0AE1</value>                    
+                </s_register>                
+                <s_register>
+                    <address>4F</address>
+                    <value>FFFF</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0E</address>
+                    <value>8000</value>                    
+                </s_register>                
+                <s_register>
+                    <address>0F</address>
+                    <value>0006</value>                    
+                </s_register>                
+                <s_register>
+                    <address>11</address>
+                    <value>0300</value>                    
+                </s_register>                
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                
+            </s_registers>
+        </node_registers>
+        <node_registers>  <!-- Registros a escribir en el nodo "0011223344556677" -->
+            <address>0011223344556677</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        <node_registers>  <!-- Registros a escribir en el nodo "8899aabbccddeeff" -->
+            <address>8899aabbccddeeff</address>
+            <s_registers>
+                <s_register>
+                    <address>12</address>
+                    <value>0C10</value>                    
+                </s_register>                            
+            </s_registers>
+        </node_registers>            
+        
+    </es.unizar.howlab.core.zigbee.telegesis.driver>
+
+</root>




More information about the Commit mailing list