diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..212386fe9c39a5fa8804e8ba83d7b6af144d7f80
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,84 @@
+# Pre-requisites about cmake itself
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+if(COMMAND cmake_policy)
+  cmake_policy(SET CMP0005 NEW) 
+  cmake_policy(SET CMP0003 NEW) 
+endif(COMMAND cmake_policy)
+
+# The project name and the type of project
+PROJECT(comm)
+
+SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
+SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
+SET(CMAKE_INSTALL_PREFIX /usr/local)
+
+IF (NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE "DEBUG") 
+ENDIF (NOT CMAKE_BUILD_TYPE)
+
+SET(CMAKE_C_FLAGS_DEBUG "-g -Wall")
+SET(CMAKE_C_FLAGS_RELEASE "-O3")
+
+ADD_SUBDIRECTORY(src)
+
+FIND_PACKAGE(Doxygen)
+
+FIND_PATH(IRI_DOC_DIR doxygen.conf ${CMAKE_SOURCE_DIR}/doc/iri_doc/)
+IF (IRI_DOC_DIR)
+  ADD_CUSTOM_TARGET (doc ${DOXYGEN_EXECUTABLE} ${CMAKE_SOURCE_DIR}/doc/iri_doc/doxygen.conf)
+ELSE (IRI_DOC_DIR)
+  ADD_CUSTOM_TARGET (doc ${DOXYGEN_EXECUTABLE} ${CMAKE_SOURCE_DIR}/doc/doxygen.conf)
+ENDIF (IRI_DOC_DIR)
+
+ADD_CUSTOM_TARGET (distclean @echo cleaning cmake files)
+
+IF (UNIX)
+  ADD_CUSTOM_COMMAND(
+    COMMENT "distribution clean"
+    COMMAND make ARGS clean
+    COMMAND rm ARGS -rf ${CMAKE_SOURCE_DIR}/build/*
+
+    TARGET  distclean
+  )
+ELSE(UNIX)
+  ADD_CUSTOM_COMMAND(
+    COMMENT "distclean only implemented in unix"
+    TARGET  distclean
+  )
+ENDIF(UNIX)
+
+ADD_CUSTOM_TARGET (uninstall @echo uninstall package)
+
+IF (UNIX)
+  ADD_CUSTOM_COMMAND(
+    COMMENT "uninstall package"
+    COMMAND xargs ARGS rm < install_manifest.txt
+
+    TARGET  uninstall
+  )
+ELSE(UNIX)
+  ADD_CUSTOM_COMMAND(
+    COMMENT "uninstall only implemented in unix"
+    TARGET  uninstall
+  )
+ENDIF(UNIX)
+
+
+IF (UNIX)
+  SET(CPACK_PACKAGE_FILE_NAME "iri-${PROJECT_NAME}-dev-${CPACK_PACKAGE_VERSION}${DISTRIB}${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+  SET(CPACK_PACKAGE_NAME "iri-${PROJECT_NAME}-dev")
+  SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Part of IRI-laboratory libraries. More information at http://wikiri.upc.es/index.php/Robotics_Lab")
+  SET(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+  SET(CPACK_GENERATOR "DEB")
+  SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "labrobotica@iri.upc.edu")
+  SET(CPACK_SET_DESTDIR "ON")  # Necessary because of the absolute install paths
+
+  INCLUDE(CPack)
+ELSE(UNIX)
+  ADD_CUSTOM_COMMAND(
+    COMMENT "packaging only implemented in unix"
+    TARGET  uninstall
+  )
+ENDIF(UNIX)
+
diff --git a/Findcomm.cmake b/Findcomm.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8408e22ccf83143cb335c3760d48cbd32f8376c9
--- /dev/null
+++ b/Findcomm.cmake
@@ -0,0 +1,21 @@
+FIND_PATH(comm_INCLUDE_DIR comm.h commexceptions.h rs232.h rs232exceptions.h ftdiserver.h ftdimodule.h ftdiexcetpions.h socket.h socketclient.h socketserver.h socketexceptions.h /usr/include/iridrivers /usr/local/include/iridrivers)
+
+
+FIND_LIBRARY(comm_LIBRARY
+    NAMES comm
+    PATHS /usr/lib /usr/local/lib /usr/local/lib/iridrivers) 
+
+IF (comm_INCLUDE_DIR AND comm_LIBRARY)
+   SET(comm_FOUND TRUE)
+ENDIF (comm_INCLUDE_DIR AND comm_LIBRARY)
+
+IF (comm_FOUND)
+   IF (NOT comm_FIND_QUIETLY)
+      MESSAGE(STATUS "Found comm library: ${comm_LIBRARY}")
+   ENDIF (NOT comm_FIND_QUIETLY)
+ELSE (comm_FOUND)
+   IF (comm_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find comm library")
+   ENDIF (comm_FIND_REQUIRED)
+ENDIF (comm_FOUND)
+
diff --git a/ReadMe.txt b/ReadMe.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6095168a12c39397be843096b9cd6f6d7800c403
--- /dev/null
+++ b/ReadMe.txt
@@ -0,0 +1,17 @@
+Copyright (C) 2009-2010 Institut de Robòtica i Informàtica Industrial, CSIC-UPC.
+Author shernand (shernand@iri.upc.edu)
+All rights reserved.
+
+This file is part of IRI communications library
+IRI communications library is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+at your option) any later version.
+  
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+  
+You should have received a copy of the GNU Lesser General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
new file mode 100644
index 0000000000000000000000000000000000000000..347af2ef86bf4786d49b13d48c12146b0d001b01
--- /dev/null
+++ b/doc/doxygen.conf
@@ -0,0 +1,251 @@
+# Doxyfile 1.5.5
+
+@INCLUDE_PATH = ../doc/
+@INCLUDE = doxygen_project_name.conf
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NUMBER         = 
+OUTPUT_DIRECTORY       = ../doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = NO
+ABBREVIATE_BRIEF       = 
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+BUILTIN_STL_SUPPORT    = NO
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+TYPEDEF_HIDES_STRUCT   = NO
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = NO
+SORT_BRIEF_DOCS        = NO
+SORT_GROUP_NAMES       = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = YES
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = YES
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = ../src \
+                         ../doc/main.dox
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          = *.c \
+                         *.h \
+                         *.cpp
+RECURSIVE              = YES
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = *.tab.c \
+                         *.tab.h \
+                         lex* \
+                         *glr.h \
+                         *llr.h \
+                         *glr.c \
+                         *llr.c \
+                         *general.h
+EXCLUDE_SYMBOLS        = 
+EXAMPLE_PATH           = ../src/examples
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = ../doc/images
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+HTML_DYNAMIC_SECTIONS  = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = _USE_MPI=1
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+MSCGEN_PATH            = 
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = NO
+INCLUDED_BY_GRAPH      = NO
+CALL_GRAPH             = YES
+CALLER_GRAPH           = YES
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = NO
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 2
+DOT_TRANSPARENT        = YES
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
diff --git a/doc/doxygen_project_name.conf b/doc/doxygen_project_name.conf
new file mode 100644
index 0000000000000000000000000000000000000000..b8e4e368fcdb5e11cdbd8f9a97430c5f97ef6190
--- /dev/null
+++ b/doc/doxygen_project_name.conf
@@ -0,0 +1 @@
+PROJECT_NAME = "IRI communications"
diff --git a/doc/images/comm_states.eps b/doc/images/comm_states.eps
new file mode 100644
index 0000000000000000000000000000000000000000..0eb51e74a71d7b8a53d29b9699379e4582201846
--- /dev/null
+++ b/doc/images/comm_states.eps
@@ -0,0 +1,506 @@
+%!PS-Adobe-3.0 EPSF-3.0 
+%%BoundingBox: 0 0 794 595
+%%Pages: 0
+%%Creator: Sun Microsystems, Inc.
+%%Title: none
+%%CreationDate: none
+%%LanguageLevel: 2
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset SDRes-Prolog 1.0 0
+/b4_inc_state save def
+/dict_count countdictstack def
+/op_count count 1 sub def
+userdict begin
+0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath
+/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if
+/bdef {bind def} bind def
+/c {setgray} bdef
+/l {neg lineto} bdef
+/rl {neg rlineto} bdef
+/lc {setlinecap} bdef
+/lj {setlinejoin} bdef
+/lw {setlinewidth} bdef
+/ml {setmiterlimit} bdef
+/ld {setdash} bdef
+/m {neg moveto} bdef
+/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef
+/r {rotate} bdef
+/t {neg translate} bdef
+/s {scale} bdef
+/sw {show} bdef
+/gs {gsave} bdef
+/gr {grestore} bdef
+/f {findfont dup length dict begin
+{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def
+currentdict end /NFont exch definefont pop /NFont findfont} bdef
+/p {closepath} bdef
+/sf {scalefont setfont} bdef
+/ef {eofill}bdef
+/pc {closepath stroke}bdef
+/ps {stroke}bdef
+/pum {matrix currentmatrix}bdef
+/pom {setmatrix}bdef
+/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+%%Page: 1 1
+%%BeginPageSetup
+%%EndPageSetup
+pum
+0.02835 0.02833 s 
+0 -21000 t
+/tm matrix currentmatrix def
+gs
+0 0 m 27999 0 l 27999 20999 l 0 20999 l 0 0 l eoclip newpath
+gs
+0 0 m 27999 0 l 27999 20999 l 0 20999 l 0 0 l eoclip newpath
+0 0 m 28000 0 l 28000 21000 l 0 21000 l 0 0 l eoclip newpath
+gs
+gs
+pum
+1402 19590 t
+pom
+gr
+gr
+gs
+gs
+pum
+13937 19590 t
+pom
+gr
+gr
+0 lw 1 lj 0.000 c 10160 7773 m  9459 7773 8890 7204 8890 6503 ct 8890 5802 9459 5233 10160 5233 ct 
+10861 5233 11430 5802 11430 6503 ct 11430 7204 10861 7773 10160 7773 ct pc
+gs
+gs
+pum
+9340 6638 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+407 -196 m  403 -198 398 -200 393 -201 ct 388 -203 382 -203 376 -203 ct 355 -203 338 -196 327 -182 ct 
+315 -168 310 -148 310 -122 ct 310 0 l  271 0 l  271 -231 l  310 -231 l  310 -195 l 
+318 -210 328 -220 341 -227 ct 354 -234 369 -237 388 -237 ct 390 -237 393 -237 396 -236 ct 
+399 -236 403 -236 407 -235 ct 407 -196 l  p ef
+644 -125 m  644 -106 l  469 -106 l  471 -80 479 -60 493 -47 ct 507 -33 526 -26 552 -26 ct 
+566 -26 580 -28 594 -32 ct 608 -35 621 -41 635 -48 ct 635 -12 l  621 -6 607 -2 593 1 ct 
+579 4 564 6 549 6 ct 512 6 483 -5 462 -26 ct 440 -48 429 -77 429 -113 ct 429 -151 440 -181 460 -204 ct 
+480 -226 508 -237 543 -237 ct 574 -237 598 -227 617 -207 ct 635 -187 644 -160 644 -125 ct 
+p
+606 -136 m  605 -157 600 -174 588 -186 ct 577 -199 562 -205 543 -205 ct 522 -205 505 -199 492 -187 ct 
+480 -175 472 -158 470 -136 ct 606 -136 l  p ef
+814 -116 m  783 -116 762 -113 750 -106 ct 738 -99 732 -87 732 -70 ct 732 -56 737 -46 746 -38 ct 
+755 -30 767 -26 782 -26 ct 803 -26 820 -33 833 -48 ct 845 -63 852 -83 852 -108 ct 
+852 -116 l  814 -116 l  p
+890 -132 m  890 0 l  852 0 l  852 -35 l  843 -21 832 -11 819 -4 ct 806 3 791 6 772 6 ct 
+748 6 729 -1 715 -14 ct 701 -27 694 -45 694 -67 ct 694 -93 703 -113 721 -126 ct 
+738 -139 764 -146 799 -146 ct 852 -146 l  852 -150 l  852 -167 846 -181 835 -190 ct 
+823 -200 807 -205 786 -205 ct 773 -205 760 -203 747 -200 ct 735 -197 723 -192 711 -186 ct 
+711 -221 l  725 -226 739 -230 752 -233 ct 765 -236 778 -237 790 -237 ct 823 -237 848 -228 865 -211 ct 
+882 -194 890 -167 890 -132 ct p ef
+1004 -297 m  1004 -232 l  1083 -232 l  1083 -202 l  1004 -202 l  1004 -76 l 
+1004 -57 1007 -45 1012 -40 ct 1017 -35 1028 -32 1044 -32 ct 1083 -32 l  1083 0 l 
+1044 0 l  1014 0 994 -5 983 -16 ct 972 -27 966 -47 966 -76 ct 966 -202 l  938 -202 l 
+938 -232 l  966 -232 l  966 -297 l  1004 -297 l  p ef
+1330 -125 m  1330 -106 l  1155 -106 l  1157 -80 1165 -60 1179 -47 ct 1193 -33 1212 -26 1238 -26 ct 
+1252 -26 1266 -28 1280 -32 ct 1294 -35 1307 -41 1321 -48 ct 1321 -12 l  1307 -6 1293 -2 1279 1 ct 
+1265 4 1250 6 1235 6 ct 1198 6 1169 -5 1148 -26 ct 1126 -48 1115 -77 1115 -113 ct 
+1115 -151 1126 -181 1146 -204 ct 1166 -226 1194 -237 1229 -237 ct 1260 -237 1284 -227 1303 -207 ct 
+1321 -187 1330 -160 1330 -125 ct p
+1292 -136 m  1291 -157 1286 -174 1274 -186 ct 1263 -199 1248 -205 1229 -205 ct 
+1208 -205 1191 -199 1178 -187 ct 1166 -175 1158 -158 1156 -136 ct 1292 -136 l 
+p ef
+1547 -197 m  1547 -322 l  1585 -322 l  1585 0 l  1547 0 l  1547 -35 l 
+1539 -21 1529 -11 1517 -4 ct 1505 2 1490 6 1473 6 ct 1445 6 1422 -5 1405 -28 ct 
+1387 -50 1378 -80 1378 -116 ct 1378 -152 1387 -182 1405 -204 ct 1422 -227 1445 -238 1473 -238 ct 
+1490 -238 1505 -234 1517 -228 ct 1529 -221 1539 -211 1547 -197 ct p
+1418 -116 m  1418 -88 1423 -66 1435 -50 ct 1446 -34 1462 -26 1482 -26 ct 1502 -26 1518 -34 1530 -50 ct 
+1541 -66 1547 -88 1547 -116 ct 1547 -144 1541 -166 1530 -182 ct 1518 -198 1502 -206 1482 -206 ct 
+1462 -206 1446 -198 1435 -182 ct 1423 -166 1418 -144 1418 -116 ct p ef
+pom
+gr
+gr
+19685 7773 m  18984 7773 18415 7204 18415 6503 ct 18415 5802 18984 5233 19685 5233 ct 
+20386 5233 20955 5802 20955 6503 ct 20955 7204 20386 7773 19685 7773 ct pc
+gs
+gs
+pum
+18891 6638 t
+130 -205 m  109 -205 93 -197 81 -181 ct 69 -165 63 -143 63 -115 ct 63 -88 69 -66 81 -50 ct 
+93 -34 109 -26 130 -26 ct 150 -26 166 -34 178 -50 ct 189 -66 195 -88 195 -116 ct 
+195 -143 189 -165 178 -181 ct 166 -197 150 -205 130 -205 ct p
+130 -237 m  163 -237 189 -226 207 -205 ct 226 -183 236 -154 236 -115 ct 236 -78 226 -48 207 -26 ct 
+189 -5 163 6 130 6 ct 96 6 70 -5 52 -26 ct 33 -48 23 -78 23 -115 ct 23 -154 33 -183 52 -205 ct 
+70 -226 96 -237 130 -237 ct p ef
+335 -35 m  335 88 l  296 88 l  296 -231 l  335 -231 l  335 -196 l  343 -210 353 -220 365 -227 ct 
+377 -234 392 -237 409 -237 ct 437 -237 459 -226 477 -204 ct 495 -181 503 -152 503 -115 ct 
+503 -79 495 -50 477 -27 ct 459 -5 437 6 409 6 ct 392 6 377 3 365 -4 ct 353 -11 343 -21 335 -35 ct 
+p
+464 -116 m  464 -143 458 -165 447 -181 ct 435 -197 419 -205 399 -205 ct 379 -205 363 -197 352 -181 ct 
+340 -165 335 -143 335 -115 ct 335 -88 340 -66 352 -50 ct 363 -34 379 -26 399 -26 ct 
+419 -26 435 -34 447 -50 ct 458 -66 464 -88 464 -116 ct p ef
+763 -125 m  763 -106 l  588 -106 l  590 -80 598 -60 612 -47 ct 626 -33 645 -26 671 -26 ct 
+685 -26 699 -28 713 -32 ct 727 -35 740 -41 754 -48 ct 754 -12 l  740 -6 726 -2 712 1 ct 
+698 4 683 6 668 6 ct 631 6 602 -5 581 -26 ct 559 -48 548 -77 548 -113 ct 548 -151 559 -181 579 -204 ct 
+599 -226 627 -237 662 -237 ct 693 -237 717 -227 736 -207 ct 754 -187 763 -160 763 -125 ct 
+p
+725 -136 m  724 -157 719 -174 707 -186 ct 696 -199 681 -205 662 -205 ct 641 -205 624 -199 611 -187 ct 
+599 -175 591 -158 589 -136 ct 725 -136 l  p ef
+1019 -140 m  1019 0 l  981 0 l  981 -138 l  981 -160 977 -177 968 -188 ct 
+960 -199 947 -204 930 -204 ct 909 -204 893 -197 881 -184 ct 870 -171 864 -153 864 -131 ct 
+864 0 l  825 0 l  825 -231 l  864 -231 l  864 -195 l  873 -209 883 -220 896 -227 ct 
+908 -234 922 -237 938 -237 ct 965 -237 985 -229 999 -212 ct 1012 -196 1019 -172 1019 -140 ct 
+p ef
+1292 -125 m  1292 -106 l  1117 -106 l  1119 -80 1127 -60 1141 -47 ct 1155 -33 1174 -26 1200 -26 ct 
+1214 -26 1228 -28 1242 -32 ct 1256 -35 1269 -41 1283 -48 ct 1283 -12 l  1269 -6 1255 -2 1241 1 ct 
+1227 4 1212 6 1197 6 ct 1160 6 1131 -5 1110 -26 ct 1088 -48 1077 -77 1077 -113 ct 
+1077 -151 1088 -181 1108 -204 ct 1128 -226 1156 -237 1191 -237 ct 1222 -237 1246 -227 1265 -207 ct 
+1283 -187 1292 -160 1292 -125 ct p
+1254 -136 m  1253 -157 1248 -174 1236 -186 ct 1225 -199 1210 -205 1191 -205 ct 
+1170 -205 1153 -199 1140 -187 ct 1128 -175 1120 -158 1118 -136 ct 1254 -136 l 
+p ef
+1509 -197 m  1509 -322 l  1547 -322 l  1547 0 l  1509 0 l  1509 -35 l 
+1501 -21 1491 -11 1479 -4 ct 1467 2 1452 6 1435 6 ct 1407 6 1384 -5 1367 -28 ct 
+1349 -50 1340 -80 1340 -116 ct 1340 -152 1349 -182 1367 -204 ct 1384 -227 1407 -238 1435 -238 ct 
+1452 -238 1467 -234 1479 -228 ct 1491 -221 1501 -211 1509 -197 ct p
+1380 -116 m  1380 -88 1385 -66 1397 -50 ct 1408 -34 1424 -26 1444 -26 ct 1464 -26 1480 -34 1492 -50 ct 
+1503 -66 1509 -88 1509 -116 ct 1509 -144 1503 -166 1492 -182 ct 1480 -198 1464 -206 1444 -206 ct 
+1424 -206 1408 -198 1397 -182 ct 1385 -166 1380 -144 1380 -116 ct p ef
+pom
+gr
+gr
+19685 15393 m  18984 15393 18415 14824 18415 14123 ct 18415 13422 18984 12853 19685 12853 ct 
+20386 12853 20955 13422 20955 14123 ct 20955 14824 20386 15393 19685 15393 ct 
+pc
+gs
+gs
+pum
+18547 14258 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+363 -205 m  342 -205 326 -197 314 -181 ct 302 -165 296 -143 296 -115 ct 296 -88 302 -66 314 -50 ct 
+326 -34 342 -26 363 -26 ct 383 -26 399 -34 411 -50 ct 422 -66 428 -88 428 -116 ct 
+428 -143 422 -165 411 -181 ct 399 -197 383 -205 363 -205 ct p
+363 -237 m  396 -237 422 -226 440 -205 ct 459 -183 469 -154 469 -115 ct 469 -78 459 -48 440 -26 ct 
+422 -5 396 6 363 6 ct 329 6 303 -5 285 -26 ct 266 -48 256 -78 256 -115 ct 256 -154 266 -183 285 -205 ct 
+303 -226 329 -237 363 -237 ct p ef
+723 -140 m  723 0 l  685 0 l  685 -138 l  685 -160 681 -177 672 -188 ct 664 -199 651 -204 634 -204 ct 
+613 -204 597 -197 585 -184 ct 574 -171 568 -153 568 -131 ct 568 0 l  529 0 l 
+529 -231 l  568 -231 l  568 -195 l  577 -209 587 -220 600 -227 ct 612 -234 626 -237 642 -237 ct 
+669 -237 689 -229 703 -212 ct 716 -196 723 -172 723 -140 ct p ef
+915 -322 m  915 -290 l  879 -290 l  865 -290 856 -288 850 -282 ct 845 -277 842 -267 842 -252 ct 
+842 -232 l  905 -232 l  905 -202 l  842 -202 l  842 0 l  804 0 l  804 -202 l 
+768 -202 l  768 -232 l  804 -232 l  804 -248 l  804 -274 810 -293 822 -304 ct 
+834 -316 853 -322 879 -322 ct 915 -322 l  p ef
+946 -232 m  984 -232 l  984 -1 l  946 -1 l  946 -232 l  p
+946 -322 m  984 -322 l  984 -274 l  946 -274 l  946 -322 l  p ef
+1216 -118 m  1216 -146 1210 -167 1199 -182 ct 1188 -198 1172 -205 1151 -205 ct 
+1131 -205 1115 -198 1104 -182 ct 1092 -167 1087 -146 1087 -118 ct 1087 -91 1092 -70 1104 -55 ct 
+1115 -39 1131 -32 1151 -32 ct 1172 -32 1188 -39 1199 -55 ct 1210 -70 1216 -91 1216 -118 ct 
+p
+1254 -29 m  1254 11 1245 40 1228 59 ct 1210 78 1184 88 1148 88 ct 1134 88 1122 87 1110 85 ct 
+1098 83 1086 80 1075 76 ct 1075 39 l  1086 45 1097 49 1108 52 ct 1119 55 1130 57 1142 57 ct 
+1166 57 1185 50 1197 37 ct 1210 24 1216 4 1216 -22 ct 1216 -41 l  1208 -27 1198 -17 1186 -10 ct 
+1174 -3 1159 0 1142 0 ct 1114 0 1091 -11 1073 -32 ct 1056 -54 1047 -83 1047 -118 ct 
+1047 -154 1056 -183 1073 -205 ct 1091 -226 1114 -237 1142 -237 ct 1159 -237 1174 -234 1186 -227 ct 
+1198 -220 1208 -210 1216 -196 ct 1216 -231 l  1254 -231 l  1254 -29 l  p ef
+1327 -91 m  1327 -231 l  1365 -231 l  1365 -93 l  1365 -71 1369 -54 1378 -43 ct 
+1386 -33 1399 -27 1416 -27 ct 1437 -27 1453 -34 1465 -47 ct 1477 -60 1483 -78 1483 -100 ct 
+1483 -231 l  1521 -231 l  1521 0 l  1483 0 l  1483 -36 l  1473 -21 1463 -11 1451 -4 ct 
+1438 3 1424 6 1408 6 ct 1382 6 1361 -2 1348 -19 ct 1334 -35 1327 -59 1327 -91 ct 
+p
+p ef
+1732 -196 m  1728 -198 1723 -200 1718 -201 ct 1713 -203 1707 -203 1701 -203 ct 
+1680 -203 1663 -196 1652 -182 ct 1640 -168 1635 -148 1635 -122 ct 1635 0 l  1596 0 l 
+1596 -231 l  1635 -231 l  1635 -195 l  1643 -210 1653 -220 1666 -227 ct 1679 -234 1694 -237 1713 -237 ct 
+1715 -237 1718 -237 1721 -236 ct 1724 -236 1728 -236 1732 -235 ct 1732 -196 l 
+p ef
+1969 -125 m  1969 -106 l  1794 -106 l  1796 -80 1804 -60 1818 -47 ct 1832 -33 1851 -26 1877 -26 ct 
+1891 -26 1905 -28 1919 -32 ct 1933 -35 1946 -41 1960 -48 ct 1960 -12 l  1946 -6 1932 -2 1918 1 ct 
+1904 4 1889 6 1874 6 ct 1837 6 1808 -5 1787 -26 ct 1765 -48 1754 -77 1754 -113 ct 
+1754 -151 1765 -181 1785 -204 ct 1805 -226 1833 -237 1868 -237 ct 1899 -237 1923 -227 1942 -207 ct 
+1960 -187 1969 -160 1969 -125 ct p
+1931 -136 m  1930 -157 1925 -174 1913 -186 ct 1902 -199 1887 -205 1868 -205 ct 
+1847 -205 1830 -199 1817 -187 ct 1805 -175 1797 -158 1795 -136 ct 1931 -136 l 
+p ef
+2186 -197 m  2186 -322 l  2224 -322 l  2224 0 l  2186 0 l  2186 -35 l 
+2178 -21 2168 -11 2156 -4 ct 2144 2 2129 6 2112 6 ct 2084 6 2061 -5 2044 -28 ct 
+2026 -50 2017 -80 2017 -116 ct 2017 -152 2026 -182 2044 -204 ct 2061 -227 2084 -238 2112 -238 ct 
+2129 -238 2144 -234 2156 -228 ct 2168 -221 2178 -211 2186 -197 ct p
+2057 -116 m  2057 -88 2062 -66 2074 -50 ct 2085 -34 2101 -26 2121 -26 ct 2141 -26 2157 -34 2169 -50 ct 
+2180 -66 2186 -88 2186 -116 ct 2186 -144 2180 -166 2169 -182 ct 2157 -198 2141 -206 2121 -206 ct 
+2101 -206 2085 -198 2074 -182 ct 2062 -166 2057 -144 2057 -116 ct p ef
+pom
+gr
+gr
+18785 5603 m  18414 5307 l  18666 5144 l  18785 5603 l  p ef
+1 lw 0 lj 11058 5603 m  11064 5543 l  11080 5484 l  11107 5428 l  11145 5374 l 
+11249 5270 l  11390 5175 l  11565 5087 l  11771 5007 l  12265 4869 l  12850 4762 l 
+13503 4685 l  14922 4624 l  16340 4685 l  16993 4762 l  17578 4869 l  18072 5007 l 
+18278 5087 l  18453 5175 l  18594 5270 l  18620 5296 l  ps
+gs
+gs
+pum
+14076 4336 t
+130 -205 m  109 -205 93 -197 81 -181 ct 69 -165 63 -143 63 -115 ct 63 -88 69 -66 81 -50 ct 
+93 -34 109 -26 130 -26 ct 150 -26 166 -34 178 -50 ct 189 -66 195 -88 195 -116 ct 
+195 -143 189 -165 178 -181 ct 166 -197 150 -205 130 -205 ct p
+130 -237 m  163 -237 189 -226 207 -205 ct 226 -183 236 -154 236 -115 ct 236 -78 226 -48 207 -26 ct 
+189 -5 163 6 130 6 ct 96 6 70 -5 52 -26 ct 33 -48 23 -78 23 -115 ct 23 -154 33 -183 52 -205 ct 
+70 -226 96 -237 130 -237 ct p ef
+335 -35 m  335 88 l  296 88 l  296 -231 l  335 -231 l  335 -196 l  343 -210 353 -220 365 -227 ct 
+377 -234 392 -237 409 -237 ct 437 -237 459 -226 477 -204 ct 495 -181 503 -152 503 -115 ct 
+503 -79 495 -50 477 -27 ct 459 -5 437 6 409 6 ct 392 6 377 3 365 -4 ct 353 -11 343 -21 335 -35 ct 
+p
+464 -116 m  464 -143 458 -165 447 -181 ct 435 -197 419 -205 399 -205 ct 379 -205 363 -197 352 -181 ct 
+340 -165 335 -143 335 -115 ct 335 -88 340 -66 352 -50 ct 363 -34 379 -26 399 -26 ct 
+419 -26 435 -34 447 -50 ct 458 -66 464 -88 464 -116 ct p ef
+763 -125 m  763 -106 l  588 -106 l  590 -80 598 -60 612 -47 ct 626 -33 645 -26 671 -26 ct 
+685 -26 699 -28 713 -32 ct 727 -35 740 -41 754 -48 ct 754 -12 l  740 -6 726 -2 712 1 ct 
+698 4 683 6 668 6 ct 631 6 602 -5 581 -26 ct 559 -48 548 -77 548 -113 ct 548 -151 559 -181 579 -204 ct 
+599 -226 627 -237 662 -237 ct 693 -237 717 -227 736 -207 ct 754 -187 763 -160 763 -125 ct 
+p
+725 -136 m  724 -157 719 -174 707 -186 ct 696 -199 681 -205 662 -205 ct 641 -205 624 -199 611 -187 ct 
+599 -175 591 -158 589 -136 ct 725 -136 l  p ef
+1019 -140 m  1019 0 l  981 0 l  981 -138 l  981 -160 977 -177 968 -188 ct 
+960 -199 947 -204 930 -204 ct 909 -204 893 -197 881 -184 ct 870 -171 864 -153 864 -131 ct 
+864 0 l  825 0 l  825 -231 l  864 -231 l  864 -195 l  873 -209 883 -220 896 -227 ct 
+908 -234 922 -237 938 -237 ct 965 -237 985 -229 999 -212 ct 1012 -196 1019 -172 1019 -140 ct 
+p ef
+1185 -322 m  1167 -290 1153 -259 1144 -228 ct 1135 -197 1131 -166 1131 -134 ct 
+1131 -102 1135 -70 1144 -39 ct 1153 -8 1167 23 1185 55 ct 1152 55 l  1131 23 1116 -9 1106 -41 ct 
+1095 -72 1090 -103 1090 -134 ct 1090 -164 1095 -195 1106 -227 ct 1116 -258 1131 -289 1152 -322 ct 
+1185 -322 l  p ef
+1253 -322 m  1286 -322 l  1307 -289 1322 -258 1332 -227 ct 1343 -195 1348 -164 1348 -134 ct 
+1348 -103 1343 -72 1332 -41 ct 1322 -9 1307 23 1286 55 ct 1253 55 l  1271 23 1285 -8 1294 -39 ct 
+1303 -70 1307 -102 1307 -134 ct 1307 -166 1303 -197 1294 -228 ct 1285 -259 1271 -290 1253 -322 ct 
+p ef
+pom
+gr
+gr
+11058 7401 m  11508 7251 l  11508 7551 l  11058 7401 l  p ef
+18785 7401 m  11418 7401 l  ps
+gs
+gs
+pum
+14208 7247 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+273 -322 m  311 -322 l  311 0 l  273 0 l  273 -322 l  p ef
+481 -205 m  460 -205 444 -197 432 -181 ct 420 -165 414 -143 414 -115 ct 414 -88 420 -66 432 -50 ct 
+444 -34 460 -26 481 -26 ct 501 -26 517 -34 529 -50 ct 540 -66 546 -88 546 -116 ct 
+546 -143 540 -165 529 -181 ct 517 -197 501 -205 481 -205 ct p
+481 -237 m  514 -237 540 -226 558 -205 ct 577 -183 587 -154 587 -115 ct 587 -78 577 -48 558 -26 ct 
+540 -5 514 6 481 6 ct 447 6 421 -5 403 -26 ct 384 -48 374 -78 374 -115 ct 374 -154 384 -183 403 -205 ct 
+421 -226 447 -237 481 -237 ct p ef
+797 -225 m  797 -189 l  787 -194 775 -198 764 -201 ct 752 -204 740 -205 728 -205 ct 
+709 -205 695 -202 685 -197 ct 676 -191 671 -182 671 -170 ct 671 -162 675 -155 681 -150 ct 
+688 -145 702 -140 722 -135 ct 735 -132 l  762 -127 781 -119 793 -108 ct 804 -97 810 -83 810 -64 ct 
+810 -42 801 -25 784 -13 ct 767 0 744 6 714 6 ct 702 6 689 5 675 2 ct 662 0 648 -4 633 -8 ct 
+633 -48 l  647 -40 661 -35 674 -31 ct 688 -28 702 -26 715 -26 ct 733 -26 747 -29 756 -35 ct 
+766 -41 771 -50 771 -61 ct 771 -71 767 -79 760 -85 ct 753 -90 738 -96 715 -101 ct 
+701 -104 l  678 -109 661 -116 650 -127 ct 640 -137 635 -151 635 -169 ct 635 -191 642 -207 658 -219 ct 
+673 -231 695 -237 723 -237 ct 737 -237 751 -236 763 -234 ct 775 -232 787 -229 797 -225 ct 
+p ef
+1068 -125 m  1068 -106 l  893 -106 l  895 -80 903 -60 917 -47 ct 931 -33 950 -26 976 -26 ct 
+990 -26 1004 -28 1018 -32 ct 1032 -35 1045 -41 1059 -48 ct 1059 -12 l  1045 -6 1031 -2 1017 1 ct 
+1003 4 988 6 973 6 ct 936 6 907 -5 886 -26 ct 864 -48 853 -77 853 -113 ct 853 -151 864 -181 884 -204 ct 
+904 -226 932 -237 967 -237 ct 998 -237 1022 -227 1041 -207 ct 1059 -187 1068 -160 1068 -125 ct 
+p
+1030 -136 m  1029 -157 1024 -174 1012 -186 ct 1001 -199 986 -205 967 -205 ct 
+946 -205 929 -199 916 -187 ct 904 -175 896 -158 894 -136 ct 1030 -136 l  p ef
+1223 -322 m  1205 -290 1191 -259 1182 -228 ct 1173 -197 1169 -166 1169 -134 ct 
+1169 -102 1173 -70 1182 -39 ct 1191 -8 1205 23 1223 55 ct 1190 55 l  1169 23 1154 -9 1144 -41 ct 
+1133 -72 1128 -103 1128 -134 ct 1128 -164 1133 -195 1144 -227 ct 1154 -258 1169 -289 1190 -322 ct 
+1223 -322 l  p ef
+1291 -322 m  1324 -322 l  1345 -289 1360 -258 1370 -227 ct 1381 -195 1386 -164 1386 -134 ct 
+1386 -103 1381 -72 1370 -41 ct 1360 -9 1345 23 1324 55 ct 1291 55 l  1309 23 1323 -8 1332 -39 ct 
+1341 -70 1345 -102 1345 -134 ct 1345 -166 1341 -197 1332 -228 ct 1323 -259 1309 -290 1291 -322 ct 
+p ef
+pom
+gr
+gr
+10159 5233 m  9910 4829 l  10202 4761 l  10159 5233 l  p ef
+4475 2927 m  4479 2989 l  4491 3047 l  4511 3101 l  4539 3153 l  4616 3246 l 
+4719 3329 l  4848 3400 l  5000 3462 l  5363 3563 l  5793 3638 l  6273 3697 l 
+7317 3799 l  8361 3936 l  8841 4039 l  9271 4175 l  9462 4259 l  9634 4355 l 
+9786 4463 l  9915 4585 l  10018 4722 l  10095 4875 l  10097 4880 l  ps
+gs
+gs
+pum
+5953 3331 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+407 -196 m  403 -198 398 -200 393 -201 ct 388 -203 382 -203 376 -203 ct 355 -203 338 -196 327 -182 ct 
+315 -168 310 -148 310 -122 ct 310 0 l  271 0 l  271 -231 l  310 -231 l  310 -195 l 
+318 -210 328 -220 341 -227 ct 354 -234 369 -237 388 -237 ct 390 -237 393 -237 396 -236 ct 
+399 -236 403 -236 407 -235 ct 407 -196 l  p ef
+644 -125 m  644 -106 l  469 -106 l  471 -80 479 -60 493 -47 ct 507 -33 526 -26 552 -26 ct 
+566 -26 580 -28 594 -32 ct 608 -35 621 -41 635 -48 ct 635 -12 l  621 -6 607 -2 593 1 ct 
+579 4 564 6 549 6 ct 512 6 483 -5 462 -26 ct 440 -48 429 -77 429 -113 ct 429 -151 440 -181 460 -204 ct 
+480 -226 508 -237 543 -237 ct 574 -237 598 -227 617 -207 ct 635 -187 644 -160 644 -125 ct 
+p
+606 -136 m  605 -157 600 -174 588 -186 ct 577 -199 562 -205 543 -205 ct 522 -205 505 -199 492 -187 ct 
+480 -175 472 -158 470 -136 ct 606 -136 l  p ef
+814 -116 m  783 -116 762 -113 750 -106 ct 738 -99 732 -87 732 -70 ct 732 -56 737 -46 746 -38 ct 
+755 -30 767 -26 782 -26 ct 803 -26 820 -33 833 -48 ct 845 -63 852 -83 852 -108 ct 
+852 -116 l  814 -116 l  p
+890 -132 m  890 0 l  852 0 l  852 -35 l  843 -21 832 -11 819 -4 ct 806 3 791 6 772 6 ct 
+748 6 729 -1 715 -14 ct 701 -27 694 -45 694 -67 ct 694 -93 703 -113 721 -126 ct 
+738 -139 764 -146 799 -146 ct 852 -146 l  852 -150 l  852 -167 846 -181 835 -190 ct 
+823 -200 807 -205 786 -205 ct 773 -205 760 -203 747 -200 ct 735 -197 723 -192 711 -186 ct 
+711 -221 l  725 -226 739 -230 752 -233 ct 765 -236 778 -237 790 -237 ct 823 -237 848 -228 865 -211 ct 
+882 -194 890 -167 890 -132 ct p ef
+1004 -297 m  1004 -232 l  1083 -232 l  1083 -202 l  1004 -202 l  1004 -76 l 
+1004 -57 1007 -45 1012 -40 ct 1017 -35 1028 -32 1044 -32 ct 1083 -32 l  1083 0 l 
+1044 0 l  1014 0 994 -5 983 -16 ct 972 -27 966 -47 966 -76 ct 966 -202 l  938 -202 l 
+938 -232 l  966 -232 l  966 -297 l  1004 -297 l  p ef
+1330 -125 m  1330 -106 l  1155 -106 l  1157 -80 1165 -60 1179 -47 ct 1193 -33 1212 -26 1238 -26 ct 
+1252 -26 1266 -28 1280 -32 ct 1294 -35 1307 -41 1321 -48 ct 1321 -12 l  1307 -6 1293 -2 1279 1 ct 
+1265 4 1250 6 1235 6 ct 1198 6 1169 -5 1148 -26 ct 1126 -48 1115 -77 1115 -113 ct 
+1115 -151 1126 -181 1146 -204 ct 1166 -226 1194 -237 1229 -237 ct 1260 -237 1284 -227 1303 -207 ct 
+1321 -187 1330 -160 1330 -125 ct p
+1292 -136 m  1291 -157 1286 -174 1274 -186 ct 1263 -199 1248 -205 1229 -205 ct 
+1208 -205 1191 -199 1178 -187 ct 1166 -175 1158 -158 1156 -136 ct 1292 -136 l 
+p ef
+1486 -322 m  1468 -290 1454 -259 1445 -228 ct 1436 -197 1432 -166 1432 -134 ct 
+1432 -102 1436 -70 1445 -39 ct 1454 -8 1468 23 1486 55 ct 1453 55 l  1432 23 1417 -9 1407 -41 ct 
+1396 -72 1391 -103 1391 -134 ct 1391 -164 1396 -195 1407 -227 ct 1417 -258 1432 -289 1453 -322 ct 
+1486 -322 l  p ef
+1554 -322 m  1587 -322 l  1608 -289 1623 -258 1633 -227 ct 1644 -195 1649 -164 1649 -134 ct 
+1649 -103 1644 -72 1633 -41 ct 1623 -9 1608 23 1587 55 ct 1554 55 l  1572 23 1586 -8 1595 -39 ct 
+1604 -70 1608 -102 1608 -134 ct 1608 -166 1604 -197 1595 -228 ct 1586 -259 1572 -290 1554 -322 ct 
+p ef
+pom
+gr
+gr
+19684 12853 m  19549 12398 l  19849 12408 l  19684 12853 l  p ef
+20583 7401 m  20544 8733 l  20500 9200 l  20443 9560 l  20374 9834 l  20299 10041 l 
+20217 10202 l  20134 10336 l  20050 10464 l  19968 10605 l  19893 10780 l 
+19824 11008 l  19767 11309 l  19723 11704 l  19696 12493 l  ps
+gs
+gs
+pum
+20558 10554 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+363 -205 m  342 -205 326 -197 314 -181 ct 302 -165 296 -143 296 -115 ct 296 -88 302 -66 314 -50 ct 
+326 -34 342 -26 363 -26 ct 383 -26 399 -34 411 -50 ct 422 -66 428 -88 428 -116 ct 
+428 -143 422 -165 411 -181 ct 399 -197 383 -205 363 -205 ct p
+363 -237 m  396 -237 422 -226 440 -205 ct 459 -183 469 -154 469 -115 ct 469 -78 459 -48 440 -26 ct 
+422 -5 396 6 363 6 ct 329 6 303 -5 285 -26 ct 266 -48 256 -78 256 -115 ct 256 -154 266 -183 285 -205 ct 
+303 -226 329 -237 363 -237 ct p ef
+723 -140 m  723 0 l  685 0 l  685 -138 l  685 -160 681 -177 672 -188 ct 664 -199 651 -204 634 -204 ct 
+613 -204 597 -197 585 -184 ct 574 -171 568 -153 568 -131 ct 568 0 l  529 0 l 
+529 -231 l  568 -231 l  568 -195 l  577 -209 587 -220 600 -227 ct 612 -234 626 -237 642 -237 ct 
+669 -237 689 -229 703 -212 ct 716 -196 723 -172 723 -140 ct p ef
+915 -322 m  915 -290 l  879 -290 l  865 -290 856 -288 850 -282 ct 845 -277 842 -267 842 -252 ct 
+842 -232 l  905 -232 l  905 -202 l  842 -202 l  842 0 l  804 0 l  804 -202 l 
+768 -202 l  768 -232 l  804 -232 l  804 -248 l  804 -274 810 -293 822 -304 ct 
+834 -316 853 -322 879 -322 ct 915 -322 l  p ef
+946 -232 m  984 -232 l  984 -1 l  946 -1 l  946 -232 l  p
+946 -322 m  984 -322 l  984 -274 l  946 -274 l  946 -322 l  p ef
+1216 -118 m  1216 -146 1210 -167 1199 -182 ct 1188 -198 1172 -205 1151 -205 ct 
+1131 -205 1115 -198 1104 -182 ct 1092 -167 1087 -146 1087 -118 ct 1087 -91 1092 -70 1104 -55 ct 
+1115 -39 1131 -32 1151 -32 ct 1172 -32 1188 -39 1199 -55 ct 1210 -70 1216 -91 1216 -118 ct 
+p
+1254 -29 m  1254 11 1245 40 1228 59 ct 1210 78 1184 88 1148 88 ct 1134 88 1122 87 1110 85 ct 
+1098 83 1086 80 1075 76 ct 1075 39 l  1086 45 1097 49 1108 52 ct 1119 55 1130 57 1142 57 ct 
+1166 57 1185 50 1197 37 ct 1210 24 1216 4 1216 -22 ct 1216 -41 l  1208 -27 1198 -17 1186 -10 ct 
+1174 -3 1159 0 1142 0 ct 1114 0 1091 -11 1073 -32 ct 1056 -54 1047 -83 1047 -118 ct 
+1047 -154 1056 -183 1073 -205 ct 1091 -226 1114 -237 1142 -237 ct 1159 -237 1174 -234 1186 -227 ct 
+1198 -220 1208 -210 1216 -196 ct 1216 -231 l  1254 -231 l  1254 -29 l  p ef
+1422 -322 m  1404 -290 1390 -259 1381 -228 ct 1372 -197 1368 -166 1368 -134 ct 
+1368 -102 1372 -70 1381 -39 ct 1390 -8 1404 23 1422 55 ct 1389 55 l  1368 23 1353 -9 1343 -41 ct 
+1332 -72 1327 -103 1327 -134 ct 1327 -164 1332 -195 1343 -227 ct 1353 -258 1368 -289 1389 -322 ct 
+1422 -322 l  p ef
+1490 -322 m  1523 -322 l  1544 -289 1559 -258 1569 -227 ct 1580 -195 1585 -164 1585 -134 ct 
+1585 -103 1580 -72 1569 -41 ct 1559 -9 1544 23 1523 55 ct 1490 55 l  1508 23 1522 -8 1531 -39 ct 
+1540 -70 1544 -102 1544 -134 ct 1544 -166 1540 -197 1531 -228 ct 1522 -259 1508 -290 1490 -322 ct 
+p ef
+pom
+gr
+gr
+10159 7773 m  10359 8203 l  10060 8237 l  10159 7773 l  p ef
+18785 13223 m  18760 12834 l  18688 12484 l  18572 12171 l  18414 11892 l 
+18219 11644 l  17989 11426 l  17727 11234 l  17437 11066 l  16784 10792 l 
+16056 10585 l  14472 10290 l  12888 10021 l  12160 9846 l  11507 9618 l 
+11217 9478 l  10955 9317 l  10725 9132 l  10530 8922 l  10372 8683 l  10256 8414 l 
+10189 8132 l  ps
+gs
+gs
+pum
+14843 10131 t
+206 -223 m  206 -187 l  196 -193 185 -197 174 -200 ct 163 -203 152 -205 141 -205 ct 
+117 -205 97 -197 84 -181 ct 70 -166 63 -144 63 -115 ct 63 -87 70 -65 84 -50 ct 
+97 -34 117 -26 141 -26 ct 152 -26 163 -28 174 -31 ct 185 -34 196 -38 206 -44 ct 
+206 -9 l  196 -4 185 0 173 2 ct 162 5 150 6 137 6 ct 102 6 75 -5 54 -27 ct 34 -49 23 -78 23 -115 ct 
+23 -153 34 -183 54 -205 ct 75 -226 104 -237 140 -237 ct 151 -237 163 -236 174 -233 ct 
+185 -231 196 -227 206 -223 ct p ef
+273 -322 m  311 -322 l  311 0 l  273 0 l  273 -322 l  p ef
+481 -205 m  460 -205 444 -197 432 -181 ct 420 -165 414 -143 414 -115 ct 414 -88 420 -66 432 -50 ct 
+444 -34 460 -26 481 -26 ct 501 -26 517 -34 529 -50 ct 540 -66 546 -88 546 -116 ct 
+546 -143 540 -165 529 -181 ct 517 -197 501 -205 481 -205 ct p
+481 -237 m  514 -237 540 -226 558 -205 ct 577 -183 587 -154 587 -115 ct 587 -78 577 -48 558 -26 ct 
+540 -5 514 6 481 6 ct 447 6 421 -5 403 -26 ct 384 -48 374 -78 374 -115 ct 374 -154 384 -183 403 -205 ct 
+421 -226 447 -237 481 -237 ct p ef
+797 -225 m  797 -189 l  787 -194 775 -198 764 -201 ct 752 -204 740 -205 728 -205 ct 
+709 -205 695 -202 685 -197 ct 676 -191 671 -182 671 -170 ct 671 -162 675 -155 681 -150 ct 
+688 -145 702 -140 722 -135 ct 735 -132 l  762 -127 781 -119 793 -108 ct 804 -97 810 -83 810 -64 ct 
+810 -42 801 -25 784 -13 ct 767 0 744 6 714 6 ct 702 6 689 5 675 2 ct 662 0 648 -4 633 -8 ct 
+633 -48 l  647 -40 661 -35 674 -31 ct 688 -28 702 -26 715 -26 ct 733 -26 747 -29 756 -35 ct 
+766 -41 771 -50 771 -61 ct 771 -71 767 -79 760 -85 ct 753 -90 738 -96 715 -101 ct 
+701 -104 l  678 -109 661 -116 650 -127 ct 640 -137 635 -151 635 -169 ct 635 -191 642 -207 658 -219 ct 
+673 -231 695 -237 723 -237 ct 737 -237 751 -236 763 -234 ct 775 -232 787 -229 797 -225 ct 
+p ef
+1068 -125 m  1068 -106 l  893 -106 l  895 -80 903 -60 917 -47 ct 931 -33 950 -26 976 -26 ct 
+990 -26 1004 -28 1018 -32 ct 1032 -35 1045 -41 1059 -48 ct 1059 -12 l  1045 -6 1031 -2 1017 1 ct 
+1003 4 988 6 973 6 ct 936 6 907 -5 886 -26 ct 864 -48 853 -77 853 -113 ct 853 -151 864 -181 884 -204 ct 
+904 -226 932 -237 967 -237 ct 998 -237 1022 -227 1041 -207 ct 1059 -187 1068 -160 1068 -125 ct 
+p
+1030 -136 m  1029 -157 1024 -174 1012 -186 ct 1001 -199 986 -205 967 -205 ct 
+946 -205 929 -199 916 -187 ct 904 -175 896 -158 894 -136 ct 1030 -136 l  p ef
+1223 -322 m  1205 -290 1191 -259 1182 -228 ct 1173 -197 1169 -166 1169 -134 ct 
+1169 -102 1173 -70 1182 -39 ct 1191 -8 1205 23 1223 55 ct 1190 55 l  1169 23 1154 -9 1144 -41 ct 
+1133 -72 1128 -103 1128 -134 ct 1128 -164 1133 -195 1144 -227 ct 1154 -258 1169 -289 1190 -322 ct 
+1223 -322 l  p ef
+1291 -322 m  1324 -322 l  1345 -289 1360 -258 1370 -227 ct 1381 -195 1386 -164 1386 -134 ct 
+1386 -103 1381 -72 1370 -41 ct 1360 -9 1345 23 1324 55 ct 1291 55 l  1309 23 1323 -8 1332 -39 ct 
+1341 -70 1345 -102 1345 -134 ct 1345 -166 1341 -197 1332 -228 ct 1323 -259 1309 -290 1291 -322 ct 
+p ef
+pom
+gr
+gr
+gr
+gs
+0 0 m 27999 0 l 27999 20999 l 0 20999 l 0 0 l eoclip newpath
+gr
+gr
+0 21000 t 
+pom
+count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore
+%%PageTrailer
+%%Trailer
+%%EOF
diff --git a/doc/images/comm_states.odp b/doc/images/comm_states.odp
new file mode 100644
index 0000000000000000000000000000000000000000..3cd96c6f84857f1dd2ad958453ade4ecf691d861
Binary files /dev/null and b/doc/images/comm_states.odp differ
diff --git a/doc/images/comm_states.png b/doc/images/comm_states.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9a452f08de48c6415ee98a66a1c8bc346d6ab27
Binary files /dev/null and b/doc/images/comm_states.png differ
diff --git a/doc/main.dox b/doc/main.dox
new file mode 100644
index 0000000000000000000000000000000000000000..73bc774760e8e2ea0f44d11c80f6151860fc69a7
--- /dev/null
+++ b/doc/main.dox
@@ -0,0 +1,143 @@
+/*! \mainpage IRI Communications
+
+  \section Introduction
+
+  This set of drivers for standard communication devices. This library offers a 
+  generic communication device which can be used to create drivers for new 
+  communication devices easily: it is only necessary to implement the low level, 
+  operating system dependent functions, all the other features are already 
+  implemented.
+
+  The main features of all communication devices are:
+
+      - Data is automatically received and stored into a data FIFO by an internal thread.
+      - An event is generated whenever there is new data into this FIFO. Read operations are non-blocking.
+      - An event is generated when an unexpected error happen.
+      - Only a few functions have to be implemented to generate a new driver.
+
+  The communication devices currently supported by this library include:
+
+      - serial port: This drivers provides a simple and easy to use yet 
+        complete interface to a standard computer serial port. This driver allows 
+        the user to open any available serial port, configure it as needed and send 
+        and receive data to and from it. Some USB devices can also use this driver 
+        (those that appear as a virtual COM port). 
+
+      - ftdi driver: This driver is intended to be used to interface with 
+        devices with any of the following FTDI chips:
+            - FT2232H
+            - FT4232H
+            - FT232R
+            - FT245R
+            - FT2232
+            - FT232B
+            - FT245B
+            - FT8U232AM
+            - FT8U245AM
+   This driver can also be used with USB devices that appear as virtual serial 
+   ports in the host computer. In this case it is also possible to use the serial 
+   port driver
+
+      - sockets: This driver provide an implementation of server and client 
+        TCP sockets in Linux. UDP connections are not yet supported. The server 
+        side can handle as many connections as needed, providing notifications for 
+        the following event for each of the connections:
+            - new connection 
+            - disconnection 
+            - reception of new data
+
+        Both the client and server can be used with other implementations of the POSIX sockets.
+
+  \section Installation
+
+  \subsection Pre-Requisites
+
+  This package requires of the following libraries and packages
+	 - <A href="http://www.cmake.org">cmake</A>, a cross-platform build system.
+	 - <A href="http://www.doxygen.org">doxygen</a> and 
+	   <A href="http://www.graphviz.org">graphviz</a> to generate the documentation.
+         - <A href="http://wikiri.upc.es/index.php/Utilities_library">utilities library</a>, a set of basic tools to develop software.
+	 .
+  
+  All the IRI-related dependencies can be automatically installed by calling 
+   - sudo make dep
+   .
+  from the <em>build</em> folder and after calling the <em>cmake ..</em> command.
+
+  Under MacOS most of the packages are available via <a href="http://www.finkproject.org/">fink</a>. <br>
+
+  \subsection Compilation
+
+  Just download this package, uncompress it, and execute
+   - cd build
+   - cmake ..
+   .
+  to generate the makefile and then
+   - make
+   .
+  to obtain the executable (in this example called <em>main_example</em>).
+
+  The <em>cmake</em> only need to be executed once (make will automatically call
+  <em>cmake</em> if you modify one of the <em>CMakeList.txt</em> files).
+
+  To generate this documentation type
+       - make doc
+       .
+
+  The files in the <em>build</em> directory are genetated by <em>cmake</em>
+  and <em>make</em> and can be safely removed.
+  After doing so you will need to call cmake manually again.
+
+  \subsection Configuration
+
+  The default build mode is DEBUG. That is, objects and executables 
+  include debug information.
+
+  The RELEASE build mode optimizes for speed. To build in this mode
+  execute
+      - cmake .. -DCMAKE_BUILD_TYPE=RELEASE
+      .
+  The release mode will be kept until next time cmake is executed.
+
+  \section Customization
+
+  To build a new application using these library, first it is necessary to locate if the library
+  has been installed or not using the following command
+
+      - FIND_PACKAGE(comm)
+
+  In the case that the package is present, it is necessary to add the header files directory to
+  the include directory path by using
+
+      - INCLUDE_DIRECTORIES(${comm_INCLUDE_DIR})
+
+  Finally, it is also nevessary to link with the desired libraries by using the following command
+
+      - TARGET_LINK_LIBRARIES(<executable name> ${comm_LIBRARY})
+      .
+
+  All these steps are automatically done when the new project is created following the instructions
+  in <A href="http://wikiri.upc.es/index.php/Create_a_new_development_project">here</a>
+
+  \section License
+
+  This package is licensed under a 
+  <a href="http://creativecommons.org/licenses/by/3.0/">
+    Creative Commons Attribution 3.0 Unported License</a>.
+
+  \section Disclaimer
+
+  This package is distributed in the hope that it will be useful, but without any warranty. 
+  it is provided "as is" without warranty of any kind, either expressed or implied, including, 
+  but not limited to, the implied warranties of merchantability and fitness for a particular 
+  purpose. The entire risk as to the quality and performance of the program is with you. 
+  should the program prove defective, the GMR group does not assume the cost of any necessary 
+  servicing, repair  or correction.
+
+  In no event unless required by applicable law the author will be liable to you for damages, 
+  including any general, special, incidental or consequential damages arising out of the use or 
+  inability to use the program (including but not limited to loss of data or data being rendered 
+  inaccurate or losses sustained by you or third parties or a failure of the program to operate 
+  with any other programs), even if the author has been advised of the possibility of such damages. 
+
+ */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6fc247ffff1ca50868db59fb35c64addc004f27e
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,57 @@
+FIND_PATH(FTDI_INCLUDE_DIR ftd2xx.h WinTypes.h /usr/include/ /usr/local/include/)
+
+FIND_LIBRARY(FTDI_LIBRARY
+    NAMES ftd2xx
+    PATHS /usr/lib /usr/local/lib)
+
+IF(FTDI_INCLUDE_DIR AND FTDI_LIBRARY)
+  SET(BUILD_FTDI TRUE)
+ELSE(FTDI_INCLUDE_DIR AND FTDI_LIBRARY)
+  MESSAGE(STATUS "FTDI library won't be build. Impossible to locate the necessary files")     
+ENDIF(FTDI_INCLUDE_DIR AND FTDI_LIBRARY)
+
+# edit the following line to add all the source code files of the library
+SET(sources ./comm.cpp ./commexceptions.cpp ./serial/rs232.cpp ./serial/rs232exceptions.cpp  ./sockets/socket.cpp ./sockets/socketclient.cpp ./sockets/socketserver.cpp ./sockets/socketexceptions.cpp)
+# edit the following line to add all the header files of the library
+SET(headers ./comm.h ./commexceptions.h ./serial/rs232.h ./serial/rs232exceptions.h ./sockets/socket.h ./sockets/socketclient.h ./sockets/socketserver.h ./sockets/socketexceptions.h)
+
+IF(BUILD_FTDI)
+  SET(sources ${sources} ./usb_ftdi/ftdiserver.cpp ./usb_ftdi/ftdimodule.cpp ./usb_ftdi/ftdiexceptions.cpp)
+  SET(headers ${headers} ./usb_ftdi/ftdiserver.h ./usb_ftdi/ftdimodule.h ./usb_ftdi/ftdiexceptions.h)
+ENDIF(BUILD_FTDI)
+
+INCLUDE_DIRECTORIES(.)
+
+# edit the following line to find the necessary packages
+FIND_PACKAGE(iriutils REQUIRED)
+
+INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR})
+
+# edit the following line to add the necessary include directories
+INCLUDE_DIRECTORIES(./serial ./usb_ftdi ./sockets)
+
+IF(BUILD_FTDI)
+  INCLUDE_DIRECTORIES(${FTDI_INCLUDE_DIR})
+ENDIF(BUILD_FTDI)
+
+ADD_LIBRARY(comm SHARED ${sources})
+
+#edit the following line to add the necessary system libraries (if any)
+
+TARGET_LINK_LIBRARIES(comm ${iriutils_LIBRARY})
+
+IF(BUILD_FTDI) 
+  TARGET_LINK_LIBRARIES(comm ${FTDI_LIBRARY})
+ENDIF(BUILD_FTDI)
+
+INSTALL(TARGETS comm
+  RUNTIME DESTINATION bin
+  LIBRARY DESTINATION lib/iridrivers
+  ARCHIVE DESTINATION lib/iridrivers
+)
+
+INSTALL(FILES ${headers} DESTINATION include/iridrivers)
+
+INSTALL(FILES ../Findcomm.cmake DESTINATION ${CMAKE_ROOT}/Modules/)
+
+ADD_SUBDIRECTORY(examples)
diff --git a/src/comm.cpp b/src/comm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..643753534fdb643b299f1acff51f2f0aecf3282e
--- /dev/null
+++ b/src/comm.cpp
@@ -0,0 +1,328 @@
+#include <string.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+#include "comm.h"
+#include "commexceptions.h"
+#include "ctime.h"
+
+CComm::CComm(const std::string& comm_id) 
+{
+  this->rx_event_id="";
+  this->error_event_id="";
+  this->comm_thread_id="";
+  this->error_msg="";
+  this->state=created;
+  try{
+    this->set_id(comm_id);
+    /* get a reference to the event handler */
+    this->event_server=CEventServer::instance();
+    /* create the events */
+    this->rx_event_id+=comm_id;
+    this->rx_event_id+="_rx_event_id";
+    this->event_server->create_event(this->rx_event_id);
+    this->error_event_id+=comm_id;
+    this->error_event_id+="_error_event";
+    this->event_server->create_event(this->error_event_id);
+    /* get the reference to the thread handler */
+    this->thread_server=CThreadServer::instance();
+    /* create the thread */
+    this->comm_thread_id+=comm_id;
+    this->comm_thread_id+="_comm_thread";
+    this->thread_server->create_thread(this->comm_thread_id);
+    /* attach the thread function */
+    this->thread_server->attach_thread(this->comm_thread_id,comm_thread,this);
+  }catch(CException &e){
+    this->close();
+    /* delete the events */
+    throw;
+  }
+}
+
+void CComm::set_id(const std::string& comm_id)
+{
+  if(comm_id.size()==0)
+  {
+    /* handle exceptions */
+    throw CCommException(_HERE_,"Invalid communication id.\n","empty name");
+  }
+  else
+    this->comm_id=comm_id;
+}
+
+std::string& CComm::get_id(void)
+{
+  return this->comm_id;
+}
+
+void CComm::open(void *comm_dev)
+{
+  if(this->state==created)
+  {
+    try{
+      this->access_comm.enter();
+      this->hard_open(comm_dev);
+      this->thread_server->start_thread(this->comm_thread_id);
+      this->state=opened;
+      this->access_comm.exit();
+    }catch(CException &e){
+      this->access_comm.exit();
+      /* handle exception */
+      throw;
+    }
+  }
+  else
+  {
+    /* handle exceptions */
+    throw CCommException(_HERE_,"The communication device is already opened\n.",this->comm_id);
+  }
+}
+
+void CComm::config(void *config)
+{
+  this->access_comm.enter();
+  if(this->state==created)
+  { 
+    this->access_comm.exit();
+    /* handle exceptions */
+    throw CCommException(_HERE_,"The communication device has not been opened yet.\n",this->comm_id);
+  }
+  else
+  {
+    try{
+      if(this->state==opened)
+        this->state=configured;
+      /* otherwise, keep the current state */
+      this->hard_config(config);
+    }catch(CException &e){
+      this->access_comm.exit();
+      /* handle exception */
+      throw;
+    }
+  }
+  this->access_comm.exit();
+}
+
+int CComm::read(unsigned char *data,int len)
+{
+  int num_available=0;
+  int i=0;
+
+  if(data==NULL)
+  {
+    /* handle exceptions */
+    throw CCommException(_HERE_,"Invalid data buffer to save the data received (NULL pointer).\n",this->comm_id);
+  }
+  else
+  {
+    if(this->state==configured || this->state==sending)
+    {
+      this->access_comm.enter();
+      num_available=this->receive_queue.size();
+      if(len>num_available)
+      {
+        len=num_available;
+        this->event_server->reset_event(this->rx_event_id);
+      }
+      for(i=0;i<len;i++)
+      {
+        data[i]=*this->receive_queue.begin();
+        this->receive_queue.pop_front();
+      }
+      this->access_comm.exit();
+      return len;
+    }
+    else
+    {
+      throw CCommException(_HERE_,"The communication device is not configured yet.\n",this->comm_id);
+    }
+  }
+  return len;
+}
+
+int CComm::write(unsigned char *data,int len)
+{
+  int written_len=0;
+
+  if(data==NULL)
+  {
+    /* handle exceptions */
+    throw CCommException(_HERE_,"Invalid data buffer to be sent (NULL pointer).\n",this->comm_id);
+  }  
+  else
+  {
+    this->access_comm.enter();
+    if(this->state==configured)
+    {
+      try{
+        written_len=this->hard_write(data,len);
+      }catch(CException &e){
+        this->access_comm.exit();
+        /* handle exceptions */
+        throw;
+      }
+      if(written_len!=len)
+      {
+        /* handle exceptions */
+        this->access_comm.exit();
+        throw CCommException(_HERE_,"Unexpected error while writing to the communication device.\n",this->comm_id);
+      }
+    }
+    else
+    {
+      this->access_comm.exit();
+      throw CCommException(_HERE_,"The communication device is not configured yet.\n",this->comm_id);
+    }
+    this->access_comm.exit();
+    return len;
+  }
+  return len;
+}
+
+unsigned int CComm::get_num_data(void)
+{
+  unsigned int num=0;
+
+  if(this->state==configured || this->state==sending)
+  {
+    this->access_comm.enter();
+    num=this->receive_queue.size();
+    this->access_comm.exit();
+  }
+
+  return num;
+}
+
+std::string& CComm::get_rx_event_id(void)
+{
+  return this->rx_event_id;
+}
+
+std::string& CComm::get_error_event_id(void)
+{
+  return this->error_event_id;
+}
+
+std::string& CComm::get_error(void)
+{
+  return this->error_msg;
+}
+
+int CComm::get_state(void)
+{
+  return this->state;
+}
+
+void CComm::close(void)
+{
+  if(this->state==configured || this->state==sending || this->state==opened)
+  {
+    /* finish the thread */
+    if(this->state==configured)
+      this->thread_server->kill_thread(this->comm_thread_id);
+    /* close the communication device */
+    this->access_comm.try_enter();
+    try{
+      this->hard_close();
+    }catch(CException &e){
+      this->access_comm.exit();
+      /* handle exceptions */
+      throw;
+    }
+    /* flush the data queues */
+    this->receive_queue.erase(this->receive_queue.begin(),this->receive_queue.end());
+    /* change the current state */
+    this->state=created;
+    this->access_comm.exit();
+  }
+}
+
+void *CComm::comm_thread(void *param)
+{
+  CComm *comm_dev=(CComm *)param;
+  int wait_result;
+  bool end=false;
+
+  while(!end)
+  {
+    wait_result=comm_dev->hard_wait_comm_event();
+    comm_dev->access_comm.enter();
+    if(wait_result==-1)
+      end=true;
+    else
+    {
+      if(wait_result==1)/* data has been received */
+      {
+        comm_dev->on_receive(); 
+      }
+      if(wait_result==2)
+      {
+        comm_dev->on_error();
+      }
+    }
+    comm_dev->access_comm.exit();
+  }
+  /* handle exceptions */
+//  throw CCommException(_HERE_,"Unexpected error while waiting for new data.\n",comm_dev->comm_id);
+
+  return NULL;
+}
+
+void CComm::on_receive(void)
+{
+  unsigned char *data=NULL;
+  int num=0,num_read=0,i=0;
+
+  if((num=this->hard_get_num_data())==-1)
+  {
+    /* handle exceptions */
+    throw CCommException(_HERE_,"Impossible to get the number of new data available on the communication device.\n",this->comm_id);
+  }
+  data=new unsigned char[num];
+  if((num_read=this->hard_read(data,num))==-1)
+  {
+    delete[] data;
+    /* handle exceptions */
+    throw CCommException(_HERE_,"Impossible to read from the communication device.\n",this->comm_id);
+  }
+  else
+  {
+    if(num_read!=num)
+    {
+      delete[] data;
+      /* handle exceptions */
+      throw CCommException(_HERE_,"Not all desired data has been read from the communicationd device.\n",this->comm_id);
+    }
+    else
+    {
+      for(i=0;i<num;i++)
+        this->receive_queue.push_back(data[i]);
+      if(!this->event_server->event_is_set(this->rx_event_id))
+      {
+        this->event_server->set_event(this->rx_event_id);
+      }
+      delete[] data;
+    }
+  }
+}
+
+void CComm::on_error(void)
+{
+  /* handle exceptions */
+}
+
+CComm::~CComm()
+{
+  /* delete the events */
+  if(this->rx_event_id.size()!=0)
+    this->event_server->delete_event(this->rx_event_id);
+  if(this->error_event_id.size()!=0)
+  {
+    this->event_server->delete_event(this->error_event_id);
+  }
+  /* delete the thread */
+  if(this->comm_thread_id.size()!=0)
+  {
+    this->thread_server->delete_thread(this->comm_thread_id);
+  }
+}
diff --git a/src/comm.h b/src/comm.h
new file mode 100644
index 0000000000000000000000000000000000000000..27919ea21ab0c9262bb31f44d478aff242c2d047
--- /dev/null
+++ b/src/comm.h
@@ -0,0 +1,649 @@
+#ifndef _COMM_H
+#define _COMM_H
+
+#include <list>
+#include "eventserver.h"
+#include "threadserver.h"
+#include "mutex.h"
+
+typedef enum {created,configured,opened,sending} comm_states;
+
+/**
+ * \brief Implementation of a generic communication devidei
+ * 
+ * This class implements the basic features of a communication device. All
+ * standard communication devices (pipes, serial ports, sockets, etc...) will
+ * inherit from this base class and only need to define the specific functions
+ * to open (hard_open()), configure (hard_config()), read (hard_read(), write
+ * (hard_write()), get the number of available data (hard_get_num_data()), 
+ * close (hard_close()) and wait for communication events (hard_wait_comm_event())
+ * on the device.
+ *
+ * The interface provided by this class includes two events (data reception,
+ * and error) and one data queue where the received data is temporarly stored. 
+ * The events can be accessed through the event handler (CEventServer) by any 
+ * other object, and two functions are provided to retrieve their 
+ * identifiers (get_rx_event_id(), and error_event_id()).
+ *
+ * The recive event indicates if the device has received data and it remains
+ * active while there is data in the internal queue to be read. When the receive 
+ * queue is empty, the event is reset. Finally the error event indicates that an
+ * error ocurred. Use the get_error() function to retrieve the error code.
+ *
+ * When created the communication device starts a thread that is actually the 
+ * one responsible of handling the communication events (received data, 
+ * and errors). This thread is used exlcusively inside the class and can not be
+ * accessed outside it. This thread uses the wait function provided by the 
+ * inherited class to wait for any communication events.
+ *
+ * Most devices in Linux are referenced by a file descriptor for both read and
+ * write operations, or also, two different file descriptors, one for read 
+ * operations, and the other one for write operations. However, other devices
+ * may provide different methods of interfacing them, so no specific device
+ * handler is provided by this class. It is the inherited class that must provide
+ * it, together with the functions to open it, configure it, read from and write 
+ * to it and close it.
+ *
+ * To open the device, the user must call the base class open() function and also
+ * provide a function (hard_open()) to actually open the communication device. 
+ * The user provided function is automatically called by the base class open()
+ * function and it is responsible of initializing the device handler.
+ *
+ * After that, the device must be configured. Similarly to what happen with the
+ * open() function, the inherited class must provide the hard_config() function
+ * to perform all the required configuration steps. Both the open() and config()
+ * function have a void * parameter to allow the inherited class to pass through 
+ * any data structure. This parameter is passed to the corresponding inherited 
+ * class function (hard_open() or hard_config() respectively).
+ *
+ * Only after configuration, it is possible to read from and write to the device.
+ * Any previous attempt to do so will result in an error. The inherited class
+ * must also provide functions to actually read from (hard_read()) and write to
+ * (hard_write()) the device. To close the communication device, it is necessary
+ * to call the close() function which ends the thread and flushes any data still
+ * inside the transmission and reception queues. Also this function calls the 
+ * hard_close() function to actually close the device handle.
+ *
+ * The events and the thread itself are not destroyed until the communciation 
+ * device object is destroyed. It is possible to close the device at any time.
+ *
+ * For a propper operation, any inherited class must provide an implementation
+ * for the hard_open(), hard_config(), hard_read(), hard_write(), hard_close(),
+ * hard_get_num_data() and hard_wait_comm_event() functions. This functions are
+ * automatically called by the base class and must not be called directly.
+ *
+ * Any communication device is driven by an internal state machine, whose state is
+ * automatically changed when the different functions are called. The next figure
+ * shows the different states and also the state transition conditions.
+ *
+ *  \image html comm_states.png
+ *  \image latex comm_states.eps "Communication device states" width=10cm
+ *
+ */
+class CComm
+{
+  protected:
+    /**
+     * \brief receive event identifier
+     *
+     * This string has a unique identifier of the reception event that is used 
+     * through out the code to take action on the desired event. This string is 
+     * initialized at construction time using the identifier of the communication 
+     * device provided to the constructor and can not be modified afterwards. The
+     * function get_rx_event_id() can be used to retrieve this identifier.
+     */
+    std::string rx_event_id;
+    /**
+     * \brief error event identifier
+     *
+     * This string has a unique identifier of the error event that is used 
+     * through out the code to take action on the desired event. This string is 
+     * initialized at construction time using the identifier of the communication 
+     * device provided to the constructor and can not be modified afterwards. The
+     * function get_error_event_id() can be used to retrieve this identifier.
+     */
+    std::string error_event_id;
+    /**
+     * \brief communication thread identifier
+     *
+     * This string has a unique identifier of the communication thread that is used 
+     * through out the code to take action on the desired thread. This string is 
+     * initialized at construction time using the identifier of the communication 
+     * device provided to the constructor and can not be modified afterwards. This
+     * thread is only accessible from inside the class so it is not possible to
+     * retrieve its identifier.
+     */
+    std::string comm_thread_id;
+    /** 
+     * \brief communication error message
+     *
+     * This string has the information message of any error that could happen on
+     * the communication device. By default it is initialized to NULL, and it is 
+     * only created when there is an error. The error message is automatically 
+     * created when an error is detected by the communication thread, and it can
+     * be retrieved by calling the get_error() function.
+     */ 
+    std::string error_msg;
+    /** 
+     * \brief received data queue
+     *
+     * This dynamic queue stores all the data that is recieved by the communication
+     * device until it is read by the user. There is no limit in the number of bytes
+     * stored in this list except for the physical memory available. The data 
+     * received through the serial port is automatically put into the queue by the 
+     * communication thread, and the function read() is used to retrieve it. The 
+     * function get_num_data() returns the number of bytes in this queue. By default,
+     * this queue is empty.
+     */
+    std::list<unsigned char> receive_queue;
+    /**
+     * \brief current state of the communication device
+     * 
+     * This variable keeps the current state of the communication device. The state
+     * of the device is changed automatically by the class functions and can not be 
+     * modified outside it. The possible states of the communication device are:
+     *
+     *  - created: when the object has been just created.
+     *  - opened: after opening the device with the open() function.
+     *  - configured: after calling the config() function.
+     *  - sending: when the device is busy sending data.
+     *
+     * It is possible to retrieve the current state of the communication device at
+     * any time using the get_state() function.
+     */
+    comm_states state;
+    /**
+     * \brief Reference to the unique event handler
+     *
+     * This reference to the unique event handler is initialized when an object of
+     * this class is first created. It is used to create and handle all the 
+     * communication events. The object pointed by this reference is shared by all
+     * objects in any application.
+     */  
+    CEventServer *event_server;
+    /**
+     * \brief Reference to the unique thread handler
+     *
+     * This reference to the unique thread handler is initialized when an object of
+     * this class is first created. It is used to create and handle all the 
+     * communication threads. The object pointed by this reference is shared by all
+     * objects in any application.
+     */ 
+    CThreadServer *thread_server;
+    /**
+     * \brief A unique identifier for the obejct
+     *
+     * This string has a unique identifier of the object that is used throug
+     * out the code to take action on the desired object. This string is
+     * initialized at contruction time and can not be modified afterwards.
+     */
+     std::string comm_id;
+    /**
+     * \brief Communication mutual exclusion object
+     *
+     * This object is intended to be used by to handle the access to the shared 
+     * communication resource defined by the inherited classes. Using this mutex
+     * multiple simultaneous read or write operations on the communication device 
+     * are avoided which would result in data corruption or unexpected errors.
+     * This object is initialized at contruction time.
+     */
+    CMutex access_comm;
+    /** 
+     * \brief Thread function
+     * 
+     * This is the main function executed by the communication device to handle 
+     * the communication events. This function waits for either a receive or error
+     * events permanently, and the calls the appropriate function to handle the 
+     * events (on_receive() and on_error() respectively).
+     *
+     * Except for the time where this function is actually waiting for an event 
+     * to get active, it locks the user mutex of the base class in order to avoid
+     * that other threads interfere with the correct execution of the function. 
+     * The mutex is freed when the function is waiting to allow other threads to
+     * access the class shared resources.
+     *
+     * When data is received, this function automatically reads it from the physical
+     * communication device and stores it into the internal receive queue. Then the 
+     * receive event is activated to awake any waiting thread.
+     *
+     * In case of an error, the error event is activated. To retrieve the error 
+     * message, it is necessary to use the get_error() function. In case of an error,
+     * the thread is terminated, but no exception is thrown because there is no way 
+     * to catch it.
+     *
+     * \param param a reference to the communication device object that is associated
+     * to the thread. This reference is necessary to access the internal attributes
+     * of the class.
+     */
+    static void *comm_thread(void *param);
+    /**
+     * \brief function to handle the reception events
+     *
+     * This function handles the receive events. When called, it first gets how many 
+     * bytes have been received. Then all the bytes are read from the physical 
+     * communication device and stored into the internal receive queue. If the event
+     * is not already set, it is activated to indicate to any waiting thread that
+     * data is available.
+     *
+     * This function is executed only by the communication thread when new data is 
+     * received, so its execution can not be interrupted by other threads trying to
+     * access the class shared resources because the mutex is already locked by the
+     * communications thread function
+     *
+     * This function throws a CCommException in case of any error.
+     */
+    void on_receive(void);
+    /** 
+     * \brief function to handle the errors
+     *
+     * This function handles any error in the communication device. This function
+     * creates an error message with the information of the error, and the activates
+     * the error event and throws an exception in order to finish the thread. It is 
+     * important to note than the thread is terminated if there is any error.
+     *
+     * This function is executed only by the communication thread when new data is 
+     * received, so its execution can not be interrupted by other threads trying to
+     * access the class shared resources because the mutex is already locked by the
+     * communications thread function
+     *
+     * This function throws a CCommException in case of any error.
+     */
+    void on_error(void);
+    /**
+     * \brief Function to set the object identifier
+     *
+     * This function sets the unique identifier of each object. This function
+     * is protected, and therefore can only be executed inside the class, because
+     * the identifier can not be modified after construction of the object.
+     *
+     * This function throws a CCommException if there is any error.
+     *
+     * \param comm_id A null terminated string which identified the 
+     *                communication device. This string is used to create a
+     *                unique identifier for all the threads and events of the
+     *                class.
+     */
+     void set_id(const std::string& comm_id);
+     /**
+      * \brief Function to actually open the device
+      *
+      * This function is called automatically when the base class open() function
+      * is called. It must create a handle to the communication device in order to 
+      * be used in the future. The device handle must be provided by any inherited 
+      * class since it is device dependant.
+      *
+      * This class accepts a generic parameter (void *) to allow the user to pass 
+      * to the function any data structure. This parameter comes from the base
+      * class open() function, but no action is performed on it.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \param comm_dev a generic pointer (void *) to the data structure needed to
+      *                 identify the communication device to open and any other
+      *                 required information. This parameter may be NULL if not
+      *                 needed.
+      */ 
+     virtual void hard_open(void *comm_dev=NULL)=0;
+     /**
+      * \brief Function to actually configure the device
+      * 
+      * This function is called automatically when the base class config() function
+      * is called. It must configure the communication device as required by the 
+      * application.
+      *
+      * This class accepts a generic parameter (void *) to allow the user to pass 
+      * to the function any data structure. This parameter comes from the base
+      * class open() function, but no action is performed on it.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \param config a generic pointer (void *) to the data structure needed to
+      *               configure the communicationd device. This parameter may be
+      *               NULL if not needed.
+      */ 
+     virtual void hard_config(void *config=NULL)=0;
+     /**
+      * \brief Function to actually read from the device
+      *
+      * This function is automatically called when the new data received is activated.
+      * The read() function from the base class gets data from the internal queue, so
+      * this function is not used. It must try to read the ammount of data specified 
+      * and store it in the data buffer provided without blocking. Also, it must 
+      * return the number of bytes actually read from the devicve, since they may be
+      * different than the desired value.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      *  \param data a reference to the buffer where the received data must be 
+      *  copied. The necessary memory for this buffer must be allocated before 
+      *  calling this function and have enough size to store all the desired data.
+      *  If this buffer is not initialized, the function throws an exception.
+      *
+      *  \param len a positive interger that indicates the number of byte to be
+      *  read from the communication device. This value must be at most the length 
+      *  of the data buffer provided to the function.
+      *
+      *  \return an integer with the number of bytes actually read. These number 
+      *  coincide with the desired number if there is enough data in the internal 
+      *  queue, but it could be smaller if not.
+      */ 
+     virtual int hard_read(unsigned char *data, int len)=0;
+     /**
+      * \brief Function to actually write to the device
+      *
+      * This function is automatically called when the base class write() function
+      * is called. It must try to write the desired ammount of data to the communication 
+      * device without blocking. Also it must return the number of bytes actually
+      * written to the communication device since they may be different from the
+      * desired value.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      *  \param data a reference to the buffer with the data must be send to the 
+      *  device. The necessary memory for this buffer must be allocated before 
+      *  calling this function and have enough size to store all the desired data.
+      *  If this buffer is not initialized, the function throws an exception.
+      *
+      *  \param len a positive interger that indicates the number of byte to be
+      *  written to the communication device. This value must be at most the length 
+      *  of the data buffer provided to the function.
+      *
+      *  \return an integer with the number of bytes actually written. These number 
+      *  coincide with the desired number if there is enough data in the internal 
+      *  queue, but it could be smaller if not.
+      */ 
+     virtual int hard_write(unsigned char *data, int len)=0;
+     /**
+      * \brief Function to actually get the number of bytes availables
+      *
+      * This function is called when the new data received event is activated.
+      * It must get the number of data bytes available from the communication
+      * device and return its value without blocking.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \return an integer with the number of bytes available in the receive queue. 
+       * This value can be 0 if there is no data available, but there is ni upper
+      * limit in its value.
+      */ 
+     virtual int hard_get_num_data(void)=0;
+     /**
+      * \brief Function to actually wait for a given communication event
+      *
+      * This function is called in the internal communciation thread to wait for 
+      * any event on the communuication device. It must check for any event on the
+      * device (reception or error) and return the corresponding identifier. When 
+      * an event is activated, this function must return to allow the base class 
+      * to handle it, and the it is called again to wait for the next event.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \return -1 if there has been any error or else the identifier of the 
+      *         communciation event:
+      *
+      * - 1 for the new data received event
+      * - 2 for the error event
+      */ 
+     virtual int hard_wait_comm_event(void)=0;
+     /**
+      * \brief Function to actually close the device
+      *
+      * This function is called when the base class close() funciton is called. It
+      * must free the device handle initialized by the open() function and also free
+      * any other resource allocated by the inherited class.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      */ 
+     virtual void hard_close(void)=0;
+  public:
+    /** 
+     * \brief Constructor
+     * 
+     * This constructor creates the receive, send and error events and also the 
+     * thread to handle these events. By default all the events are reset. After
+     * creating the object is already possible to get the event identifiers for 
+     * the receive and error events.
+     *
+     * The thread is attached to the function to be executed, but it is not 
+     * started yet. It is only started when the open() function is called.  
+     *
+     * Also the error message is not initialized (set to NULL) at construction 
+     * time. This message is only initialized when there is an error on the
+     * communication device.
+     *
+     * By default, the intial state of the communication device is created.
+     *
+     * \param comm_id A null terminated string which identified the 
+     *                communication device. This string is used to create a
+     *                unique identifier for all the threads and events of the
+     *                class.
+     */
+    CComm(const std::string& comm_id);
+    /** 
+     * \brief Function to retrieve the object identifier
+     *
+     * This function returns the object identifier of the object as a null
+     * terminated string.
+     *
+     * This function thows a CCommException if there is any error.
+     *
+     * \return A refernce to a non allocated memory space where the
+     * identifier of the object is to be copied. The necessary memory is allocated
+     * internally to match the size of the identifier. The calling process is
+     * responsible of freeing the allocated memory.
+     */
+    std::string& get_id(void);
+    /**
+     * \brief function to open the communication device
+     *
+     * This function starts the communication thread that has been created at
+     * construction time if the device is in the created state. Otherwise, an
+     * exception is thrown because the device should be alredy opened. If it is
+     * necessary to open a new communication device using a previously 
+     * initialized CCom  object, it is necessary to first close the communication 
+     * device with the close() function and the call this function again. If 
+     * successfull, this function changes the current state of the device to
+     * opened.
+     *
+     * This function does not actually open any communication device, since this
+     * class is a generic placeholder for communication devices. It is the 
+     * inherited class which has to provide a hard_open() function that actually 
+     * opens the desired communication device. The inherited class hard_open() 
+     * function must initialize the device handler.
+     * 
+     * This function throws a CCommException if there is any error.
+     */
+    void open(void *comm_dev=NULL);
+    /**
+     * \brief function to configure the communication device
+     *
+     * This function only changes the current state of the communication device
+     * if it is not already configured, but does not configure any of the 
+     * device parameters since they greatly vary from one communication device to
+     * another. If the device has not been previously opened, this function 
+     * throws an exception.
+     *
+     * It is the inherited class that has to provide a hard_config() function that 
+     * actually configures the particular parameters of the communication device. 
+     *
+     * This function throws a CCommException if there is any error.
+     */
+    void config(void *config=NULL);
+    /**
+     * \brief function to read from the communication device
+     *
+     * This function tries to read a given number of bytes from the communication
+     *  device if the device has been opened and configured. Otherwise it throws 
+     *  an exception. If the number of bytes currently in the receive queue is less
+     *  than the desired number, the function returns all the available data and
+     *  also the number of bytes actually read. 
+     *
+     *  If the number of bytes in the queue is greater or equal than the desired 
+     *  number, the function returns all the required data. In both cases, the 
+     *  function will never block. When read, the bytes are removed from the
+     *  internal queue, so they can not be read again. Use the get_num_data()
+     *  function to get how many bytes are available in the receive queue.
+     *
+     *  If the internal receive queue gets empty after a read operation, the
+     *  receive event is cleared to indicate that there is no more data available.
+     *  This event will be set again by the communication thread when new data
+     *  is received.
+     *
+     *  This function throws a CCommException if there is any error.
+     *
+     *  \param data a reference to the buffer where the received data must be 
+     *  copied. The necessary memory for this buffer must be allocated before 
+     *  calling this function and have enough size to store all the desired data.
+     *  If this buffer is not initialized, the function throws an exception.
+     *
+     *  \param len a positive interger that indicates the number of byte to be
+     *  read from the communication device. This value must be at most the length 
+     *  of the data buffer provided to the function.
+     *
+     *  \return an integer with the number of bytes actually read. These number 
+     *  coincide with the desired number if there is enough data in the internal 
+     *  queue, but it could be smaller if not.
+     */
+    int read(unsigned char *data,int len);
+    /**
+     * \brief function to write to the communication device
+     *
+     * This function tries to write a given number of bytes to the communication
+     * device if the device has been opened and configured. Otherwise it throws 
+     * an exception. If the device is currently sending data, the new data provided
+     * to this function is temporary stored into the internal send queue to be
+     * trasmited when the device is ready. Otherwise, the information is send
+     * immediately.
+     *
+     * If the new data is send immediatelly, the send event is reset to indicate 
+     * that the device is not ready to send data, and any further write operation
+     * will temporary store the data into the internal queue. This event is set
+     * again by the communication device when a transmission is ended and there
+     * is no data in the send queue.
+     *
+     * This function throws a CCommException if there is any error.
+     *
+     *  \param data a reference to the buffer with the data must be send to the 
+     *  device. The necessary memory for this buffer must be allocated before 
+     *  calling this function and have enough size to store all the desired data.
+     *  If this buffer is not initialized, the function throws an exception.
+     *
+     *  \param len a positive interger that indicates the number of byte to be
+     *  written to the communication device. This value must be at most the length 
+     *  of the data buffer provided to the function.
+     *
+     *  \return an integer with the number of bytes actually written. These number 
+     *  coincide with the desired number if there is enough data in the internal 
+     *  queue, but it could be smaller if not.
+     */
+    int write(unsigned char *data, int len);
+    /**
+     * \brief function to get the number of bytes in the reception queue
+     *
+     * This function returns the number of byte currently available in the internal
+     * receive queue.
+     *
+     * \return an integer with the number of bytes available in the receive queue. 
+     * This value can be 0 if there is no data available, but there is ni upper
+     * limit in its value.
+     */
+    unsigned int get_num_data(void);
+    /**
+     * \brief function to get the receive event identifier
+     * 
+     * This fucntion returns the receive event identifier as a null terminated 
+     * string that can be used to access the event from any thread.
+     *
+     * This function throws a CCommException in case of any error.
+     *
+     * \return A reference to a non-allocated memory space where the 
+     * identifier of the event is to be copied. The necessary memory is allocated
+     * internally to match the size of the identifier. The calling process is 
+     * responsible of freeing the allocated memory.
+     *
+     */
+    std::string& get_rx_event_id(void);
+    /** 
+     * \brief function to get the error event identifier
+     *
+     * This fucntion returns the error event identifier as a null terminated 
+     * string that can be used to access the event from any thread.
+     *
+     * This function throws a CCommException in case of any error.
+     *
+     * \return A reference to a non-allocated memory space where the 
+     * identifier of the event is to be copied. The necessary memory is allocated
+     * internally to match the size of the identifier. The calling process is 
+     * responsible of freeing the allocated memory.
+     */
+    std::string& get_error_event_id(void);
+    /**
+     * \brief function to get the error message
+     *
+     * This function returns the error message of the error that caused the 
+     * communication thread to end. This function will return always a NULL 
+     * pointer except when an error has ocurred. 
+     *
+     * This function throws a CCommException in case of any error.
+     *
+     * \return A reference to a non-allocated memory space where the 
+     * error message is to be copied. The necessary memory is allocated
+     * internally to match the size of the identifier. The calling process is 
+     * responsible of freeing the allocated memory.
+     */
+    std::string& get_error(void);
+    /** 
+     * \brief function to get the current state of the comunication device
+     * 
+     * This function returns the current state of the communication device. The
+     * state is automatically updated by the class itself and can not be modified
+     * outside the class.  
+     *
+     * This function throws a CCommException in case of any error.
+     *
+     * \return the current state of the communication device. The possible state 
+     * are:
+     *  - created: when the object has been just created.
+     *  - opened: after opening the device with the open() function.
+     *  - configured: after calling the config() function.
+     */
+    int get_state(void);
+    /**
+     * \brief function to close the communication device
+     *
+     * This function closes the communication device. This operation consists on
+     * terminating the communication thread to avoid the event from being set or
+     * reset by it. Even if the particular communication device is opened by an
+     * inherited class, this function closes it. So the inherited class does not
+     * have to do it. Finally, any data in both the receive and the send queues 
+     * are flushed.
+     *
+     * This function does not destroy the events or the thread objects because 
+     * the device can still be opened again. These objects are only destroyed 
+     * when the object itself is destroyed. After calling this function, the
+     * current state of the communication device is set to created whatever
+     * the old state was.
+     *
+     * This function throws a CCommException in case of any error.
+     */
+    void close(void);
+    /**
+     * \brief destructor
+     *
+     * This function destroys the communication object. First, it calls the
+     * close() function to finish the thread and flush any remaining data. It
+     * then destroys all the events and the communication thread.
+     *
+     * This function throws a CCommException in case of any error.  
+     */
+    virtual ~CComm();
+};
+
+#endif
diff --git a/src/commexceptions.cpp b/src/commexceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c17119cf9968dc31fa7d372f3ff52daf1537d25
--- /dev/null
+++ b/src/commexceptions.cpp
@@ -0,0 +1,12 @@
+#include "commexceptions.h"
+#include <string.h>
+#include <stdio.h>
+
+const std::string comm_exception_msg="[CComm class] - ";
+
+CCommException::CCommException(const std::string& where,const std::string& error_msg,const std::string& comm_id):CException(where,comm_exception_msg)
+{
+  this->error_msg+=error_msg;
+  this->error_msg+=" - ";
+  this->error_msg+=comm_id;
+}
diff --git a/src/commexceptions.h b/src/commexceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..30b535b8aa5f061c52044ce42547995528330dde
--- /dev/null
+++ b/src/commexceptions.h
@@ -0,0 +1,58 @@
+#ifndef COMM_EXCEPTIONS
+#define COMM_EXCEPTIONS
+
+#include "exceptions.h"
+
+/**
+ * \brief Generic communication exception class
+ *
+ * This class implements the exceptions for the CComm class. In addition
+ * to the basic error message provided by the base class CException, this
+ * exception class provides also the unique identifier of the communication
+ * device that generated the exception.
+ *
+ * Also, similarly to other exception classes, it appends a class identifer
+ * string ("[CComm class] - ") to the error message in order to identify the
+ * class that generated the exception.
+ *
+ * The base class can be used to catch any exception thrown by the application
+ * or also, this class can be used in order to catch only exceptions generated 
+ * by CComm objects.
+ */
+class CCommException : public CException
+{
+  public:
+    /**
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CComm class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * [CComm class] - <error message> - <comm id>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     * \param comm_id a null terminated string that contains the communication
+     *                device unique identifier. This string must be the one used 
+     *                to create the communication device.
+     *
+     */
+    CCommException(const std::string& where, const std::string& error_msg,const std::string& comm_id);
+};
+
+#endif
diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e90ba1216e40736893f854cbed0c5e47597b159f
--- /dev/null
+++ b/src/examples/CMakeLists.txt
@@ -0,0 +1,35 @@
+# edit the following line to add the source code for the example and the name of the executable
+ADD_EXECUTABLE(test_rs232 test_rs232.cpp)
+
+# edit the following line to add the necessary libraries
+TARGET_LINK_LIBRARIES(test_rs232 ${IRIUTILS_LIBRARY} comm pthread)
+
+IF(BUILD_FTDI)
+  ADD_EXECUTABLE(test_ftdi test_ftdi.cpp)
+
+  TARGET_LINK_LIBRARIES(test_ftdi ${IRIUTILS_LIBRARY} ${FTDI_LIBRARY} comm pthread)
+ENDIF(BUILD_FTDI)
+
+# edit the following line to add the source code for the example and the name of the executable
+ADD_EXECUTABLE(test_client test_simple_client.cpp)
+
+# edit the following line to add the necessary libraries
+TARGET_LINK_LIBRARIES(test_client ${IRIUTILS_LIBRARY} comm pthread)
+
+# edit the following line to add the source code for the example and the name of the executable
+ADD_EXECUTABLE(test_server test_simple_server.cpp)
+
+# edit the following line to add the necessary libraries
+TARGET_LINK_LIBRARIES(test_server ${IRIUTILS_LIBRARY} comm pthread)
+
+# edit the following line to add the source code for the example and the name of the executable
+ADD_EXECUTABLE(test_multiple_server test_multiple_server.cpp)
+
+# edit the following line to add the necessary libraries
+TARGET_LINK_LIBRARIES(test_multiple_server ${IRIUTILS_LIBRARY} comm pthread)
+
+# edit the following line to add the source code for the example and the name of the executable
+ADD_EXECUTABLE(test_multiple_client test_multiple_client.cpp)
+
+# edit the following line to add the necessary libraries
+TARGET_LINK_LIBRARIES(test_multiple_client ${IRIUTILS_LIBRARY} comm pthread)
diff --git a/src/examples/test_ftdi.cpp b/src/examples/test_ftdi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad031e3fa1cdee98a8c28ecea2ed7b00ea851154
--- /dev/null
+++ b/src/examples/test_ftdi.cpp
@@ -0,0 +1,73 @@
+#include "ftdimodule.h"
+#include "ftdiserver.h"
+#include "ftdiexceptions.h"
+#include <stdio.h>
+
+/** \example test_ftdi.cpp
+ * 
+ * This example shows how to use the D2XX FTDI driver.
+ *
+ * This examples first creates an FTDI server which scans for all FTDI devices
+ * connected to the computer with the default PID and VID combinations provided
+ * by the manufacturer. If devices with different PID and VID combinations are
+ * used, it is necessary to use the add_custom_PID() function.
+ *
+ * When done, the information of all devices detected is displayed on screen.
+ * Then the first FTDI device, if any, is opened and configured. If this 
+ * operations are successfull, the specific information of the device is also
+ * displyed on screen.
+ *
+ * The output of this example when a single FTDI device is connected is as 
+ * follows:
+ *
+ * \verbatim
+ * Number of FTDI devices detected: 1
+ * Device 0
+ * The device is closed
+ * The device is full speed
+ * Type: 5
+ * Device id: 67330049
+ * Location: 0
+ * Serial number: A2001mHr
+ * Description: FT232R USB UART
+ * 
+ * ****************** FTDI Devices Info ***********************
+ * Device name: FTDI_A2001mHr
+ * Type: 5
+ * Device id: 67330049
+ * Serial Number: A2001mHr
+ * Description: FT232R USB UART
+ * \endverbatim
+ *
+ * This example program does not try to read and write from and to the device
+ * because it highly depends on the particular device connected. This example
+ * only scans for available devices and displays its information. For a full
+ * example of this driver, see the segwayRMP200 driver.
+ */
+int main(int argc, char *argv[])
+{
+  CFTDIServer *ftdi_server=CFTDIServer::instance();
+  CFTDI *ftdi_device=NULL;
+  TFTDIconfig ftdi_config;
+
+  ftdi_config.baud_rate = 115200;
+  ftdi_config.word_length = 8;
+  ftdi_config.stop_bits = 2;
+  ftdi_config.parity = 0;
+  ftdi_config.read_timeout = 1000;
+  ftdi_config.write_timeout = 1000;
+  ftdi_config.latency_timer = 16;
+
+  std::cout << (*ftdi_server) << std::endl;
+  if(ftdi_server->get_num_devices()>0)
+  {
+    ftdi_device=ftdi_server->get_device(ftdi_server->get_serial_number(0));
+    ftdi_device->config(&ftdi_config);
+    std::cout << (*ftdi_device) << std::endl;
+    ftdi_device->close();
+  }
+  if(ftdi_device!=NULL)
+    delete ftdi_device;
+}
+
+
diff --git a/src/examples/test_multiple_client.cpp b/src/examples/test_multiple_client.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bfc5a003f33c2efc10866f37ca5f102919b9162d
--- /dev/null
+++ b/src/examples/test_multiple_client.cpp
@@ -0,0 +1,51 @@
+#include "socketclient.h"
+#include "socketexceptions.h"
+#include "eventexceptions.h"
+
+std::string server_ip="147.83.76.185";
+int server_port=2012;
+
+int main(int argc,char *argv[])
+{
+  CEventServer *event_server=CEventServer::instance();
+  CSocketClient client("client");
+  std::list<std::string> events;
+  unsigned char msg[5]="hola";
+  int i=0,event_id=0;
+  TSocket_info info;
+
+  try{
+    info.address=server_ip;
+    info.port=server_port;
+    std::cout << "connecting ... " << std::endl;
+    while(!client.is_connected())
+    {
+      try{
+        client.open(&info);
+      }catch(CSocketNoConnectionException &e){
+        std::cout << "  nobody is listening" << std::endl;
+        sleep(1);
+      }
+    }
+    client.config();
+    std::cout << "connected." << std::endl;
+    events.push_back(client.get_rx_event_id());
+    events.push_back(client.get_connection_closed_event());
+    for(i=0;i<10;i++)
+    {
+      try{
+        event_id=event_server->wait_first(events,1000);
+        if(event_id==1)
+          break;
+      }catch(CEventTimeoutException &e){
+        std::cout << "sending data ..." << std::endl;
+        client.write(msg,5);
+      }
+    }
+    sleep(1);
+    std::cout << "closing connection ..." << std::endl;
+    client.close();
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;
+  }
+}
diff --git a/src/examples/test_multiple_server.cpp b/src/examples/test_multiple_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..376491d6ee68036608f3fea373023de62457929a
--- /dev/null
+++ b/src/examples/test_multiple_server.cpp
@@ -0,0 +1,84 @@
+#include "eventexceptions.h"
+#include "socketserver.h"
+#include "eventserver.h"
+
+std::string server_IP_address="147.83.76.185";
+int server_port=2012;
+int num_listen=1;
+
+int main(int argc,char *argv[])
+{
+  CEventServer *event_server=CEventServer::instance();
+  std::list<TClient_info *>::iterator it;
+  int event_id=0,num=0,client_index=0;
+  std::list<TClient_info *> info;
+  CSocketServer server("server");
+  std::list<std::string> events;
+  TClient_info *client_info;
+  TSocket_info sock_info;
+  unsigned char *data;
+
+  try{
+    sock_info.port=server_port;
+    sock_info.address=server_IP_address;
+    server.open(&sock_info);
+    server.config(&num_listen);
+    server.set_max_clients(5);
+    server.start_server();
+    while(1)
+    {
+      try{
+        events.clear();
+        events.push_back(server.get_new_connection_event_id());
+        for(it=info.begin();it!=info.end();it++)
+        {
+          events.push_back((*it)->rx_event_id);
+          events.push_back((*it)->disconnect_event_id);
+        }
+        event_id=event_server->wait_first(events,1000);
+        if(event_id==0)
+        {
+          std::cout << "new connection ..." << std::endl;
+          client_info=server.get_new_client();
+          info.push_back(client_info);
+          std::cout << "  client id: " << client_info->client_id << std::endl;
+          std::cout << "  IP address: " << client_info->IP << " at port " << client_info->port << std::endl;
+        }
+        else
+        {
+          event_id--;
+          for(it=info.begin();it!=info.end();it++)
+          {
+            if(event_id>=2)
+              event_id-=2;
+            else
+            {
+              if((event_id%2)==1)// disconnect event
+              {
+                std::cout << "client " << (*it)->client_id << " disconnected." << std::endl;
+                server.free_client((*it));
+                it=info.erase(it);
+              }
+              else// rx event
+              {
+                std::cout << "  data received from " << (*it)->client_id << " ";
+                num=server.get_num_data_from((*it)->client_id);
+                data=new unsigned char[num];
+                server.read_from((*it)->client_id,data,num);
+                std::cout << data << std::endl;
+                delete[] data;
+              }
+              break;
+            }
+          }
+        }
+      }catch(CEventTimeoutException &e){
+        std::cout << "waiting ..." << std::endl;
+      }catch(CException &e){
+        std::cout << e.what() << std::endl;
+      }
+    }
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;
+  }    
+}
diff --git a/src/examples/test_rs232.cpp b/src/examples/test_rs232.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4598df360b6299d8b1f5c7dbb6f0ec548cbe8c14
--- /dev/null
+++ b/src/examples/test_rs232.cpp
@@ -0,0 +1,119 @@
+#include "eventserver.h"
+#include "threadserver.h"
+#include "commexceptions.h"
+#include "rs232.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string>
+#include <iostream>
+
+const std::string serial_dev="/dev/ttyS0";
+const std::string empty_string="";
+
+/**
+ * \example test_rs232.cpp
+ *
+ * This example shows how to use the serial port driver
+ *
+ * This example tries to use the first serial port available to send and 
+ * receive data. This example is intended to be used with the RX and TX signals
+ * of the serial cable connected, so that all the data sent by the driver is 
+ * recevived by itself.
+ *
+ * \verbatim
+ * RX --\
+ *      |
+ * TX --/
+ * \endverbatim
+ *
+ * The CComm base class provide events to signal the data reception and also
+ * some unexpected error on the port. These events are used in this example to
+ * wait for all the required data, instead of peridically polling it for new 
+ * data (the event server is used).
+ *
+ * By default the serial port used is the /dev/ttyS0. If more serial ports are 
+ * available or USB to serial adapters are present, the device name can be
+ * changed to the desired one: /dev/ttySn or /dev/ttyUSBn.
+ *
+ * The output of this example should be something like this:
+ *
+ * \verbatim
+ *
+ * \endverbatim
+ *
+ * Several error may be thrown either by the CComm class or the CRS232 class:
+ *
+ * * Invalid device name to open.
+ *
+ * * Trying to configure the serial port before being opened.
+ *
+ * * Trying to open the port once it is already opened.
+ *
+ * * Trying to send or receive data before configuring the serial port.
+ *
+ * * Trying to write invalid data-
+ *
+ * * Providing an invalid buffer to save all the received data. 
+ */
+int main(int argc,char *argv[])
+{
+  CEventServer *event_server=CEventServer::instance();
+  unsigned char msg[5]="hola";
+  std::string rx_event;
+  CRS232 serial_port("serial_port");
+  std::list<std::string> events;
+  int num=0,total_length=0,i=0;
+  TRS232_config serial_config;
+
+  serial_config.baud=9600;
+  serial_config.num_bits=8;
+  serial_config.parity=none;
+  serial_config.stop_bits=1;
+  try{
+    serial_port.open((void *)&empty_string);
+  }catch(CCommException &e){
+    std::cout << e.what() << std::endl;
+  }
+  try{
+    serial_port.config(&serial_config);
+  }catch(CCommException &e){
+    std::cout << e.what() << std::endl;
+  }
+  serial_port.open((void *)&serial_dev);
+  rx_event=serial_port.get_rx_event_id();
+  std::cout << "Data reception event id: " << rx_event << std::endl;
+  events.push_back(rx_event);
+  try{
+    serial_port.open((void *)"/dev/ttyS0");
+  }catch(CCommException &e){
+    std::cout << e.what() << std::endl;
+  }
+  try{
+    serial_port.write(msg,5);
+  }catch(CCommException &e){
+    std::cout << e.what() << std::endl;
+  }
+  serial_port.config(&serial_config);
+  try{
+    serial_port.write(NULL,5);
+  }catch(CCommException &e){
+    std::cout << e.what() << std::endl;
+  }
+  try{
+    for(i=0;i<10;i++)
+    {
+      serial_port.write(msg,5);
+      do{
+        event_server->wait_all(events,1000);
+        num=serial_port.get_num_data();
+        serial_port.read(&msg[total_length],num);
+        total_length+=num;
+      }while(total_length<5);
+      total_length=0;
+      printf("Message received: %s\n",msg);
+    }
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;
+  }
+  serial_port.close();
+}
diff --git a/src/examples/test_simple_client.cpp b/src/examples/test_simple_client.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..488d1815826140682f5819b9a26d8e6f389ab0f9
--- /dev/null
+++ b/src/examples/test_simple_client.cpp
@@ -0,0 +1,44 @@
+#include "socketclient.h"
+#include "socketexceptions.h"
+
+std::string server_ip="192.168.0.13";
+int server_port=6653;
+
+int main(int argc,char *argv[])
+{
+  TSocket_info info;
+  CSocketClient client("client");
+  unsigned char msg[5]="hola",answer[5];
+
+  try{
+    while(1)
+    {
+      info.address=server_ip;
+      info.port=server_port;
+      std::cout << "connecting ... " << std::endl;
+      while(!client.is_connected())
+      {
+        try{
+          client.open(&info);
+        }catch(CSocketNoConnectionException &e){
+          std::cout << "  nobody is listening" << std::endl;
+          sleep(1);
+        }
+      }
+      client.config(NULL);
+      std::cout << "connected." << std::endl;
+      sleep(1);
+      std::cout << "sending data ..." << std::endl;
+      client.write(msg,5);
+      sleep(1);
+      client.read(answer,5);
+      std::cout << "data received ... " << answer << std::endl;
+      sleep(1);
+      std::cout << "closing connection ..." << std::endl;
+      client.close();
+      sleep(1);
+    }
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;
+  }
+}
diff --git a/src/examples/test_simple_server.cpp b/src/examples/test_simple_server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c6a7a2fe2c09d3ccc23e9c295e66dfd246b752f
--- /dev/null
+++ b/src/examples/test_simple_server.cpp
@@ -0,0 +1,65 @@
+#include "eventexceptions.h"
+#include "socketserver.h"
+#include "eventserver.h"
+
+std::string server_IP_address="127.0.0.1";
+int server_port=2012;
+int num_listen=1;
+
+int main(int argc,char *argv[])
+{
+  CEventServer *event_server=CEventServer::instance();
+  CSocketServer server("server");
+  std::list<std::string> con_events,client_events;
+  TSocket_info sock_info;
+  unsigned char *data;
+  TClient_info *info;
+  int event_id,num;
+
+  try{
+    sock_info.port=server_port;
+    sock_info.address=server_IP_address;
+    server.open(&sock_info);
+    server.config(&num_listen);
+    server.set_max_clients(5);
+    con_events.push_back(server.get_new_connection_event_id());
+    server.start_server();
+    while(1)
+    {
+      try{
+        event_server->wait_first(con_events,1000);
+        std::cout << "new connection ..." << std::endl;
+        info=server.get_new_client();
+        std::cout << "  client id: " << info->client_id << std::endl;
+        std::cout << "  IP address: " << info->IP << " at port " << info->port << std::endl;
+        client_events.clear();
+        client_events.push_back(info->rx_event_id);
+        client_events.push_back(info->disconnect_event_id);
+        do{
+          event_id=event_server->wait_first(client_events);
+          if(event_id==0)
+          {
+            std::cout << "  data received ... ";
+            num=server.get_num_data_from(info->client_id);
+            data=new unsigned char[num];
+            server.read_from(info->client_id,data,num);
+            std::cout << data << std::endl;
+            delete[] data;
+          }
+          if(event_id==1)
+          {
+            server.free_client(info);
+            std::cout << "client disconnected ... " << std::endl;
+          }
+        }while(event_id!=1);
+      }catch(CEventTimeoutException &e){
+        std::cout << "waiting ..." << std::endl;
+      }catch(CException &e){
+        std::cout << e.what() << std::endl;
+      }
+    }
+    server.stop_server();
+  }catch(CException &e){
+    std::cout << e.what() << std::endl;
+  }    
+}
diff --git a/src/serial/rs232.cpp b/src/serial/rs232.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ceffa0a668f2dd734fae15d19ef017bf945f7560
--- /dev/null
+++ b/src/serial/rs232.cpp
@@ -0,0 +1,357 @@
+#include "rs232.h"
+#include "rs232exceptions.h"
+#include "ctime.h"
+
+CRS232::CRS232(const std::string& comm_id) : CComm(comm_id)
+{
+  this->serial_fd=-1;
+}
+
+void CRS232::set_baudrate(int baud)
+{
+  struct termios config;
+  int baudrate;
+
+  if(tcgetattr(this->serial_fd,&config)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the attribute structure.\n",this->comm_id);
+  }
+  else
+  {
+    switch(baud)
+    {
+      case 50: baudrate=B50;
+               break; 
+      case 75: baudrate=B75;
+               break;
+      case 110: baudrate=B110;
+                break;
+      case 134: baudrate=B134;
+                break;
+      case 150: baudrate=B150;
+                break;
+      case 200: baudrate=B200;
+                break;
+      case 300: baudrate=B300;
+                break;
+      case 600: baudrate=B600; 
+                break;
+      case 1200: baudrate=B1200;
+                 break;
+      case 1800: baudrate=B1800;
+                 break;
+      case 2400: baudrate=B2400;
+                 break;
+      case 4800: baudrate=B4800;
+                 break;
+      case 9600: baudrate=B9600;
+                 break;
+      case 19200: baudrate=B19200;
+                  break;
+      case 38400: baudrate=B38400;
+                  break;
+      case 57600: baudrate=B57600;
+                  break;
+      case 115200: baudrate=B115200;
+                   break;
+      default: /* handle exception */
+               throw CRS232Exception(_HERE_,"Invalid baudrate. See the documentation for the possible values.\n",this->comm_id);
+               break;
+    }
+    cfsetispeed(&config,baudrate);
+    cfsetospeed(&config,baudrate);
+    if(tcsetattr(this->serial_fd,TCSANOW,&config)==-1)
+    {
+      /* handle exceptions */
+      throw CRS232Exception(_HERE_,"Impossible to set up the new attribute structure.\n",this->comm_id);
+    }
+  }
+}
+
+void CRS232::set_num_bits(char num_bits)
+{
+  struct termios config;
+  int bits;
+
+  if(tcgetattr(this->serial_fd,&config)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the attribute structure.\n",this->comm_id);
+  }
+  else
+  {
+    switch(num_bits)
+    {
+      case 5: bits=CS5;
+              break;
+      case 6: bits=CS6;
+              break;
+      case 7: bits=CS7;
+              break;
+      case 8: bits=CS8;
+              break;
+      default: /* handle exceptions */
+               throw CRS232Exception(_HERE_,"Invalid number of bits per packet. See the documentation for the possible values.\n",this->comm_id);
+               break;
+    }
+    config.c_cflag&=~CSIZE;
+    config.c_cflag|=bits;
+    if(tcsetattr(this->serial_fd,TCSANOW,&config)==-1)
+    {
+      /* handle exceptions */
+      throw CRS232Exception(_HERE_,"Impossible to set up the new attribute structure.\n",this->comm_id);
+    }
+  }
+}
+
+void CRS232::set_parity(parity_type parity)
+{
+  struct termios config;
+
+  if(tcgetattr(this->serial_fd,&config)==-1)
+  {
+    /* handle exception */
+    throw CRS232Exception(_HERE_,"Impossible to get the attribute structure.\n",this->comm_id);
+  }
+  else
+  {
+    if(parity!=none)
+    {
+      config.c_cflag|=PARENB;
+      if(parity==odd) config.c_cflag|=PARODD;
+      else if(parity==even) config.c_cflag&=~PARODD;
+      else
+      {
+        /* handle exceptions */
+        throw CRS232Exception(_HERE_,"Invalid parity type. See the documentation for the possible values.\n",this->comm_id);
+      }
+    }
+    else config.c_cflag&=~PARENB;
+    if(tcsetattr(this->serial_fd,TCSANOW,&config)==-1)
+    {
+      /* handle exceptions */
+      throw CRS232Exception(_HERE_,"Impossible to set up the new attribute structure.\n",this->comm_id);
+    }
+  }
+}
+
+void CRS232::set_stop_bits(char stop_bits)
+{
+  struct termios config;
+
+  if(tcgetattr(this->serial_fd,&config)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the attribute structure.\n",this->comm_id);
+  } 
+  else
+  {
+    if(stop_bits==2) config.c_cflag|=CSTOPB;
+    else if(stop_bits==1)config.c_cflag&=~CSTOPB;
+    else
+    {
+      /* handle execptions */
+      throw CRS232Exception(_HERE_,"Invalid number of stop bits. See the documentation for the possible values.\n",this->comm_id);
+    }
+    if(tcsetattr(this->serial_fd,TCSANOW,&config)==-1)
+    {
+      /* handle exception */
+      throw CRS232Exception(_HERE_,"Impossible to set up the new attribute structure.\n",this->comm_id);
+    }
+  }
+}
+
+void CRS232::hard_open(void *comm_dev)
+{
+  std::string *serial_dev=(std::string *)comm_dev;
+  struct termios config;
+
+  if(serial_dev->size()==0)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Invalid serial port device name (empty string).\n",this->comm_id);
+  }
+  else
+  {
+    this->serial_fd=::open(serial_dev->c_str(),O_RDWR | O_NOCTTY | O_NONBLOCK | O_ASYNC);
+    if(this->serial_fd==-1)
+    {
+      /* handle exceptions */
+      throw CRS232Exception(_HERE_,"Impossible to open the serial port.\n",this->comm_id);
+    }
+    else
+    {
+      if(tcgetattr(this->serial_fd,&config)==-1)
+      {
+        /* handle exceptions */
+        throw CRS232Exception(_HERE_,"Impossible to get the attribute structure.\n",this->comm_id);
+      }
+      else
+      {
+        config.c_cflag|=(CLOCAL | CREAD);
+        config.c_cflag&=~CRTSCTS;
+        config.c_lflag&=~(ICANON | ECHO | ECHOE | ISIG);
+        config.c_iflag&=~(IXON | IXOFF | IXANY);
+        config.c_iflag&=~(INLCR | IGNCR | ICRNL);
+        config.c_oflag&=~OPOST;
+        config.c_cc[VMIN]=0;
+        config.c_cc[VTIME]=100;
+        if(tcsetattr(this->serial_fd,TCSANOW,&config)==-1)
+        {
+          /* handle exceptions */
+          throw CRS232Exception(_HERE_,"Impossible to set up the new attribute structure.\n",this->comm_id);
+        }
+      }
+    }
+  }
+}
+
+void CRS232::hard_config(void *config)
+{
+  TRS232_config *serial_conf=(TRS232_config *)config;
+
+  this->set_baudrate(serial_conf->baud);
+  this->set_num_bits(serial_conf->num_bits);
+  this->set_parity(serial_conf->parity);
+  this->set_stop_bits(serial_conf->stop_bits);
+}
+
+int CRS232::hard_read(unsigned char *data, int len)
+{
+  int num_read=0;
+
+  if((num_read=::read(this->serial_fd,data,len))==-1)
+  {
+    return -1;
+  }
+
+  return num_read;
+}
+
+int CRS232::hard_write(unsigned char *data, int len)
+{
+  int num_written=0;
+
+  if((num_written=::write(this->serial_fd,data,len))==-1)
+  {
+    return -1;
+  } 
+
+  return num_written; 
+}
+
+int CRS232::hard_get_num_data(void)
+{
+  int num;
+
+  if(ioctl(this->serial_fd,FIONREAD,&num)==-1)
+  {
+    return -1;
+  }
+
+  return num;
+}
+
+int CRS232::hard_wait_comm_event(void)
+{
+  fd_set receive_set,error_set;
+  int max_fd,wait_result=0;
+
+  max_fd=this->serial_fd+1;
+  FD_ZERO(&receive_set);
+  FD_SET(this->serial_fd,&receive_set);
+  FD_ZERO(&error_set);
+  FD_SET(this->serial_fd,&error_set);
+  wait_result=select(max_fd,&receive_set,NULL,&error_set,NULL);
+  if(wait_result==-1)
+    return -1; 
+  else
+  {
+    if(FD_ISSET(this->serial_fd,&receive_set))/* data has been received */
+    {
+      return 1;
+    }
+    if(FD_ISSET(this->serial_fd,&error_set))
+    {
+      return 2;
+    }
+  }
+
+  return -1;
+}
+
+void CRS232::hard_close(void)
+{
+  if(this->serial_fd!=-1)
+  {
+    ::close(this->serial_fd);
+    this->serial_fd=-1;
+  }
+}
+
+void CRS232::set_control_signal(control_signals signal)
+{
+  int status;
+
+  if(ioctl(this->serial_fd, TIOCMBIS, (const int *)&signal)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the control signals status.\n",this->comm_id);
+  } 
+
+  return;
+
+  if(ioctl(this->serial_fd, TIOCMGET, &status)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the control signals status.\n",this->comm_id);
+  } 
+  status|=signal;
+  if(ioctl(this->serial_fd, TIOCMSET, status)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to set the control signals status.\n",this->comm_id);
+  }
+}
+
+void CRS232::clear_control_signal(control_signals signal)
+{
+  int status;
+
+  if(ioctl(this->serial_fd, TIOCMBIC, (const int *)&signal)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the control signals status.\n",this->comm_id);
+  } 
+
+  return;
+
+  if(ioctl(this->serial_fd, TIOCMGET, &status)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to get the control signals status.\n",this->comm_id);
+  } 
+  status&=~signal;
+  if(ioctl(this->serial_fd, TIOCMSET, status)==-1)
+  {
+    /* handle exceptions */
+    throw CRS232Exception(_HERE_,"Impossible to set the control signals status.\n",this->comm_id);
+  }
+}
+
+bool CRS232::get_control_signal(control_signals signal)
+{
+  int status;
+
+  ioctl(this->serial_fd, TIOCMGET, &status);
+  if(status&signal) 
+    return true;
+  else
+    return false;  
+}
+
+CRS232::~CRS232()
+{
+  this->close();
+}
diff --git a/src/serial/rs232.h b/src/serial/rs232.h
new file mode 100644
index 0000000000000000000000000000000000000000..18d603d6e6a19b5b6e95dae6d45fb8cf5815bfb4
--- /dev/null
+++ b/src/serial/rs232.h
@@ -0,0 +1,424 @@
+#ifndef _RS232_H
+#define _RS232_H
+
+#include "comm.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <termios.h>
+#include <unistd.h>  
+#include <fcntl.h>
+#include <errno.h>
+#include <string>
+
+/**
+ * \brief Available types of parity
+ *
+ * This enumeration provides all the possible parity types available on the
+ * RS-232 serial port. The parity types are:
+ *
+ * * none: no parity bit is used and there is no way to detect errors.
+ * * even: adds an additional bit such that the number of ones in each packet
+ *         is even.
+ * * odd: adds an additional bit such that the number of ones in each packet
+ *        is odd.
+ * * mark: adds an additional bit with the fixed value of one.
+ * * space: adds an additional bit with the fixed value of zero.
+ */
+typedef enum {none,even,odd,mark,space} parity_type;
+
+/**
+ * \brief Available control signals of the RS232 port
+ *
+ * This enumeration provides identifiers for all the control signals of
+ * an standard serial port. These signals include the following:
+ * 
+ * * DSR: Data Set Ready. This signal indicates the sending device that the
+ *        receiving device is ready.
+ * * DTR: Data Terminal Ready. This signal indicates the receiving device that
+ *        the sending device is ready.
+ * * RTS: Request To Send. This signal is used to perform hardware flow control
+ *        and is used by the sending device to check if it is possible to start 
+ *        sending data.
+ * * CTS: Clear To Send. This signal is used to perform hardware flow control
+ *        and it is used by the receiving device as an answer to the RTS signal
+ *        to notify that the receiving device is ready to receive data.
+ * * CD: Data Carrier Detect. This signal was used in modems to notify that the
+ *       modem was connected to the telephon line.
+ * * RI: Ring Indicator: This signal was used in modems to notify that the ring
+ *       signal was detected on the telephone line.
+ *
+ * This is the standard function for each of the control signals of a serial port,
+ * However they can be used for other purposes.
+ *
+ */
+typedef enum {rs232_dsr=TIOCM_DSR,
+              rs232_dtr=TIOCM_DTR,
+              rs232_rts=TIOCM_RTS,
+              rs232_cts=TIOCM_CTS,
+              rs232_cd=TIOCM_CD,
+              rs232_ri=TIOCM_RI} control_signals;
+
+/**
+ * \brief Configuration structure for the serial port
+ */
+typedef struct{
+  /**
+   * \brief Serial port baudrate
+   *
+   * This filed represents the desired speed in bits per second. Not all values are 
+   * valid. The valid values for this parameter are listed below:
+   *
+   * - 50
+   * - 75
+   * - 110
+   * - 134
+   * - 150
+   * - 200
+   * - 300
+   * - 600
+   * - 1200
+   * - 1800
+   * - 2400
+   * - 4800
+   * - 9600
+   * - 19200
+   * - 38400
+   * - 57600
+   * - 115200
+   *
+   */
+  int baud;
+  /**
+   * \brief Number of bits per paquet
+   *
+   * This field represents the number of bits of each packet. Not all values 
+   * are valid. The valid values for this parameter are 5,6,7 or 8.
+   */ 
+  char num_bits;
+  /**
+   * \brief Parity type
+   *
+   * This field represents the desired parity type for each packet. This parameter 
+   * must belong to the parity_type enumeration. See the documentation on this data
+   * type for more information on the possible values of this parameter.
+   */ 
+  parity_type parity;
+  /**
+   * \brief Number of stop bits
+   *
+   * This field represents the desired number of stop bits per packet. The possible 
+   * values for this parameter are only 1 or 2.
+   */ 
+  char stop_bits;
+}TRS232_config;
+
+/** 
+ * \brief RS-232 Serial port driver
+ *
+ * This class implements a driver to use the standard RS-232 ports on any
+ * computer. It inherits from the CComm class which provides the basic 
+ * interface to any communication device. 
+ *
+ * This class overloads the open() and config() functions of the base class 
+ * to suit the specific requirements of a serial port. Also, several 
+ * functions are declared to configure the features of the serial port:
+ * baudrate, number of bits, parity and number of stop bits.
+ *
+ * For a more detailed description of the behavior of this class, see the
+ * documentation for the CComm base class.
+ */
+class CRS232 : public CComm
+{
+  private:
+    /**
+     * \brief write file descriptor of the communication device
+     * 
+     * This variable is the write file descriptor associated to the communication 
+     * device. By default it is initialized to -1, and it is the inherited class
+     * that must initialize it when actually opening the communication device by
+     * calling the open() function. The read and write file descriptors can be
+     * the same or different, depending on the particular communication device.
+     */
+    int serial_fd;
+  protected:
+    /**
+     * \brief Function to set the desired baudrate
+     *
+     * This functions sets the speed of the srial port in bits per second.
+     * If the given speed is not valid this function throws a CRS232Exception.
+     *
+     * \param baud the desired speed in bits per second. Not all values are 
+     *             valid. The valid values for this parameter are listed below:
+     *
+     * - 50
+     * - 75
+     * - 110
+     * - 134
+     * - 150
+     * - 200
+     * - 300
+     * - 600
+     * - 1200
+     * - 1800
+     * - 2400
+     * - 4800
+     * - 9600
+     * - 19200
+     * - 38400
+     * - 57600
+     * - 115200
+     *
+     */  
+    void set_baudrate(int baud);
+    /**
+     * \brief Function to set the number of bits per packet
+     *  
+     * This function sets the number of data bits included in each packet. If
+     * the given number of bits is not valid, a CRS232Exception is thrown.
+     *
+     * \param num_bits The number of bits of each packet. Not all values are 
+     *                 valid. The valid values for this parameter are 5,6,7 or
+     *                 8.
+     *
+     */  
+    void set_num_bits(char num_bits);
+    /**
+     * \brief Function to set the parity
+     *
+     * This function sets the desired parity (if any) for each of the packets.
+     * If the given parity type is not valid, a CRS232Exception is thrown.
+     *
+     * \param parity the desired parity type for each packet. This parameter 
+     *               must belong to the parity_type enumeration. See the
+     *               documentation on this data type for more information
+     *               on the possible values of this parameter.
+     */  
+    void set_parity(parity_type parity);
+    /**
+     * \brief Function to set the number of stop bits
+     *
+     * This function sets the desired number of stop bits for each packet. If
+     * the given number of stop bits is not valid, a CRS232Exception is thrown.
+     *
+     * \param stop_bits the desired number of stop bits per packet. The possible 
+     *                  values for this parameter are only 1 or 2.
+     *
+     */  
+    void set_stop_bits(char stop_bits);
+    /**
+     * \brief Function to open an RS232 serial port
+     *
+     * This function is called automatically when the base class open() function
+     * is called. It must create a handle to the communication device in order to 
+     * be used in the future. The device handle must be provided by any inherited 
+     * class since it is device dependant.
+     *
+     * This class accepts a generic parameter (void *) to allow the user to pass 
+     * to the function any data structure. This parameter comes from the base
+     * class open() function, but no action is performed on it.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \param comm_dev a generic pointer (void *) to the data structure needed to
+     *                 identify the communication device to open and any other
+     *                 required information. This parameter may be NULL if not
+     *                 needed.
+     * \verbatim
+     * /dev/ttyS0
+     * \endverbatim
+     */
+     virtual void hard_open(void *comm_dev);
+     /**
+     * \brief Function to configure the serial port
+     * 
+     * This function is called automatically when the base class config() function
+     * is called. It must configure the communication device as required by the 
+     * application.
+     *
+     * This class accepts a generic parameter (void *) to allow the user to pass 
+     * to the function any data structure. This parameter comes from the base
+     * class open() function, but no action is performed on it.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \param config a pointer to a TRS232_config structure already initialized
+     *               with all teh configuration parameters of the serial port.
+     */ 
+     virtual void hard_config(void *config);
+     /**
+      * \brief Function to actually read from the device
+      *
+      * This function is automatically called when the new data received is activated.
+      * The read() function from the base class gets data from the internal queue, so
+      * this function is not used. It must try to read the ammount of data specified 
+      * and store it in the data buffer provided without blocking. Also, it must 
+      * return the number of bytes actually read from the devicve, since they may be
+      * different than the desired value.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      *  \param data a reference to the buffer where the received data must be 
+      *  copied. The necessary memory for this buffer must be allocated before 
+      *  calling this function and have enough size to store all the desired data.
+      *  If this buffer is not initialized, the function throws an exception.
+      *
+      *  \param len a positive interger that indicates the number of byte to be
+      *  read from the communication device. This value must be at most the length 
+      *  of the data buffer provided to the function.
+      *
+      *  \return an integer with the number of bytes actually read. These number 
+      *  coincide with the desired number if there is enough data in the internal 
+      *  queue, but it could be smaller if not.
+      */ 
+     virtual int hard_read(unsigned char *data, int len);
+     /**
+      * \brief Function to actually write to the device
+      *
+      * This function is automatically called either when the base class write()
+      * function is called or when the data transmission end event is activated.
+      * It must try to write the desired ammount of data to the communication 
+      * device without blocking. Also it must return the number of bytes actually
+      * written to the communication device since they may be different from the
+      * desired value.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      *  \param data a reference to the buffer with the data must be send to the 
+      *  device. The necessary memory for this buffer must be allocated before 
+      *  calling this function and have enough size to store all the desired data.
+      *  If this buffer is not initialized, the function throws an exception.
+      *
+      *  \param len a positive interger that indicates the number of byte to be
+      *  written to the communication device. This value must be at most the length 
+      *  of the data buffer provided to the function.
+      *
+      *  \return an integer with the number of bytes actually written. These number 
+      *  coincide with the desired number if there is enough data in the internal 
+      *  queue, but it could be smaller if not.
+      */
+     virtual int hard_write(unsigned char *data, int len);
+     /**
+      * \brief Function to actually get the number of bytes availables
+      *
+      * This function is called when the new data received event is activated.
+      * It must get the number of data bytes available from the communication
+      * device and return its value without blocking.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \return an integer with the number of bytes available in the receive queue. 
+      * This value can be 0 if there is no data available, but there is ni upper
+      * limit in its value.
+      */
+     virtual int hard_get_num_data(void);
+     /**
+      * \brief Function to actually wait for a given communication event
+      *
+      * This function is called in the internal communciation thread to wait for 
+      * any event on the communuication device. It must check for any event on the
+      * device (reception, end of transmission or error) and return the
+      * corresponding identifier. When an event is activated, this function must 
+      * return to allow the base class to handle it, and the it is called again
+      * to wait for the next event.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      *
+      * \return -1 if there has been any error or else the identifier of the 
+      *         communciation event:
+      *
+      * - 0 for the end of transmission event
+      * - 1 for the new data received event
+      * - 2 for the error event
+      */
+     virtual int hard_wait_comm_event(void);
+     /**
+      * \brief Function to actually close the device
+      *
+      * This function is called when the base class close() funciton is called. It
+      * must free the device handle initialized by the open() function and also free
+      * any other resource allocated by the inherited class.
+      *
+      * This function can throw any CCommException object exception or else any
+      * exception class defined by the inherited class.
+      */
+     virtual void hard_close(void);
+  public:
+    /**
+     * \brief Constructor
+     *
+     * This constructor creates a new CRS232 object initialized by default, 
+     * but it does not open any physical serial port. This constructor calls
+     * the base class constructor with the serial port unique identifier
+     * provided to the constructor.
+     *
+     * \param comm_id A null terminated string which identified the
+     *                communication device. This string is used to create a
+     *                unique identifier for all the threads and events of the
+     *                class.
+     *
+     */ 
+    CRS232(const std::string& comm_id);
+    /**
+     * \brief Function to set an RS232 control signal
+     * 
+     * This function changes the state of an output control signal to its 
+     * active state (negative voltage). See the documentation on the 
+     * control_signals enumeration type for information on the possible control
+     * signals.
+     *
+     * If the state of the control signal can not be changed, an CRS232Exception
+     * object is thrown.
+     *
+     * \param signal an identifier of the signal to be activated. This parameter
+     *               must be of the control_signals enumeration type. 
+     *
+     */
+    void set_control_signal(control_signals signal);
+    /**
+     * \brief Funciton to reset an RS232 control signal
+     *
+     * This function chnages the state of an output control signal to its inactive
+     * state (positive voltage). See the documentation on the control_signals
+     * enumeration type for information on the possible control signals.
+     *
+     * If the state of the control signal can not be changed, an CRS232Exception 
+     * object is thrown.
+     *
+     * \param signal an identifier of the signal to be activated. This parameter
+     *               must be of the control_signals enumeration type. 
+     *
+     */
+    void clear_control_signal(control_signals signal);
+    /**
+     * \brief Function to get the current state of an RS232 control signal
+     *
+     * This function returns the current state of an input control signal. See
+     * the documentation on the control_signals enumeration type for information
+     * on the possible control signals.
+     *
+     * If the state of the control signal can not be changed, an CRS232Exception 
+     * object is thrown.
+     *
+     * \return the current state of the desired control signal. True is the 
+     *         current state is active (negative voltage) and false id the 
+     *         current state is inactive (positive voltage).
+     */
+    bool get_control_signal(control_signals signal);
+    /**
+     * \brief destructor
+     *
+     * This destructor does nothing. The base class destructor is the one in 
+     * charge of freeing all the allocated resources.
+     */  
+    ~CRS232();
+};
+
+#endif
diff --git a/src/serial/rs232exceptions.cpp b/src/serial/rs232exceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..369bdc7b4dd0560b303247130f9ad57f3173fd33
--- /dev/null
+++ b/src/serial/rs232exceptions.cpp
@@ -0,0 +1,11 @@
+#include "rs232exceptions.h"
+#include <string.h>
+#include <stdio.h>
+
+const std::string rs232_exception_msg="[CRS232 class] - ";
+
+CRS232Exception::CRS232Exception(const std::string& where,const std::string& error_msg,const std::string& comm_id):CCommException(where,rs232_exception_msg,error_msg)
+{
+  this->error_msg+=" - ";
+  this->error_msg+=comm_id;
+}
diff --git a/src/serial/rs232exceptions.h b/src/serial/rs232exceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..afacce075a372c37c87f4addaf45dd56073c3680
--- /dev/null
+++ b/src/serial/rs232exceptions.h
@@ -0,0 +1,60 @@
+#ifndef RS232_EXCEPTIONS
+#define RS232_EXCEPTIONS
+
+#include "commexceptions.h"
+
+/**
+ * \brief RS232 exception class
+ *
+ * This class implements the exceptions for the CRS232 communication class. 
+ * In addition to the basic error message provided by the base class CException, 
+ * this exception class provides also the unique identifier of the communication
+ * device that generated the exception.
+ *
+ * Also, similarly to other exception classes, it appends a class identifer
+ * string ("[CRS232 class] - ") to the error message in order to identify 
+ * the class that generated the exception.
+ *
+ * The base class can be used to catch any exception thrown by the application
+ * or also, this class can be used in order to catch only exceptions generated 
+ * by CS232 objects.
+ *
+ */
+class CRS232Exception : public CCommException
+{
+  public:
+    /**
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CRS232 class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device 
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * Error: [CComm class] - [CRS232 class] - <error message> - <comm id>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     * \param comm_id a null terminated string that contains the communication
+     *                device unique identifier. This string must be the one used to 
+     *                create the object.
+     *
+     *
+     */  
+    CRS232Exception(const std::string& where,const std::string& error_msg,const std::string& comm_id);
+};
+
+#endif
diff --git a/src/sockets/socket.cpp b/src/sockets/socket.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aaddeff9f5eb119bcb424ebd772ae41d17443078
--- /dev/null
+++ b/src/sockets/socket.cpp
@@ -0,0 +1,182 @@
+#include "socket.h"
+#include "socketexceptions.h"
+#include <string.h>
+
+CSocket::CSocket(const std::string &comm_id) : CComm(comm_id)
+{
+  struct hostent *host;
+  char name[1024];
+
+  this->connection_closed_event.clear();
+  this->connection_closed_event+=comm_id;
+  this->connection_closed_event+="_closed";
+  this->event_server->create_event(this->connection_closed_event);
+  this->cloned=false;
+}
+
+CSocket::CSocket(const std::string &comm_id,const int fd) : CComm(comm_id)
+{
+  struct hostent *host;
+  char name[200];
+
+  if(fd<0)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_, "Invalid file descriptor",comm_id);
+  }
+  else
+  {
+    this->connection_closed_event.clear();
+    this->connection_closed_event+=comm_id;
+    this->connection_closed_event+="_closed";
+    this->event_server->create_event(this->connection_closed_event);
+    this->cloned=true;
+    this->socket_fd=fd;
+  }
+}
+
+CSocket *CSocket::create_socket(const std::string &comm_id, const int fd)
+{
+  CSocket *new_socket;
+
+  new_socket=new CSocket(comm_id,fd);
+
+  return new_socket;
+}
+
+std::string CSocket::get_connection_closed_event(void)
+{
+  return this->connection_closed_event;
+}
+
+void CSocket::hard_open(void *comm_dev)
+{
+  int yes=1;
+
+  if(!this->cloned)
+  {
+    if((this->socket_fd=socket(AF_INET,SOCK_STREAM,0))<0)
+    {
+      /* handle exceptions */
+      throw CSocketException(_HERE_,"Error opening socket", this->comm_id);
+    }
+    else
+    {
+      if(setsockopt(this->socket_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))<0)
+      {
+        /* handle exceptions */
+        throw CSocketException(_HERE_,"Impossible to change socket options",this->comm_id);
+      }
+    }
+  }
+}
+
+void CSocket::hard_config(void *config)
+{
+  /* do nothing */
+}
+
+int CSocket::hard_read(unsigned char *data, int len)
+{
+  int num_read=0;
+
+  if(!this->event_server->event_is_set(this->connection_closed_event))
+  {
+    if((num_read=::read(this->socket_fd,data,len))==-1)
+    {
+      /* handle exceptions */
+      throw CSocketException(_HERE_,"Error while reading from the socket.",this->comm_id);
+    }
+  }
+
+  return num_read;
+}
+
+int CSocket::hard_write(unsigned char *data, int len)
+{
+  int num_write=0;
+  
+  if(!this->event_server->event_is_set(this->connection_closed_event))
+  {
+    if((num_write=::write(this->socket_fd,data,len))==-1)
+    {
+      /* handle exceptions */
+      throw CSocketException(_HERE_,"Error while writing to the socket.",this->comm_id);
+    }
+  }
+
+  return num_write;
+}
+
+int CSocket::hard_get_num_data(void)
+{
+  int num;
+
+  if(!this->event_server->event_is_set(this->connection_closed_event))
+  {
+    if(ioctl(this->socket_fd,FIONREAD,&num)==-1)
+    {
+      /* handle exceptions */
+      throw CSocketException(_HERE_,"Error while getting the number of bytes available from the socket.",this->comm_id);
+    }
+  }
+
+  return num;
+}
+
+int CSocket::hard_wait_comm_event(void)
+{
+  fd_set receive_set,error_set;
+  int max_fd,wait_result=0;
+
+  max_fd=this->socket_fd+1;
+  FD_ZERO(&receive_set);
+  FD_SET(this->socket_fd,&receive_set);
+  FD_ZERO(&error_set);
+  FD_SET(this->socket_fd,&error_set);
+  wait_result=select(max_fd,&receive_set,NULL,&error_set,NULL);
+  if(wait_result==-1)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_,"Error while waiting for socket events",this->comm_id);
+  }
+  else
+  {
+    if(FD_ISSET(this->socket_fd,&receive_set))/* data has been received */
+    {
+      if(this->hard_get_num_data()==0)
+      {
+        if(!this->event_server->event_is_set(this->connection_closed_event))
+          this->event_server->set_event(this->connection_closed_event);
+        return -1;
+      }
+      else
+        return 1;
+    }
+    if(FD_ISSET(this->socket_fd,&error_set))
+      return 2;
+  }
+  
+  return -1;
+}
+
+void CSocket::hard_close(void)
+{
+  if(this->socket_fd!=-1)
+  {
+    if(::close(this->socket_fd)<0)
+      throw CSocketException(_HERE_,"Error while closing the socket",this->comm_id);
+    this->socket_fd=-1;
+  }
+  this->cloned=false;
+}
+
+CSocket::~CSocket()
+{
+  this->close();
+  if(this->connection_closed_event.size()!=0)
+  {
+    this->event_server->delete_event(this->connection_closed_event);
+    this->connection_closed_event.clear();
+  }
+}
diff --git a/src/sockets/socket.h b/src/sockets/socket.h
new file mode 100644
index 0000000000000000000000000000000000000000..89f1763f23aa287c12e0936db0d3d486504af0ad
--- /dev/null
+++ b/src/sockets/socket.h
@@ -0,0 +1,322 @@
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+#include "comm.h"
+#include "mutex.h"
+#include <iostream>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netdb.h>
+
+/**
+ * \brief Socket information structure
+ *
+ * This structure holds information about the remote IP address and the port 
+ * where the socket is connected.  
+ *
+ */
+typedef struct {
+  /**
+   * \brief address of the socket
+   *
+   * A string with the desired IP addres to assign to the socket. The IP address 
+   * must be passed with the dot format, as shown here
+   *
+   * * 192.168.0.1
+   */
+  std::string address;
+  /**
+   * \brief port of the socket
+   *
+   * An integer with the port number to be assigned to the socket. This value can 
+   * be any positive interger which is not used by any other application.
+   */
+  int port;
+}TSocket_info;
+
+/**
+ * \brief Socket driver
+ *
+ * This class implements a driver to use generic sockets using the TCP/IP protocol.
+ * It inherits from CComm to include all the basic functionality of a communication
+ * device and reimplements the socket specific functions.
+ *
+ * This class provides an event which is activated when the connection is remotely
+ * closed. This event can be used by the application using the socket to monitor
+ * the state iof the connection. To get the identifier of this event, use the 
+ * get_connection_closed_event() function.
+ *
+ * A special constructor is provided to create a new CSocket object from an already
+ * initialized socket file descriptor provided by some system function of a 
+ * manufacturer library. However, this constructor is no public, and it can only
+ * be accessed by the create_socket() function.
+ *
+ * In case of any error, this class throws an exceptions of the CSocketException class.
+ *
+ * For more detailed description of the behavior of this class, see the documentation
+ * for the CComm base class.
+ */
+
+class CSocket : public CComm
+{
+  private:
+    /**
+     * \brief Connection closed event identifier
+     *
+     * This string holds the unique identifier of the event to indicate the
+     * closure of a connection. Its value is initialized at construction time
+     * with the name assigned to the class to create the unique identifier for
+     * the event. Use the get_connection_closed_event() function to get this
+     * string.
+     */
+    std::string connection_closed_event;
+    /**
+     * \brief cloned socket flag
+     *
+     * This attribute is used to differentiate between a CSocket object created
+     * by the default constructor and those created by the create_socket() function.
+     * This flag is mainly used to avoid opening a new socket when the hard_open()
+     * function is called. The value of this attribute is changed internally and can 
+     * not be accessed from the outside.
+     */ 
+    bool cloned;
+  protected:
+    /** 
+     * \brief socket file descriptor.
+     *
+     * This integer holds the file descriptor of the socket associated to the
+     * object. This attribute is initialized when either the open() or create_socket()
+     * functions are called and can not be modified afterwards. Its value is valid 
+     * until the close() function is called.
+     *
+     */
+    int socket_fd;
+    /**
+     * \brief Constructor with parameters 
+     *
+     * This constructor is used only by the create_socket() function to create a 
+     * new CSocket object and associate it to an already initialized socket file
+     * descriptor. Since it is protected, it can not be used as a regular 
+     * constructor.
+     *
+     * \param comm_id a string with the unique identifier of the socket object.
+     *                This identifier is used to create the unique identifiers 
+     *                of the internal threads and events, so it is imperative
+     *                that each socket has a unique name.
+     *
+     * \param fd a positive integer with the value of the file descriptor of
+     *           an already initialized socket. If the file descriptor provided
+     *           to this function is not valid or it is not properly initialized,
+     *           unexpected errors will ocurr.
+     */
+    CSocket(const std::string &comm_id,const int fd);
+    /**
+     * \brief function to create a new socket object from a file descriptor
+     *
+     * This function is used in a server side application to create a new
+     * CSocket object (or any inherited class) from an already initialized
+     * socket file descriptor. This is required when the server socket 
+     * accepts a new connection with the accept() function, which returns
+     * a file descriptor which is not associated to any CSocket object.
+     *
+     * This function is defined as static so that it can be called without
+     * having to create an object of this class, but it can not be accessed
+     * outside an object of this class, since it is defined as protected.
+     *
+     * The most common use of this function is in a server side of a connection
+     * just after the accept() function returns with a new client connection, in
+     * order to associate the new socket to a CSocket object.
+     *
+     * \param comm_id a string with the unique identifier of the socket object.
+     *                This identifier is used to create the unique identifiers 
+     *                of the internal threads and events, so it is imperative
+     *                that each socket has a unique name.
+     *
+     * \param fd a positive integer with the value of the file descriptor of
+     *           an already initialized socket. If the file descriptor provided
+     *           to this function is not valid or it is not properly initialized,
+     *           unexpected errors will ocurr.
+     *
+     * \return a new CSocket object initialized with the parameters passed as 
+     *         arguments to the function.
+     */
+    static CSocket *create_socket(const std::string &comm_id, const int fd);
+     /**
+      * \brief Function to actually open the device
+      *
+      * This function is called automatically when the base class open() function
+      * is called. By default, it initializes the socket file descriptor using the
+      * socket() system call. But, if the object has been created by the 
+      * create_socket() function, this function does nothing.
+      *
+      * This class does not need any parameter since the socket is created by 
+      * default using a TCP/IP protocol and the AF_INET socket family. So the
+      * argument passed to this function is ignored and may be NULL.
+      * 
+      * This function can throw any CSocketException object exception or the generic 
+      * CCommException class.
+      *
+      * \param comm_dev this parameter is ignored in this case and can be set to NULL.
+      *                 It is only keeped for backward compatiblity with the CComm
+      *                 class.
+      */
+    virtual void hard_open(void *comm_dev=NULL);
+    /**
+      * \brief Function to actually configure the device
+      * 
+      * This function is called automatically when the base class config() function
+      * is called. In this case this function does nothing, since all the necessay
+      * parameters are provide to the open() function. However, it is necessary to 
+      * call the config() function to successfully change the internal state of the
+      * communication device.
+      *
+      * The provided parameter in this case can be NULL since no configuration is
+      * needed. This function can throw any CCommException object exception or else 
+      * any exception class defined by the inherited class.
+      *
+      * \param config This parameter is not used since no configuration is required.
+      *               It is only keeped for backward compatiblity with the CComm
+      *               class.
+      */
+     virtual void hard_config(void *config=NULL);
+    /**
+     * \brief Function to actually read from the device
+     *
+     * This function is automatically called when the new data received event is 
+     * activated. The read() function from the base class gets data from the 
+     * internal queue, so this function is not used. It must try to read the 
+     * ammount of data specified and store it in the data buffer provided without 
+     * blocking. Also, it must return the number of bytes actually read from the 
+     * devicve, since they may be different than the desired value.
+     *
+     * In case of any error, this function throws a CSocketException exception.
+     *
+     * \param data a reference to the buffer where the received data must be 
+     * copied. The necessary memory for this buffer must be allocated before 
+     * calling this function and have enough size to store all the desired data.
+     * If this buffer is not initialized, the function throws an exception.
+     *
+     * \param len a positive interger that indicates the number of byte to be
+     * read from the communication device. This value must be at most the length 
+     * of the data buffer provided to the function.
+     *
+     * \return an integer with the number of bytes actually read. These number 
+     * coincide with the desired number if there is enough data in the internal 
+     * queue, but it could be smaller if not.
+     */
+    virtual int hard_read(unsigned char *data, int len);
+    /**
+     * \brief Hard write function
+     *
+     * This function is automatically called when the base class write() function
+     * is called. It must try to write the desired ammount of data to the communication 
+     * device without blocking. Also it must return the number of bytes actually
+     * written to the communication device since they may be different from the
+     * desired value.
+     *
+     * In case of any error, this function throws a CSocketException exception.
+     *
+     * \param data a reference to the buffer with the data must be send to the 
+     * device. The necessary memory for this buffer must be allocated before 
+     * calling this function and have enough size to store all the desired data.
+     * If this buffer is not initialized, the function throws an exception.
+     *
+     * \param len a positive interger that indicates the number of byte to be
+     * written to the communication device. This value must be at most the length 
+     * of the data buffer provided to the function.
+     *
+     * \return an integer with the number of bytes actually written. These number 
+     * coincide with the desired number if there is enough data in the internal 
+     * queue, but it could be smaller if not.
+     */
+    virtual int hard_write(unsigned char *data, int len);
+    /**
+     * \brief Function to actually get the number of bytes availables
+     *
+     * This function is called when the new data received event is activated.
+     * It must get the number of data bytes available from the communication
+     * device and return its value without blocking.
+     *
+     * In case of any error, this function throws a CSocketException exception.
+     *
+     * \return an integer with the number of bytes available in the receive queue. 
+     * This value can be 0 if there is no data available, but there is ni upper
+     * limit in its value.
+     */
+    virtual int hard_get_num_data(void);
+    /**
+     * \brief Function to actually wait for a given communication event 
+     *
+     * This function is called in the internal communciation thread to wait for 
+     * any event on the communuication device. It must check for any event on the
+     * device (reception, end of transmission or error) and return the
+     * corresponding identifier. When an event is activated, this function must 
+     * return to allow the base class to handle it, and the it is called again
+     * to wait for the next event.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \return -1 if there has been any error or else the identifier of the 
+     *         communciation event:
+     *
+     * - 1 for the new data received event
+     * - 2 for the error event
+     */
+    virtual int hard_wait_comm_event(void);
+    /** 
+     * \brief Hard close function
+     *
+     * This function is called when the base class close() funciton is called. It
+     * must free the device handle initialized by the open() function and also free
+     * any other resource allocated by the inherited class.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     */
+    virtual void hard_close(void);
+  public:
+    /**
+     * \brief default constructor
+     *
+     * This constructor creates a new CSocket object. It does not open a physical 
+     * socket, it only allocates the necessary resources to use it.
+     *
+     * \param comm_id  A null terminated string which identifies the 
+     *                 communications device. This string is used to created a
+     *                 unique identifier for all the threads and events of the
+     *                 class.
+     */
+    CSocket(const std::string &comm_id);
+    /** 
+     * \brief Function to get the name of Connection Closed Event
+     *  
+     * This function is used to retrieve the identifier of the connection closed
+     * event. This event is initialized at contruction time, and it can be
+     * retrieved at any time. 
+     *
+     * This function only returns a copy of the internal attribute, so the value
+     * returned by this function can be modified without affecting the proper
+     * function of the class.
+     *
+     * \return a string with a copy of the identifier of the connection closed
+     *         event. This identifier can be used in the wait_first() or wait_all()
+     *         functions of the CEventServer class to wait its activation.
+     */
+    std::string get_connection_closed_event(void);
+    /**
+     * \brief Destructor
+     *
+     * This destructor does nothing. The base class destructor is the one in 
+     * charge of freeing all the allocated resources.
+     */
+    virtual ~CSocket();
+};
+
+#endif
diff --git a/src/sockets/socketclient.cpp b/src/sockets/socketclient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..efb63cf52119da6e5dc075deb640c9d4f76343a0
--- /dev/null
+++ b/src/sockets/socketclient.cpp
@@ -0,0 +1,70 @@
+#include "socketclient.h"
+#include "socketexceptions.h"
+#include <string.h>
+
+CSocketClient::CSocketClient(const std::string &sock_id) : CSocket(sock_id)
+{
+  this->connected=false;
+  this->remote.address.clear();
+  this->remote.port=-1;
+}
+
+void CSocketClient::hard_close(void)
+{
+  CSocket::hard_close();
+  this->connected=false;
+  this->remote.address.clear();
+  this->remote.port=-1;
+}
+
+void CSocketClient::hard_open(void *comm_dev)
+{
+  TSocket_info *remote=(TSocket_info *)comm_dev;
+  sockaddr_in sock;
+   
+  CSocket::hard_open(NULL);
+  memset(&sock,0,sizeof(sock));
+  sock.sin_family=AF_INET;
+  if(inet_aton(remote->address.c_str(),&sock.sin_addr)==0)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_,"Impossible to convert IP address",this->comm_id);
+  }
+  else
+  {
+    sock.sin_port=htons(remote->port);
+    if((::connect(this->socket_fd,(struct sockaddr *)&sock,sizeof(sock)))<0)
+    {
+      /* handle exceptions */
+      if(errno==ECONNREFUSED)
+        throw CSocketNoConnectionException(_HERE_,"Nobody listening",this->comm_id);
+      else
+        throw CSocketException(_HERE_, "Error with connect function", this->comm_id);
+    }
+    else
+    {
+      this->connected=true;
+      this->remote.port=remote->port;
+      this->remote.address=remote->address;
+    }
+  }
+}
+
+int CSocketClient::get_remote_port(void)
+{
+  return this->remote.port;
+}
+
+std::string CSocketClient::get_remote_IP_address(void)
+{
+  return this->remote.address;
+}
+
+bool CSocketClient::is_connected(void)
+{
+  return this->connected;
+}
+
+CSocketClient::~CSocketClient()
+{
+}
diff --git a/src/sockets/socketclient.h b/src/sockets/socketclient.h
new file mode 100644
index 0000000000000000000000000000000000000000..741a876b87c6963def291e63e341f918a1bd2f46
--- /dev/null
+++ b/src/sockets/socketclient.h
@@ -0,0 +1,152 @@
+#ifndef _SOCKETCLIENT_H
+#define _SOCKETCLIENT_H
+
+#include "socket.h"
+
+/**
+ * \brief Client side socket 
+ *
+ * This class implements the functionality of a client socket. It inherits from
+ * the socket class for the basic socket communication issues and adds the
+ * necessary resources to work as a client socket.
+ *
+ * The hard_open() function (called when the base class open() function is called)
+ * is extended to try to connect to the desired server. If the server is already 
+ * listening, the connection is set. However, if the server is not yet listening,
+ * a special exception (CSocketNoConnection) is thrown. This special exception can
+ * be catch and used to iterate until the server is ready.
+ *
+ * The general procedure to work with client sockets is as follows:
+ *
+ * 1. Create a new CSocketClient object with a unique identifier.
+ * 2. Call the open() function with the server IP address and port
+ * 3. If a CSocketNoConnection is throw, either repeat step 2 or exit.
+ * 4. On success, call the config() function without any parameters
+ * 5. Perform any read or write operations on the socket
+ * 6. Call the close() function to finish the socket connection.
+ *  
+ */
+class CSocketClient : public CSocket
+{
+  private:
+    /**
+     * \brief information on the remote server
+     *
+     * This structure holds the IP address and port of the remote server to which
+     * the client socket is connected. This structure is initialized after a 
+     * successfull call to the open() function and can not be modified afterwards,
+     * until the socket is closed and reconnected to an other server.
+     *
+     * By default, the IP address string is empty and the port is initialized to -1.
+     * Use the get_remote_port() and get_remote_IP_address() to get the values
+     * of this structure at any time.
+     */ 
+    TSocket_info remote;
+    /**
+     * \brief Connection flag
+     *
+     * This flag indicated whether the client socket is connected to a server or 
+     * not. By default it is set to false, and it is only set to true after a 
+     * successfull call to the open() function. When the socket is closed, and 
+     * therefore the connection is severed, this flag is set back to false.
+     *
+     * Use the is_connected() function to check whether the socket is connected
+     * or not.
+     */ 
+    bool connected;
+  protected:
+    /**
+     * \brief Connect function
+     *
+     * This function is called when the base class open() function is called, and 
+     * it is used to perform the connection to a server. This function requires a 
+     * TSocket_info structure as parameter which must be provided to the open() 
+     * call. It also calls the hard_open() function of the CSocket class to 
+     * initialize the base class attributes.
+     *
+     * The IP address and port within this structure are used to try to stablish
+     * a communication with a remote server. If the server is already listening,
+     * the function returns normally with all the internal attributes properly
+     * initialized.
+     *
+     * If the server is not yet listening, this function throws a CSocketNoConnection
+     * exception. This exception can be catched and used to iterate the process 
+     * until the server is available or terminate the applcation. In case of any
+     * other error, this function throws a CSocketException.
+     *
+     * After the connection is set, it is still necessary to call the config() 
+     * function to properly configure the object to send and receive information.
+     *
+     * \param comm_dev a valid pointer to a TSocket_info structure with the IP
+     *                 address and listening port of the desired server. See the
+     *                 documentation on the TSocket_info structure for more
+     *                 information on the IP address and port format.
+     */
+    virtual void hard_open(void *comm_dev=NULL);
+    /**
+     * \brief function to close the client socket
+     *
+     * This function is called when the close() function of the base class is 
+     * called. It calls the hard_close() function of the CSocket class to
+     * actually terminate the connection and change all the internal attributes 
+     * to reflect that (the connection flag is set back to false and the server
+     * IP address and port are set to the default values.
+     *
+     * In case of any error, this function throws a CSocketException.
+     */ 
+    virtual void hard_close(void);
+  public:
+    /** 
+     * \brief Constructor
+     *
+     * This constructor creates a new client socket object with the provided 
+     * identifier, but does not connect it to any server yet. To do that, it
+     * is necessary to call the open() function of the base class with a 
+     * pointer to a TSocket_info structure as a parameter.
+     *
+     * \param sock_id a null terminated string with the unique identifier for
+     *                the socket. This identifier is internally used to create
+     *                the unique indentifiers for all threads and events, so 
+     *                it is important that a single identifier is not used more
+     *                than once.
+     */
+    CSocketClient(const std::string &sock_id);
+    /**
+     * \brief function to return the remote server port
+     *
+     * This function returns the port number of the current connection if the
+     * socket is connected to a server. Otherwise it returns -1.
+     *
+     * \return the server's port number to which it is connected, or -1 if the
+     *         socket is not currently connected to any server.
+     */ 
+    int get_remote_port(void);
+    /**
+     * \brief function to return the remote server IP address
+     *
+     * This function returns the IP address of the current connection if the
+     * socket is connected to a server. Otherwise it returns an empty string.
+     *
+     * \return the server'a IP address to which it is connected, or an empty
+     *         string if the socket is not currently connected to any server.
+     */
+    std::string get_remote_IP_address(void); 
+    /**
+     * \brief function to check whether the socket is connected or not
+     *
+     * This function checks wether the client socket is connected to a server 
+     * or not.
+     *
+     * \return true is the socket is connected to a server and false otherwise.
+     */ 
+    bool is_connected(void);
+    /**
+      * \brief destructor
+      *
+      * When the object is destroyed, the connection to the server is lost (if
+      * it was not closed before) and all the resources of the client are freed. 
+      */
+    virtual ~CSocketClient();
+};
+
+#endif
diff --git a/src/sockets/socketexceptions.cpp b/src/sockets/socketexceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..02e7485ff4c42919f1e136a0a62462c63de464dc
--- /dev/null
+++ b/src/sockets/socketexceptions.cpp
@@ -0,0 +1,15 @@
+#include "socketexceptions.h"
+#include <string.h>
+#include <stdio.h>
+
+const string socket_exception_msg="[CSocket class] - ";
+
+CSocketException::CSocketException(const string& where,const string& error_msg,const string& comm_id):CCommException(where,socket_exception_msg,error_msg)
+{
+  this->error_msg+=" - ";
+  this->error_msg+=comm_id;
+}
+
+CSocketNoConnectionException::CSocketNoConnectionException(const string& where,const string& error_msg,const string& comm_id):CSocketException(where,error_msg,comm_id)
+{
+}
diff --git a/src/sockets/socketexceptions.h b/src/sockets/socketexceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..75e97acfb6bd083f0fddfaf95a54e4b0b0d4eb44
--- /dev/null
+++ b/src/sockets/socketexceptions.h
@@ -0,0 +1,116 @@
+#ifndef SOCKET_EXCEPTIONS
+#define SOCKET_EXCEPTIONS
+
+#include "commexceptions.h"
+
+using namespace std;
+
+/**
+ * \brief Socket exception class
+ *
+ * This class implements the exceptions for the CSocket communication class. 
+ * In addition to the basic error message provided by the base class CException, 
+ * this exception class provides also the unique identifier of the communication
+ * device that generated the exception.
+ *
+ * Also, similarly to other exception classes, it appends a class identifer
+ * string ("[CSocket class] - ") to the error message in order to identify 
+ * the class that generated the exception.
+ *
+ * The base class can be used to catch any exception thrown by the application
+ * or also, this class can be used in order to catch only exceptions generated 
+ * by CSocket objects.
+ *
+ */
+class CSocketException : public CCommException
+{
+  public:
+    /** 
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CSocket class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device 
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * Error: [CComm class] - [CSocket class] - <error message> - <comm id>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     * \param comm_id a null terminated string that contains the communication
+     *                device unique identifier. This string must be the one used to 
+     *                create the object.
+     *
+     *
+     */  
+    CSocketException(const string& where,const string& error_msg,const string& comm_id);
+};
+
+/**
+ * \brief No connection exception class
+ *
+ * This class implements a special exception for the CSocket class and its inherited
+ * classes that indicates that the connection has been refused. This event ocurrs
+ * when a client side application is trying to connect to a server, and it is still
+ * not ready to accept connections.
+ *
+ * This exception can be caught to prevent the client application to close when the 
+ * server in not yet ready, and then used to iterate until it is. If functionality
+ * is not desired, this exception can be caught as a simple CSocketException or a
+ * basic CException.
+ *
+ * The error message and the information provided by this exception is the same as
+ * the information provided by the CSocketException class.
+ *
+ */
+class CSocketNoConnectionException : public CSocketException
+{
+  public:
+    /**
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CSocket class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device 
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * Error: [CComm class] - [CSocket class] - <error message> - <comm id>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     * \param comm_id a null terminated string that contains the communication
+     *                device unique identifier. This string must be the one used to 
+     *                create the object.
+     *
+     *
+     */  
+    CSocketNoConnectionException(const string& where,const string& error_msg,const string& comm_id);
+};
+
+#endif
diff --git a/src/sockets/socketserver.cpp b/src/sockets/socketserver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..599e8d0355263ca333d8b27be6a113d10f14788b
--- /dev/null
+++ b/src/sockets/socketserver.cpp
@@ -0,0 +1,525 @@
+#include "socketserver.h"
+#include "socketexceptions.h"
+#include "eventexceptions.h"
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <string.h>
+
+int CSocketServer::counter=0;
+
+CSocketServer::CSocketServer(const std::string &sock_id) : CSocket(sock_id)
+{
+  this->current_clients=0;
+  this->max_clients=0;
+  this->state=server_created;
+  // clear the client list
+  this->client_list.clear();
+  // clear the new connection event id
+  this->new_connection_event_id.clear();
+  this->connect_thread_id.clear();
+  this->disconnect_thread_id.clear();
+  // set up server information
+  this->info.port=-1;
+  this->info.address.clear();
+  // create the threads
+  this->connect_thread_id=sock_id + "_connect_thread";
+  this->thread_server->create_thread(this->connect_thread_id);
+  this->thread_server->attach_thread(this->connect_thread_id,connect_thread,this);
+  this->disconnect_thread_id=sock_id + "_disconnect_thread";
+  this->thread_server->create_thread(this->disconnect_thread_id);
+  this->thread_server->attach_thread(this->disconnect_thread_id,disconnect_thread,this);
+  // create the events
+  this->new_connection_event_id=sock_id+"_new_connection_event";
+  this->event_server->create_event(this->new_connection_event_id);
+  this->update_list_event_id=sock_id+"_update_list_event";
+  this->event_server->create_event(this->update_list_event_id);
+  this->finish_connect_thread_event_id=sock_id+"_finish_connect_thread_event";
+  this->event_server->create_event(this->finish_connect_thread_event_id);
+  this->finish_disconnect_thread_event_id=sock_id+"_finish_disconnect_thread_event";
+  this->event_server->create_event(this->finish_disconnect_thread_event_id);
+}
+
+void CSocketServer::hard_open(void *comm_dev)
+{
+  TSocket_info *info=(TSocket_info *)comm_dev;
+  sockaddr_in sock;
+
+  memset(&sock,0,sizeof(sock));
+  CSocket::hard_open();
+  if(comm_dev==NULL)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_,"Invalid server information",this->comm_id);
+  }
+  else
+  {
+    // set non-blocking operation
+    if(fcntl(this->socket_fd,F_SETFL,O_NONBLOCK)<0)
+    {
+      /* handle exceptions */
+      std::cout << "error" << std::endl;
+    }
+    else
+    {
+      if(this->state==server_created)
+      {
+        sock.sin_family=AF_INET;
+        if(inet_aton(info->address.c_str(),&sock.sin_addr)==0)
+        {
+          /* handle exceptions */
+          throw CSocketException(_HERE_,"Impossible to convert IP address",this->comm_id);
+        } 
+        else
+        {
+          sock.sin_port=htons(info->port);
+          if(::bind(this->socket_fd,(struct sockaddr *)&sock,sizeof(sock))<0)
+          {
+            /* handle exceptions */
+            throw CSocketException(_HERE_,"Impossible to bind the socket to the desired IP address and port.",this->comm_id);
+          }
+          else
+          {
+            this->server_access.enter();
+            this->state=server_binded;
+            this->info.port=info->port;
+            this->info.address=info->address;
+            this->server_access.exit();
+          }
+        }
+      }
+      else
+      {
+        /* handle exceptions */
+        throw CSocketException(_HERE_,"The server is not created.",this->comm_id);
+      } 
+    }
+  }
+}
+void CSocketServer::hard_config(void *config)
+{
+  int num_listen=*((int *)config);
+
+  CSocket::hard_config();
+  if(config==NULL)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_,"Invalid configuration information",this->comm_id);
+  }
+  else
+  {
+    if(this->state==server_binded)
+    {
+      if(::listen(this->socket_fd,num_listen)<0)
+      {
+        /* handle exceptions */
+        throw CSocketException(_HERE_,"Impossible to listen to the desired IP address and port.",this->comm_id);
+      }
+      else
+      {
+        this->server_access.enter();
+        this->state=server_listening;
+        this->server_access.exit();
+      }
+    }
+    else
+    {
+      /* handle exceptions */
+      throw CSocketException(_HERE_,"The server is not binded",this->comm_id);
+    }
+  }
+}
+
+int CSocketServer::hard_wait_comm_event(void)
+{
+  std::string wait_event=this->comm_id+"_wait_event";
+  std::list<std::string> events;
+
+  this->event_server->create_event(wait_event);
+  events.push_back(wait_event);
+
+  this->event_server->wait_first(events);
+
+  return -1;
+}
+
+void CSocketServer::hard_close(void)
+{
+  CSocket::hard_close();
+  this->stop_server();
+  this->state=server_created;
+  this->info.port=-1;
+  this->info.address.clear();
+}
+
+void CSocketServer::set_max_clients(int max_clients)
+{
+  this->server_access.enter();
+  this->max_clients = max_clients;
+  this->server_access.exit();
+}
+
+int CSocketServer::get_max_clients(void)
+{
+  return this->max_clients;
+}
+
+int CSocketServer::get_num_current_clients(void)
+{
+  return this->current_clients;
+}
+
+void CSocketServer::start_server(void)
+{
+  if(this->state!=server_listening)
+  {
+    /* handle exceptions */
+    throw CSocketException(_HERE_,"The server is not properly configured to accept connections",this->comm_id);
+  }
+  else
+  { 
+    this->server_access.enter();
+    this->state=server_on;
+    this->server_access.exit();
+    this->thread_server->start_thread(this->connect_thread_id);
+    this->thread_server->start_thread(this->disconnect_thread_id);
+  }
+}
+
+void CSocketServer::stop_server(void)
+{
+  std::list<TClient_info_int *>::iterator it;
+
+  if (this->state==server_on)
+  {
+    this->event_server->set_event(this->finish_connect_thread_event_id);
+    this->thread_server->end_thread(this->connect_thread_id);
+    this->event_server->set_event(this->finish_disconnect_thread_event_id);
+    this->thread_server->end_thread(this->disconnect_thread_id);
+    this->server_access.enter();
+    this->state=server_listening;
+    this->server_access.exit();
+    // remove all clients from the list
+    // activate the disconnect event    
+    for(it=this->client_list.begin();it!=this->client_list.end();it++)
+      this->event_server->set_event((*it)->disconnect_event_id);
+  }
+  else
+  {
+    /* handle exceptions */ 
+    throw CSocketException(_HERE_,"Server is not running", this->comm_id);
+  }
+}
+
+void CSocketServer::broadcast(unsigned char *data, const int len)
+{
+  std::list<TClient_info_int *>::iterator it;
+  int written=0;
+
+  try{
+    this->server_access.enter();
+    for(it=this->client_list.begin();it!=this->client_list.end();it++)
+    {
+      if((written=(*it)->socket->write(data,len))!=len)
+      {
+        this->server_access.exit();
+        /* handle exceptions */
+        throw CSocketException(_HERE_,"Error while writing to the client",(*it)->client_id);
+      }
+    }
+    this->server_access.exit();
+  }catch(CException &e){
+    /* handle exceptions */
+    this->server_access.exit();
+    throw;
+  }
+}
+
+int CSocketServer::write_to(const std::string &sock_id, unsigned char *data, const int len)
+{
+  std::list<TClient_info_int *>::iterator it;
+
+  try{
+    this->server_access.enter();
+    for(it=this->client_list.begin();it!=this->client_list.end();it++)
+    {
+      if((*it)->client_id==sock_id)
+      {
+        this->server_access.exit();
+        return (*it)->socket->write(data,len);
+      }
+    }
+    this->server_access.exit();
+    throw CSocketException(_HERE_,"Unknown socket identifier",sock_id);
+  }catch(CException &e){
+    /* handle exceptions */
+    this->server_access.exit();
+    throw;
+  }
+}
+
+int CSocketServer::read_from(const std::string &sock_id, unsigned char *data, const int len)
+{
+  std::list<TClient_info_int *>::iterator it;
+
+  try{
+    this->server_access.enter();
+    for(it=this->client_list.begin();it!=this->client_list.end();it++)
+    {
+      if((*it)->client_id==sock_id)
+      {
+        this->server_access.exit();
+        return (*it)->socket->read(data,len);
+      }
+    }
+    this->server_access.exit();
+    throw CSocketException(_HERE_,"Unknown socket identifier",sock_id);
+  }catch(CException &e){
+    /* handle exceptions */
+    this->server_access.exit();
+    throw;
+  }
+}
+
+int CSocketServer::get_num_data_from(const std::string &sock_id)
+{
+  std::list<TClient_info_int *>::iterator it;
+
+  try{
+    this->server_access.enter();
+    for(it=this->client_list.begin();it!=this->client_list.end();it++)
+    {
+      if((*it)->client_id==sock_id)
+      {
+        this->server_access.exit();
+        return (*it)->socket->get_num_data();
+      }
+    }
+    this->server_access.exit();
+    throw CSocketException(_HERE_,"Unknown socket identifier",sock_id);
+  }catch(CException &e){
+    /* handle exceptions */
+    this->server_access.exit();
+    throw;
+  }
+}
+
+string CSocketServer::get_new_connection_event_id(void)
+{
+  return this->new_connection_event_id;
+}
+
+TClient_info *CSocketServer::get_new_client(void)
+{
+  TClient_info *client,*client_queue;
+
+  this->server_access.enter(); 
+  if(this->new_clients.size()>0)
+  {
+    client_queue=this->new_clients.front();
+    client=new TClient_info;
+    client->client_id=client_queue->client_id;
+    client->IP=client_queue->IP;
+    client->port=client_queue->port;
+    client->disconnect_event_id=client_queue->disconnect_event_id;
+    client->rx_event_id=client_queue->rx_event_id;
+    this->new_clients.pop();
+    this->server_access.exit(); 
+    return client;
+  }
+  else
+  { 
+    this->server_access.exit(); 
+    return NULL;
+  }
+}
+
+void CSocketServer::free_client(TClient_info *info)
+{
+  std::list<TClient_info_int *>:: iterator it;
+  sockaddr_in sock;
+
+  this->server_access.enter();
+  for(it=this->client_list.begin();it!=this->client_list.end();it++)
+  {
+    if((*it)->client_id==info->client_id)
+    {
+      (*it)->socket->close();
+      delete (*it)->socket;
+      this->current_clients--;
+      it=this->client_list.erase(it);
+      this->event_server->delete_event(info->disconnect_event_id);
+      delete info;
+      if(this->socket_fd==-1)
+      {
+        memset(&sock,0,sizeof(sock));
+        sock.sin_family=AF_INET;
+        inet_aton(this->info.address.c_str(),&sock.sin_addr);
+        sock.sin_port=htons(this->info.port);
+        this->CSocket::hard_open();
+        ::bind(this->socket_fd,(struct sockaddr *)&sock,sizeof(sock));
+        ::listen(this->socket_fd,1);
+        this->state=server_on;          
+      }
+      this->server_access.exit();
+      return;
+    }
+  }
+  this->server_access.exit();
+  throw CSocketException(_HERE_,"No such client",this->comm_id);
+}
+
+void *CSocketServer::connect_thread(void *param)
+{
+  CSocketServer *server=(CSocketServer *)param;
+  TClient_info_int *client_info_int;
+  std::stringstream sock_id;
+  TClient_info *client_info;
+  struct sockaddr_in client;
+  int new_fd,len=0;
+  bool end=false;
+
+  while(!end)
+  {
+    if(server->state==server_on)
+    {
+      server->server_access.enter();
+      try{
+        len=sizeof(client);
+        server->server_access.exit();
+        if((new_fd=::accept(server->socket_fd,(struct sockaddr *)&client,(socklen_t *)&len))<0)
+        {
+          if(errno==EWOULDBLOCK)
+          {
+            if(server->event_server->event_is_set(server->finish_connect_thread_event_id))
+              end=true;
+            else
+              usleep(100000);
+          }
+          else
+          {  
+            /* handle exceptions */
+            throw CSocketException(_HERE_,"Unexpected error while accepting new connections.",server->comm_id);
+          }
+        }
+        else
+        {
+          server->server_access.enter();
+          server->counter++;
+          sock_id.str("");
+          sock_id << "client_socket_" << server->counter;
+          // initialize the internal client info
+          client_info_int=new TClient_info_int; 
+          client_info_int->socket=CSocket::create_socket(sock_id.str(),new_fd);
+          client_info_int->socket->open(NULL);
+          client_info_int->socket->config(NULL);
+          client_info_int->client_id=sock_id.str();
+          client_info_int->disconnect_event_id=sock_id.str()+"_disconnect";
+          server->event_server->create_event(client_info_int->disconnect_event_id);
+          // initialize the external client info
+          client_info=new TClient_info;
+          client_info->client_id=sock_id.str();
+          client_info->IP=inet_ntoa(client.sin_addr);
+          client_info->port=(int)(ntohs(client.sin_port));
+          client_info->disconnect_event_id=client_info_int->disconnect_event_id;
+          client_info->rx_event_id=client_info_int->socket->get_rx_event_id();
+          // signal the connection of a new client
+          server->new_clients.push(client_info);
+          server->client_list.push_back(client_info_int);
+          server->current_clients++;
+          server->event_server->set_event(server->new_connection_event_id);
+          server->event_server->set_event(server->update_list_event_id);
+          if(server->current_clients==server->max_clients)
+          {
+            server->CSocket::hard_close(); 
+            server->state=server_created;
+          }
+          server->server_access.exit();
+        }
+      }catch(CException &e){
+        server->server_access.exit();
+        std::cout << e.what() << std::endl;
+      }
+    }
+    else
+    {
+      if(server->event_server->event_is_set(server->finish_connect_thread_event_id))
+        end=true;
+      sleep(1);
+    }
+  }
+  
+  pthread_exit(NULL);
+}
+
+void *CSocketServer::disconnect_thread(void *param)
+{
+  std::list<TClient_info_int *>:: iterator it_client;
+  CSocketServer *server=(CSocketServer *)param;
+  std::list<std::string>:: iterator it_event;
+  std::list<std::string> events;
+  int event_id=0,i=0;
+  bool end=false;
+
+  events.clear();
+  events.push_back(server->update_list_event_id);
+  events.push_back(server->finish_disconnect_thread_event_id);
+  while(!end)
+  {
+    try{
+      event_id=server->event_server->wait_first(events);
+      server->server_access.enter();
+      if(event_id==0)
+      {
+        events.clear();
+        events.push_back(server->update_list_event_id);
+        events.push_back(server->finish_disconnect_thread_event_id);
+        for(it_client=server->client_list.begin();it_client!=server->client_list.end();it_client++)
+          events.push_back((*it_client)->socket->get_connection_closed_event());
+      }
+      else
+      {
+        if(event_id==1)
+          end=true;
+        else
+        {
+          it_event=events.begin();
+          it_client=server->client_list.begin();
+          for(i=0;i<(event_id-2);i++) 
+          { 
+            it_event++;
+            it_client++;
+          }
+          it_event++;
+          if(!server->event_server->event_is_set((*it_client)->disconnect_event_id))
+            server->event_server->set_event((*it_client)->disconnect_event_id);
+          events.erase(it_event);
+        }
+      }
+      server->server_access.exit();
+    }catch(CException &e){
+      std::cout << e.what() << std::endl;
+    }
+  }
+
+  pthread_exit(NULL);
+}
+
+CSocketServer::~CSocketServer()
+{
+  this->event_server->delete_event(this->new_connection_event_id);
+  this->new_connection_event_id="";
+  this->event_server->delete_event(this->update_list_event_id);
+  this->update_list_event_id="";
+  this->event_server->delete_event(this->finish_connect_thread_event_id);
+  this->finish_connect_thread_event_id="";
+  this->event_server->delete_event(this->finish_disconnect_thread_event_id);
+  this->finish_disconnect_thread_event_id="";
+  this->thread_server->delete_thread(this->connect_thread_id);
+  this->connect_thread_id="";
+  this->thread_server->delete_thread(this->disconnect_thread_id);
+  this->disconnect_thread_id="";
+  this->info.port=-1;
+  this->info.address.clear();
+}
diff --git a/src/sockets/socketserver.h b/src/sockets/socketserver.h
new file mode 100644
index 0000000000000000000000000000000000000000..228b23b9aab438a6f91cb6dcfe909279a7a6bc12
--- /dev/null
+++ b/src/sockets/socketserver.h
@@ -0,0 +1,677 @@
+#ifndef _SOCKETSERVER_H
+#define _SOCKETSERVER_H
+
+#include <queue>
+#include "socket.h"
+
+/**
+ * \brief possible server states
+ *
+ * This ennumeration type represents all the possible states of the server, which
+ * are used internally to control its flow. The possible states are:
+ *
+ * * server_created: It is the default state when it is created for the first time. 
+ * * server_binded: after successfully calling the open() function, the server is
+ *                  attached to an IP address and port.
+ * * server_listening: after successfully calling the config() function the server
+ *                     is ready to listen to incomming connections. If the server
+ *                     is closed, it returns to the server_created state.
+ * * server_on: It is the main state when the server is started using the start()
+ *              function. In this state, the server is capable of detecting new 
+ *              connections and disconnections, as well as send and receive data 
+ *              to and from any client. If the server is stopped it returns to the
+ *              server_listening state.
+ *
+ * The next figure shows the server states and the possible transitions between them:
+ *
+ * \image html server_states.png
+ *
+ */
+typedef enum {server_created, server_binded, server_listening, server_on} server_state;
+
+/**
+ * \brief client information
+ *
+ * This structure holds all the information required by the server side application 
+ * to handle a connection with a new client. This structure is initialized when
+ * a new connection is stablished, and the get_new_client() function should be used 
+ * to retrieve it. Once the connection is closed, the free_client() function should
+ * be used to properly free all the allocated resources.
+ */
+typedef struct 
+{
+  /**
+   * \brief client identifier 
+   *
+   * This ideintifier is automatically assigned by the server when the connection is
+   * stablished. This identifier is unique for each connection and it is used to 
+   * identify the client to which send or receive information. 
+   */ 
+  std::string client_id;
+  /**
+   * \brief client IP address
+   *
+   * This string holds the IP address of the client in dot format (192.168.0.1). This 
+   * value can be used by the server side application to identify the different 
+   * clients connected. This field is purely informative and it is not used for
+   * any operation.
+   */ 
+  std::string IP;
+  /**
+   * \brief client port
+   *  
+   * this integer is the port assigned to the client for the connection. This port
+   * is automatically assigned by the accept function and can not be modified 
+   * afterwards. This filed is purely informative and it is not used by any operation.
+   */ 
+  int port;
+  /**
+   * \brief identifier of the disconnect event.
+   *
+   * This events notifies the server side application that the connection to the
+   * client has been closed. This event is not the same as the connection closed
+   * event provided by the CSocket class. This event is used internally by the
+   * server, which activates this one when the disconnection is detected.
+   */ 
+  std::string disconnect_event_id;
+  /**
+   * \brief identifier of the reception event
+   *  
+   * This event notifies the reception of new data for the corresponding client.
+   * This event is the one provided by the CSocket base class and it is provided
+   * here because there is no direct access to the CSocket object from outside
+   * the class.
+   */ 
+  std::string rx_event_id;
+}TClient_info;
+
+/**
+ * \brief Internal client information
+ *
+ * This structure hold information of the client necessary for the server to
+ * manage the connection. This structure is only used internally by the server
+ * and can not be accessed from outside the class.
+ */
+typedef struct
+{
+  /**
+   * \brief client identifier 
+   *
+   * This ideintifier is automatically assigned by the server when the connection is
+   * stablished. This identifier is unique for each connection and it is used to 
+   * identify the client to which send or receive information. 
+   */ 
+  std::string client_id;
+  /**
+   * \brief identifier of the disconnect event.
+   *
+   * This events notifies the server side application that the connection to the
+   * client has been closed. This event is not the same as the connection closed
+   * event provided by the CSocket class. This event is used internally by the
+   * server, which activates this one when the disconnection is detected.
+   */ 
+  std::string disconnect_event_id;
+  /**
+   * \brief communication soket
+   *
+   * This field points to the CSocket object used to communicate with the client.
+   * This object can only be accessed internally by the class, and the server
+   * side application must use the unique identifier assigned to it in order to
+   * access it throw the public interface of the server.
+   *
+   * This object is created and initialized automatically when the connection is
+   * stablished, and it is only closed and freed when the free_client() function
+   * is called.
+   */ 
+  CSocket *socket;
+}TClient_info_int;
+
+/**
+ * \brief Server side socket
+ *
+ * This class implemnt the server side of a TCP/IP socket communication. It 
+ * inherits from the CSocket class for the basic socket communication issues and
+ * adds the necessary resources to provide connections to several clients 
+ * simultaneously.
+ *
+ * After creation, it is necessary to call the open() function with the IP address
+ * and the desired listining port of the server socket. Then, the config() function
+ * is provided with the number of connections that can be buffered waiting for
+ * a connection. 
+ *
+ * At this point the server is properly configured, but it will not accept new 
+ * connections until it is started by calling the start() function. After these 
+ * steps, the server socket is ready to accept connections and send and receive data 
+ * to and from them. The server can be stoped at any time calling the stop() function
+ * and restarted. When the server is stopped, all connections are lost.
+ *
+ * This class provides an event (which can be retrieved with the get_new_connection_event()
+ * function) which is activated each time a new client is connected to the server.
+ * At this point, a server side application can get all the new client information
+ * using the get_new_client() function.
+ *
+ * This information includes the unique identifier of the socket used to send
+ * and receive information because the CSocket object itself is not accessible
+ * from outisde the class. It also includes the identifier of an event which is
+ * activated when the connection is closed by the client side (disconnect_event_id).
+ *
+ * When a connection is closed, most of the associated resources in the server
+ * side are freed, but it is imperative to call the free_client() function in
+ * order to properly free all the resources and avoid memory leaks. This function
+ * should only be called after the connection is closed. calling it before, will
+ * terminate the connection from the server side.
+ *
+ * When the maximum number of connections are reached, the server does not accept
+ * any more until one of the existing connections is closed.
+ *
+ */
+class CSocketServer : public CSocket
+{
+  private:
+    /**
+     * \brief current state of the server
+     *
+     * This attribute keeps the current state of the server. By default it is 
+     * initialized to server_created, and its value automarically changes when
+     * the server is opend, configured and started. See the server_state 
+     * ennumeration documentation for more information about the possible states
+     * of the server and the state transitions.
+     */
+    server_state state;
+    /**
+     * \brief maximum number of simultaneous clients
+     *
+     * This integer has the maximum number of connections allowed for the server.
+     * By default its value is set to 1, but it can be changed at any time using
+     * the set_max_clients() function. The maximum number of clients can be 
+     * retrieved at nay time with the get_max_clients() function.
+     */
+    int max_clients;
+    /**
+     * \brief number of clients currently connected
+     *
+     * This integer has the current number of clients connected to the server. By
+     * default it is initialized to 0, and its value is automatically updated when
+     * new connections are created or existing connections are closed. The current
+     * number of connections can be retrieved with the set_num_current_connections()
+     * function.
+     */
+    int current_clients;
+    /**
+     * \brief connection counter
+     *
+     * This static integer is used to assign a unique identifier to each new 
+     * connection. This attribute is shared by all servers and it is incremented
+     * each time a new connection is set up in any of them, but it is never 
+     * decremented. This value is only used internally, and can not be modified 
+     * or accessed from outisde the class.
+     */
+    static int counter;
+    /**
+     * \brief list of clients connected
+     *
+     * This list holds the internal information required by the server to manage 
+     * each of the connections. By default the list is empty, and it is automatically
+     * updated each time a new connections is created or an existing connection
+     * is closed. This list is only used internally and can not be modified or 
+     * accessed from outside class.
+     *
+     * See the documentation on the TClient_info_int data type for more
+     * information about the elements fo this list.
+     */
+    std::list<TClient_info_int *> client_list;
+    /**
+     * \brief mutex object to access the server
+     *
+     * This object is used to avoid simultaneous access to the shared resources
+     * of the server (list of clients) from multiple threads (connection and 
+     * disconnection threads and the main thread). This object is initialized at 
+     * construction time and used internally in most of the functions.
+     */
+    CMutex server_access;
+    /**
+     * \brief identifier of the connection thread
+     *
+     * This string holds the unique identifier of the connection thread. This 
+     * identifier is created at contruction time attaching "_connect_thread" to 
+     * the identifier assigned to the server. This identifier can not be modified 
+     * or accessed outside the class.
+     */
+    std::string connect_thread_id;
+    /**
+     * \brief identifier of the disconnection thread
+     *
+     * This string holds the unique identifier of the disconnection thread. This 
+     * identifier is created at contruction time attaching "_disconnect_thread" to 
+     * the identifier assigned to the server. This identifier can not be modified 
+     * or accessed outside the class.
+     */
+    std::string disconnect_thread_id;
+    /**
+     * \brief identifier of the new connection event
+     *
+     * This string holds the identifier of the new connection event. This identifier
+     * is created at construction time attaching "new_connection_event" to the
+     * identifier assigned to the server. This identifier can not be modified outside 
+     * the class, but it can be retrieved with the get_new_connection_event_id()
+     * function to wait for new connections outside the class.
+     */
+    std::string new_connection_event_id;
+    /**
+     * \brief identifier of the update list event
+     *
+     * This string holds the identifier of the update list event. This identifier
+     * is created at construction time attaching "update_list_event" to the
+     * identifier assigned to the server. This event is only used inside the class
+     * and can not be accessed or modified outside it.
+     */
+    std::string update_list_event_id;
+    /**
+     * \brief identifier of the event to terminate the connect thread
+     *
+     * This event is used to signal the thread that is waiting for new connections
+     * to terminate its operation. This thread periodically checks the state of this
+     * event.
+     *
+     * This event is created when the server is created, but it is only activated 
+     * when the stop_server() function is called or the object is destroyed. This
+     * event is for internal use only, and can not be accessed outside the class.
+     */
+    std::string finish_connect_thread_event_id;
+    /**
+     * \brief identifier of the event to terminate the disconnect thread
+     *
+     * This event is used to signal the thread that is waiting for disconnections
+     * to terminate its operation. This thread periodically checks the state of this
+     * event.
+     *
+     * This event is created when the server is created, but it is only activated 
+     * when the stop_server() function is called or the object is destroyed. This
+     * event is for internal use only, and can not be accessed outside the class.
+     */
+    std::string finish_disconnect_thread_event_id;
+    /** 
+     * \brief queue of clients waiting to be retrieved
+     *
+     * This queue temporary holds the information of the new connections stablished
+     * to the server. This queue is empty by default and it is filled each time a new
+     * connection is created. The queue is emptied by calling the get_new_client()
+     * function when the new_connection_event_id event is activated, which returns 
+     * the necessary information to handle the connection to the server side 
+     * application. This queue can not be modified or accessed outside the class.
+     *
+     * This event can be activated several times if multiple connections are created
+     * without being acknowledge by the server side application.
+     */
+    std::queue<TClient_info *> new_clients;
+  protected:
+    /**
+     * \brief server connection IP address and port
+     *
+     * This strcture has the IP address and listening port of the server. By default
+     * the IP address uis empty and the port is set to -1. When the open() function is
+     * called successfully, this values are updated to the values provided to the
+     * function. 
+     *
+     * These values can not be directly modified nor accessed outside the class.
+     */
+    TSocket_info info;
+    /**
+     * \brief connection thread function
+     *
+     * This is the main function for the connection thread. This thread is waiting 
+     * for new connections continuously. When a new connection is created, it first
+     * created a new CSocket object associated to the new socket file descriptor
+     * to handle all the communication issues and generates both the internal 
+     * (TClient_info_int) and external (TClient_info) structures with all the 
+     * necessary information.
+     *
+     * The CSocket object can only be accessed from inside the class, and the
+     * server side application must use the client identifier provided by the
+     * get_new_client() function to access it. 
+     *
+     * After that, the new_connection event is activated to signal the server side
+     * application that a new connection is ready. If several connections are 
+     * created without being acknowledge by the server side application, this event
+     * remains active until all the new client information is retrieved.
+     *
+     * This thread does not throw any exception.
+     *
+     * \param param a pointer to the CSocketServer object to which the thread is
+     *              associated. This parameter is used to access the internal
+     *              attriobutes and functions of the class since the thread itself
+     *              is defined as static.
+     */
+    static void *connect_thread(void *param);
+    /**
+     * \brief disconnection thread function
+     *
+     * This is the main function of the disconnection thread. This thread waits 
+     * for the connection closed event of each of the active connections. When
+     * one or more of these events are activated, it frees most of the internal 
+     * resources associated with the connection and activates the corresponding
+     * disconnect event to signal the server side application that the
+     * connection is no longer available.
+     *
+     * It is the server side application the one responsible of freeing the rest
+     * of the resources associated with the closed connection by calling the
+     * free_client() function when the disconnect event is activated.
+     *
+     * If there are no active connections, this thread is inactive. As new 
+     * connections are created, this thread periodically updates the wait event 
+     * list to match the current active connections.
+     *
+     * This thread does not throw any exception.
+     *
+     * \param param a pointer to the CSocketServer object to which the thread is
+     *              associated. This parameter is used to access the internal
+     *              attriobutes and functions of the class since the thread itself
+     *              is defined as static.
+     */
+    static void *disconnect_thread(void *param);
+    /**
+     * \brief function to bind the desired IP address and port to the socket
+     *
+     * This function is automatically called when the base class open() function
+     * is called. This function binds the server socket to the desired IP
+     * address and port provided to the function. The IP address must coincide
+     * with the IP address assigned to the computer where the server is being
+     * executed, and the port can not be used by nay other application.
+     *
+     * If successful, the internal state of the server is changed to server_binded.
+     * After calling this function, it is necesary to call the config() function
+     * to properly configure the server.
+     *
+     * \param comm_dev a pointer to a valid TSocket_info strcture with the server
+     *                 IP address and desired listening port. See the documentation
+     *                 on the TSocket_info structure for more information on the
+     *                 IP address and port format.
+     */
+    virtual void hard_open(void *comm_dev=NULL);
+    /**
+     * \brief function to configure the length of the connection buffer
+     *
+     * This function is automatically called when the base class config() function
+     * is called. This function sets the maximum number of waiting connections 
+     * that are allowed. 
+     *
+     * If successfull, the internal state of the server is changed to server_listening.
+     * After calling this function, the server is properly configured, but it is still
+     * not ready to accept new connections or send and receive data. To do that, it
+     * is necessary to call the start() function.
+     *
+     * \param config a pointer to an integer value with the number of waiting
+     *               connections allowed. This value must be a positive integer.
+     */
+    virtual void hard_config(void *config=NULL);
+    /**
+     * \brief function to wait for communication events
+     *
+     * This function is only provided for compatibility since the server socket never 
+     * receives data from a client (a new socket is created for that purpose). However, 
+     * changes in the state of the socket may generate unexpected errors that the 
+     * CSocket hard_wait_comm_event() function can not handle.
+     *
+     * Therefore, this function overrides the base class function and block the thread
+     * indefinetely. When the server is destroyed, the thread is killed and this 
+     * function is aborted.
+     *
+     * \return this function will block and never return any value. 
+     */
+    virtual int hard_wait_comm_event(void);
+    /**
+     * \brief function to close the server
+     *
+     * This function will first stop the server and also close any connection with a 
+     * client which is still active, freeing all the associated resources. If 
+     * successfull this function changes the state of the server to server_created.
+     *
+     * If this function is called, in order to set up the server again, it will be
+     * necessary to call the open() and config() functions to reconfigure it and also
+     * the start() function to accept and handle new connections.
+     */
+    virtual void hard_close(void);
+  public:
+    /**
+     * \brief constructor
+     *
+     * This constructor created the connect and disconnect threads and attach them
+     * to the corresponding functions, but does not start any of them. It also
+     * creates the new connection event. The socket identifier is used to initialize
+     * the identifier for both threads and events, and each server must have a 
+     * different one.
+     *
+     * In this function all the internal attributes are initialized by default.
+     *
+     * \param sock_id a null terminated string with the identifier of the server.
+     *                This string must not have any white spaces and each server
+     *                must have a different one, since it is used to generate the
+     *                unique identifier for both threads and events.
+     */
+    CSocketServer(const std::string &sock_id);
+    /**
+     * \brief function to set the maximum number of simultaneous clients
+     *
+     * This function sets the maximum number of clients connected any given time.
+     * This function can be called any time, but if the new maximum value is 
+     * smaller than the current number of connections, this function will throw
+     * a CSocket exception instead of closing the exceeding connections.
+     *
+     * If the new value is bigger than the previous one, there is no problem.
+     * However, it is better to set this value before calling the start()
+     * function and, if it is necessary to change the maximum number of clients
+     * connected, first stop the server and then change it.
+     *
+     * \param max_clients a positive integer with the maximum number of clients
+     *                    connected any given time. 
+     */
+    void set_max_clients(int max_clients);
+    /**
+     * \brief function to get the maximum number of simultaneous clients
+     *   
+     * This function return the maximum number of clients that can be connected 
+     * to the server at any given time. 
+     *
+     * \return a positive integer with the maximum number of clients connected
+     *         to the server any given time.
+     */
+    int get_max_clients(void);
+    /**
+     * \brief function to get the number of clients currently connected
+     *
+     * This returns the number of clients currently connected to the server. This
+     * number is always between 0 and the maximum number of clients allowed. 
+     *
+     * \return a non-negative integer with the number of clients currently
+     *         connected to the server.
+     */
+    int get_num_current_clients(void);
+    /**
+     * \brief function to start the server
+     *
+     * This function starts the internal threads which allow the server to detect 
+     * new connections. Before calling this function, the server will not be able 
+     * to accept any new connections. If successfull this function changes the state
+     * of the server to server_on.
+     *
+     * After calling this function, the server side application should wait for the
+     * activation of the new connection event. Once activated, the new client
+     * information can be retrieved by calling the get_new_client() function. 
+     *
+     * At this point, the receive event and the disconnet event should be monitored to
+     * detect the reception of new data or the disconnection of the client, whatever
+     * happens first. If new data is received, the get_num_data_from() and read_from()
+     * functions can be used to get it. If the connection has been closed, the 
+     * free_client() function should be called to free all the associated resources.
+     *
+     * If successfull, this function changes the state of the server to server_on.
+     * This function throws a CSocketException in case of any error.
+     */
+    void start_server(void);
+    /**
+     * \brief function to stop the server
+     *
+     * This function stops the normal operation of the server. It closes any active
+     * connection that may still exists and frees all the associated resources. In 
+     * this case, however, the server does not loose its configuration, so in order
+     * to start accepting connections again, it is only necessary to call the 
+     * start() function.
+     *
+     * If successfull, this function changes the state of the server to 
+     * server_listening. This function throws a CSocketException in case of any 
+     * error;
+     */
+    void stop_server(void);
+    /**
+     * \brief function to send some data to all clients
+     *
+     * This function is used to send any data to all the active connections on the
+     * server. In this case no client identifier is provided because the data is
+     * sequentially sent to all available clients.
+     *
+     * This function throws a CSocketException in case of any error.
+     *
+     * \param data a pointer to an unsigned char vector with the information to
+     *             send. The memory for this parameter must be allocated before
+     *             calling this function, and its length must coincide with the
+     *             value of the second parameter.
+     *
+     * \param len a positive integer with the length of the data to be sent. This
+     *            value must coincide with the actual length of the vector passed
+     *            as first argument.
+     */
+    void broadcast(unsigned char *data, const int len);
+    /**
+     * \brief function to send data to a single client
+     *
+     * This function is used to send data to a single client. It uses the client
+     * identifier returned by the get_new_client() function to identify the
+     * desired client connection. If the specified client does not exist, this
+     * function throws a CSocketException.
+     *
+     * \param sock_id the identifier of the desired client. This value must be
+     *                one of the identifier returned by the get_new_client()
+     *                function which is still active.
+     *
+     * \param data a pointer to an unsigned char vector with the information to
+     *             send. The memory for this parameter must be allocated before
+     *             calling this function, and its length must coincide with the
+     *             value of the third parameter.
+     *
+     * \param len a positive integer with the length of the data to be sent. This
+     *            value must coincide with the actual length of the vector passed
+     *            as second argument.
+     *
+     * \return the number of bytes actually written to the client. In a standard 
+     *         case, this value should be equal to the value of the third parameter,
+     *         otherwise, and error has ocurred.
+     */
+    int write_to(const std::string &sock_id, unsigned char *data, const int len);
+    /**
+     * \brief function to get data from a single client
+     *
+     * This function is used to get data from a single client. It uses the client
+     * identifier returned by the get_new_client() function to identify the 
+     * desired client connection. If the specified client does not exist, this
+     * function throws a CSocketException.
+     *
+     * \param sock_id the identifier of the desired client. This value must be
+     *                one of the identifier returned by the get_new_client()
+     *                function which is still active.
+     *
+     * \param data a pointer to an unsigned char vector where the information 
+     *             received is stored. The memory for this parameter must be 
+     *             allocated before calling this function, and its length must 
+     *             coincide with the value of the third parameter.
+     *
+     * \param len a positive integer with the length of the data to be read. This
+     *            value must coincide with the actual length of the vector passed
+     *            as second argument. The get_num_data_from() function can be 
+     *            used to know how many data is available at any time.
+     *
+     * \return the number of bytes actually read from the client. In a standard 
+     *         case, this value should be equal to the value of the third parameter,
+     *         otherwise, and error has ocurred.
+     */
+    int read_from(const std::string &sock_id, unsigned char *data, const int len);
+    /**
+     * \brief function to get the number of available data from a single client
+     *
+     * This function is used to get the ammount of data available from a single 
+     * client. It uses the client identifier returned by the get_new_client() 
+     * function to identify the desired client connection. If the specified 
+     * client does not exist, this function throws a CSocketException.
+     *
+     * \param sock_id the identifier of the desired client. This value must be
+     *                one of the identifier returned by the get_new_client()
+     *                function which is still active.
+     *
+     * \return the number of bytes currently available at the desired client. This
+     *         value can be used as the third parameter to the read_from()
+     *         function.
+     */
+    int get_num_data_from(const std::string &sock_id);
+    /**
+     * \brief function to get the identifier of the new connection event
+     *
+     * This function return the identifier of the new connection event. This
+     * event can be used to wait for new connections once the server has been
+     * started with the start() function. There exist a single event for each 
+     * server that is activated as many times as new clients are pending to be
+     * retrieved.
+     *
+     * After this event is active, the server side application should call the
+     * get_new_client() function in order ro get all the necessary information
+     * to handle the new connection. 
+     *
+     * \return a string with a copy of the new connection event identifier. 
+     */
+    std::string get_new_connection_event_id(void);
+    /**
+     * \brief function to get the information about the new connection
+     *
+     * This function is used to get all the important information about a new
+     * connection. See the documentation on the TClient_info structure for more
+     * information about the parameters returned by this function. 
+     *
+     * This function should be called as long as the new connection event is 
+     * active, which means that there is a new client connected and waiting.
+     *
+     * \return a pointer to an structure with information about the new 
+     *         connection. The memory necessary for this structure is allocated
+     *         in this function, and it is necessary to call the free_client()
+     *         function to properly free it and all its associated resources.
+     */
+    TClient_info *get_new_client(void);
+    /**
+     * \brief function to free the resources associated with a client
+     *
+     * This function is used to properly free all the resources associated with a
+     * connection once is has been closed. This function should only be called 
+     * after the disconnect event for the corresponding connection has been
+     * activated. Otherwise, the connection will be closed and the client will be
+     * disconnected.
+     *
+     * This function actually closes the socket accociated to the connection and 
+     * destroys it, and also destroys all the events associated with it. Finally, 
+     * it also, frees the information structure passed as an argument so the
+     * server side of the application does not have to do that.
+     *
+     * \param info a pointer to a valid TClient_info structure which corresponds 
+     *             to an active connection. This structure should be the one
+     *             returned by the get_new_client() function.
+     */
+    void free_client(TClient_info *info);
+    /**
+     * \brief destructor
+     *
+     * This destructor first stops the server, if it is running, and closes all 
+     * the active connections with clients. This destructor does not free all the
+     * resources associated with each connection, so its better to first close all
+     * the connections using the free_client() function and then destroy the 
+     * server object.
+     */
+    virtual ~CSocketServer();
+};
+
+#endif
diff --git a/src/usb_ftdi/ftdiexceptions.cpp b/src/usb_ftdi/ftdiexceptions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e12766c164de6565efb57330b916b5b13efa0246
--- /dev/null
+++ b/src/usb_ftdi/ftdiexceptions.cpp
@@ -0,0 +1,37 @@
+#include "ftdiexceptions.h"
+#include <string.h>
+#include <stdio.h>
+
+const std::string ftdi_exception_msg="[CFTDI class] - ";
+const std::string ftdiserver_exception_msg="[CFTDIServer class] - ";
+
+const std::string error_messages[]={"ok.\n",
+                                    "Invalid handle.\n",
+                                    "Device not found.\n", 
+                                    "Device not opened.\n",
+                                    "Input/output error.\n",
+                                    "Insufficient resources.\n",
+                                    "Invalid parameter.\n",
+                                    "Invalid baudrate.\n",
+                                    "Device not opened for erase.\n",
+                                    "Device not opened for write.\n",
+                                    "Failed to write device.\n",
+                                    "EEPROM read failed.\n",
+                                    "EEPROM write failed.\n",
+                                    "EEPROM erase failed.\n",
+                                    "EEPROM not present.\n",
+                                    "EEPROM not programmes.\n"
+                                    "Invalid arguments.\n",
+                                    "Not supported.\n",
+                                    "Unknown error.\n"};
+
+CFTDIException::CFTDIException(const std::string& where,const std::string& error_msg,const std::string& comm_id) : CCommException(where,ftdi_exception_msg,error_msg)
+{
+  this->error_msg+=" - ";
+  this->error_msg+=comm_id;
+}
+
+CFTDIServerException::CFTDIServerException(const std::string& where,const std::string& error_msg) : CException(where,ftdi_exception_msg)
+{
+  this->error_msg+=error_msg;
+}
diff --git a/src/usb_ftdi/ftdiexceptions.h b/src/usb_ftdi/ftdiexceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..53387f0c71ac89ce01a6893d1ec66ea49e0a473a
--- /dev/null
+++ b/src/usb_ftdi/ftdiexceptions.h
@@ -0,0 +1,116 @@
+#ifndef FTDI_EXCEPTIONS
+#define FTDI_EXCEPTIONS
+
+#include "commexceptions.h"
+#include "ftd2xx.h"
+#include <string>
+
+/**
+ * \brief vector with all the error messages
+ *
+ * This constant vector has the strings corresponding to all possible errors
+ * of any FTDI device. The value of the error can be used to index the table
+ * and get the corresponding string.
+ */
+extern const std::string error_messages[];
+
+/**
+ * \brief FTDI exception class
+ *
+ * This class implements the exceptions for the FTDI communication class. 
+ * In addition to the basic error message provided by the base class CException, 
+ * this exception class provides also the unique identifier of the communication
+ * device that generated the exception.
+ *
+ * Also, similarly to other exception classes, it appends a class identifer
+ * string ("[CFTDI class] - ") to the error message in order to identify 
+ * the class that generated the exception.
+ *
+ * The base class can be used to catch any exception thrown by the application
+ * or also, this class can be used in order to catch only exceptions generated 
+ * by CFTDI objects.
+ *
+ */
+class CFTDIException : public CCommException
+{
+  public:
+    /**
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CFTDI class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device 
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * Error: [CComm class] - [CFTDI class] - <error message> - <comm id>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     * \param comm_id a null terminated string that contains the communication
+     *                device unique identifier. This string must be the one used to 
+     *                create the object.
+     *
+     *
+     */  
+    CFTDIException(const std::string& where,const std::string& error_msg,const std::string& comm_id);
+};
+
+/**
+ * \brief FTDIServer exception class
+ *
+ * This class implements the exceptions for the FTDI Server class. 
+ * Similarly to other exception classes, it appends a class identifer
+ * string ("[CFTDIServer class] - ") to the error message in order to identify 
+ * the class that generated the exception.
+ *
+ * The base class can be used to catch any exception thrown by the application
+ * or also, this class can be used in order to catch only exceptions generated 
+ * by CFTDIServer objects.
+ *
+ */
+class CFTDIServerException : public CException
+{
+  public:
+    /**
+     * \brief Constructor
+     *
+     * The constructor calls the base class constructor to add the general
+     * exception identifier and then adds the class identifier string 
+     * "[CFTDIServer class]" and the supplied error message. 
+     *
+     * It also appends the unique identifier of the communication device 
+     * that generated the exception. So, the total exception message will 
+     * look like this:
+     *
+     * \verbatim
+     * [Exception caught] - <where>
+     * [CComm class] - [CFTDIServer class] - <error message>
+     * \endverbatim
+     *
+     * \param where a null terminated string with the information about the name
+     *              of the function, the source code filename and the line where
+     *              the exception was generated. This string must be generated 
+     *              by the _HERE_ macro.
+     *
+     * \param error_msg a null terminated string that contains the error message.
+     *                  This string may have any valid character and there is no
+     *                  limit on its length.
+     *
+     */  
+    CFTDIServerException(const std::string& where,const std::string& error_msg);
+};
+
+#endif
diff --git a/src/usb_ftdi/ftdimodule.cpp b/src/usb_ftdi/ftdimodule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7520d5d0e0374e201f39e7dd58235a1cccfc1b2b
--- /dev/null
+++ b/src/usb_ftdi/ftdimodule.cpp
@@ -0,0 +1,210 @@
+
+#include "ftdimodule.h"
+#include "ftdiexceptions.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string>
+#include <iostream>
+
+CFTDI::CFTDI(const std::string& comm_id) : CComm(comm_id)
+{
+  this->ft_handle = NULL;		
+}
+	
+void CFTDI::hard_open(void* comm_dev)
+{
+  FT_STATUS ft_status;
+  std::string *serial_desc=(std::string *)comm_dev;
+
+  ft_status=FT_OpenEx((void *)serial_desc->c_str(),FT_OPEN_BY_SERIAL_NUMBER,&(this->ft_handle));
+  ft_status=FT_OpenEx((void *)serial_desc->c_str(),FT_OPEN_BY_DESCRIPTION,&(this->ft_handle));
+  if(this->ft_handle==NULL)
+  { 
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,"Impossible to open the device.\n",this->comm_id); 
+  }
+  if((ft_status=FT_ResetDevice(this->ft_handle))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id); 
+  }
+  if((ft_status=FT_Purge(this->ft_handle,FT_PURGE_RX|FT_PURGE_TX))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id); 
+  }
+  if((ft_status=FT_ResetDevice(this->ft_handle))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id); 
+  }
+  pthread_cond_init(&this->event_handle.eCondVar, NULL); 
+  pthread_mutex_init(&this->event_handle.eMutex, NULL); 		
+  pthread_mutex_lock(&this->event_handle.eMutex);
+
+  //Set condition event here, before thread is started
+  if((ft_status = FT_SetEventNotification(this->ft_handle,FT_EVENT_RXCHAR,(PVOID)&this->event_handle))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  }
+}
+
+void CFTDI::hard_config(void *config)
+{
+  FT_STATUS ft_status;
+  TFTDIconfig *ftdi_config = (TFTDIconfig*) config;		 
+
+  if(config==NULL)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,"Invalid configuration structure",this->comm_id);
+  }
+  //1. Set Baud Rate
+  if(ftdi_config->baud_rate!=-1)
+  {
+    if((ft_status=FT_SetBaudRate(this->ft_handle,ftdi_config->baud_rate))!=FT_OK)
+    {
+      /* handle exceptions */
+      throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+    }
+  }
+  //2. Set the data characteristics
+  if(ftdi_config->word_length!=-1 && ftdi_config->stop_bits!=-1 && ftdi_config->parity!=-1)
+  {
+    if((ft_status=FT_SetDataCharacteristics(this->ft_handle,ftdi_config->word_length,ftdi_config->stop_bits,ftdi_config->parity))!=FT_OK)
+    {
+      /* handle exceptions */
+      throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+    }
+  }
+  //3. set read and write timeouts
+  if((ft_status=FT_SetTimeouts(this->ft_handle,ftdi_config->read_timeout,ftdi_config->write_timeout))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  } 
+  //4. Set latency timer
+  if((ft_status=FT_SetLatencyTimer(this->ft_handle,ftdi_config->latency_timer))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  }
+  if((ft_status=FT_SetFlowControl(this->ft_handle,FT_FLOW_NONE,0x00,0x00))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  }
+}
+
+void CFTDI::hard_close(void)
+{
+  FT_STATUS ft_status;
+
+  if(this->ft_handle!=NULL)
+  {
+    if(pthread_mutex_trylock(&this->event_handle.eMutex)==EBUSY)
+      pthread_mutex_unlock(&this->event_handle.eMutex);
+    if((ft_status = FT_Close(this->ft_handle))!=FT_OK)
+    {
+      /* handle exceptions */
+      throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+    }
+    this->ft_handle = NULL; // assing no opened value
+  }
+}
+
+int CFTDI::hard_read(unsigned char *data, int len)
+{
+  FT_STATUS ft_status;
+  DWORD bytes_received;
+
+  if((ft_status = FT_Read(this->ft_handle,data,len,&bytes_received))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  }
+
+  return bytes_received;
+}
+
+int CFTDI::hard_write(unsigned char *data, int len)
+{
+  FT_STATUS ft_status;
+  DWORD bytes_written;
+
+  if((ft_status = FT_Write(this->ft_handle, data,len,&bytes_written))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+  }	
+  
+  return bytes_written;
+}
+
+int CFTDI::hard_get_num_data(void)
+{
+  FT_STATUS ft_status;
+  DWORD bytes_rx;	
+
+  if((ft_status=FT_GetQueueStatus(this->ft_handle,&bytes_rx))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);	
+  }
+ 
+  return bytes_rx;
+}
+
+int CFTDI::hard_wait_comm_event(void)
+{
+  FT_STATUS ft_status;
+  DWORD rx_bytes=0,tx_bytes=0,event_id=0;
+
+  while(rx_bytes < 1)
+  {
+    pthread_cond_wait(&event_handle.eCondVar, &event_handle.eMutex);		
+    if((ft_status = FT_GetStatus(this->ft_handle,&rx_bytes,&tx_bytes,&event_id))!=FT_OK)
+    {
+      /* handle exceptions */
+      throw CFTDIException(_HERE_,error_messages[ft_status],this->comm_id);
+    }
+  }
+  if(rx_bytes < 1) 			
+    return 2; // error	
+  else 		
+  {
+    return 1; // ready to read data	
+  }
+}
+
+std::ostream& operator<< (std::ostream& out,CFTDI& ftdi)
+{
+  FT_STATUS ft_status;
+  DWORD type;
+  DWORD id;
+  char serial_number[16];
+  char description[64];
+
+  out << "****************** FTDI Devices Info ***********************" << std::endl;
+  if((ft_status=FT_GetDeviceInfo(ftdi.ft_handle,&type,&id,serial_number,description,NULL))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIException(_HERE_,error_messages[ft_status],ftdi.comm_id);
+  } 
+  out << "Device name: " << ftdi.comm_id << std::endl;
+  out << "Type: " << type << std::endl;
+  out << "Device id: " << id << std::endl;
+  out << "Serial Number: " << serial_number << std::endl;
+  out << "Description: " << description << std::endl;
+
+  return out;
+}
+
+CFTDI::~CFTDI(){
+  this->close();
+}
+
+
diff --git a/src/usb_ftdi/ftdimodule.h b/src/usb_ftdi/ftdimodule.h
new file mode 100644
index 0000000000000000000000000000000000000000..720d56e9af021340c19672619198fbce57f45f88
--- /dev/null
+++ b/src/usb_ftdi/ftdimodule.h
@@ -0,0 +1,334 @@
+#ifndef _FTDI_MODULE_H
+#define _FTDI_MODULE_H
+
+#include <ostream>
+#include "ftd2xx.h"
+#include "comm.h"
+
+/**
+  \brief structure to hold the configuration parameters of the FTDI device
+
+  The necessary configuration parameters of the supported FTDI devices are:
+
+  - baud rate (only used on serial devices)
+  - number of bits per word (only used on serial devices)
+  - number of stop bits (only used on serial devices)
+  - parity type (only used on serial devices)
+  - read and write timeouts (used on all devices)
+  - latency timer (used on all devices)
+
+  These parameters must be configured after the device has been opened by
+  calling the open() function and before reading or writing data from or to
+  the device.
+ 
+*/
+typedef struct TFTDIconfig 
+{
+  /**
+   * \brief desired baud rate
+   *
+   * This parameter specifies the desired baud rate in bits per second of the
+   * device. This parameter only has meaning when the FTDI device is of the
+   * serial kind. Otherwise it is not used and it can be set to -1 to avoid 
+   * its initialization on the driver.
+   *
+   * The possible values for this parameter are:
+   *
+   * - 300
+   * - 600
+   * - 1200
+   * - 2400
+   * - 4800
+   * - 9600
+   * - 14400
+   * - 19200
+   * - 38400
+   * - 57600
+   * - 115200
+   * - 230400
+   * - 460800
+   * - 921600
+   *
+   */ 
+  int baud_rate; 
+  /**
+   * \brief desired word length
+   *
+   * This parameter specifies the desired length of each packet in bits. This
+   * parameter only has meaning when the FTDI device is of the serial kind.
+   * Otherwise it is not used and it can be set to -1 to avoid its initialization
+   * on the driver.
+   *
+   * The possible values for this parameter are integers from 5 to 8.
+   */ 
+  int word_length;
+  /**
+   * \brief desired number of stop bits
+   *
+   * This parameter specifies the desired number of stop bits of each packet. This
+   * parameter only has meaning when the FTDI device is of the serial kind.
+   * Otherwise it is not used and it can be set to -1 to avoid its initialization
+   * on the driver.
+   *
+   * The possible values for this parameter are:
+   *
+   * - 0 for 1 stop bits
+   * - 1 for 1.5 stop bits
+   * - 2 for 2 stop bits
+   */ 
+  int stop_bits;
+  /**
+   * \brief desired parity type
+   *
+   * This parameter specifies the desired kind of parity to be used. This parameter
+   * only has meaning when the FTDI device is of the serial kind. Otherwise it is 
+   * not used and it can be set to -1 to avoid its initialization on the driver.
+   *
+   * The possible values for this parameter are:
+   *
+   * - 0 for no parity
+   * - 1 for odd parity
+   * - 2 for even parity
+   * - 3 for mark parity
+   * - 4 for space parity 
+   */  
+  int parity;
+  /**
+   * \brief desired timeout for read operations
+   *
+   * This parameter specifies the maximum time to wait for a read operation to end in
+   * miliseconds. 
+   */  
+  int read_timeout;
+  /**
+   * \brief desired timeout for write operations
+   *
+   * This parameter specifies the maximum time to wait for a write operation to end in
+   * miliseconds. 
+   */  
+  int write_timeout;
+  /**
+   * \brief rate at which the receive buffer is flushed
+   *
+   * This parameter specifies the period in miliseconds at which the receive buffer is 
+   * flushed. This value can be set to any value between 2 and 255.
+   */
+  unsigned char latency_timer;
+}TFTDIconfig;
+
+/**
+ * \brief FTDI driver class using the D2XX library
+ *
+ * This class implements the access to any FTDI device supported by the D2XX driver
+ * provided by the manufacturer. This class inherits from the CComm class to have 
+ * all the basic communications issues solved and it only has to implement the
+ * specific functions to open the FTDI device (hatd_open()), config (hard_config()),
+ * read from (hard_read()), write to (hard_write()) and close it (hard_close()).
+ * Also it implements a function to assynchronously wait for communication events
+ * to happen (hard_wait_comm_event()). 
+ *
+ * This class allows access to any external device that uses one of the supported
+ * FTDI chips. The supported FTDI devices are:
+ *
+ * - FT2232H
+ * - FT4232H
+ * - FT232R
+ * - FT245R
+ * - FT2232
+ * - FT232B
+ * - FT245B
+ * - FT8U232AM
+ * - FT8U245AM
+ *
+ * This driver must be used when the used VID and PID values do not coincide with 
+ * the dafualt values used by the manufacturer. Otherwise, it is possible to use
+ * a standard serial port driver (CRS232) to access the device. However, this 
+ * driver provides faster transfer rates to and from the device than the virtual
+ * COM port option.
+ *
+ * This class uses exceptions to report errors. The name of the exception 
+ * class associated to this class is CFTDIException. For a more detailes
+ * descritpion, see the corresponding documentation.
+ * 
+ */
+class CFTDI : public CComm 
+{
+  private:
+    /**
+     * \brief Handle to the FTDI device
+     *
+     * This handle is used to access the associated FTDI device. By default it is set
+     * to NULL when the object is created, and it is initialized when the device is 
+     * opened by calling the open() function. This handle remains valid until the object
+     * is destroyed or the FTDI device is disconnected
+     */ 
+    FT_HANDLE ft_handle; 
+
+    EVENT_HANDLE event_handle;
+  protected:
+    /**
+     * \brief Function to actually open the device
+     *
+     * This function is called automatically when the base class open() function
+     * is called. It must create a handle to the communication device in order to 
+     * be used in the future. The device handle must be provided by any inherited 
+     * class since it is device dependant.
+     *
+     * This class accepts a generic parameter (void *) to allow the user to pass 
+     * to the function any data structure. This parameter comes from the base
+     * class open() function, but no action is performed on it.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \param comm_dev a generic pointer (void *) to the data structure needed to
+     *                 identify the communication device to open and any other
+     *                 required information. This parameter may be NULL if not
+     *                 needed.
+     */ 
+    void hard_open(void* comm_dev);
+    /**
+     * \brief Function to actually configure the device
+     * 
+     * This function is called automatically when the base class config() function
+     * is called. It must configure the communication device as required by the 
+     * application.
+     *
+     * This class accepts a generic parameter (void *) to allow the user to pass 
+     * to the function any data structure. This parameter comes from the base
+     * class open() function, but no action is performed on it.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \param config a generic pointer (void *) to the data structure needed to
+     *               configure the communicationd device. This parameter may be
+     *               NULL if not needed.
+     */ 
+    void hard_config(void *config);
+    /**
+     * \brief Function to actually read from the device
+     *
+     * This function is automatically called when the new data received is activated.
+     * The read() function from the base class gets data from the internal queue, so
+     * this function is not used. It must try to read the ammount of data specified 
+     * and store it in the data buffer provided without blocking. Also, it must 
+     * return the number of bytes actually read from the devicve, since they may be
+     * different than the desired value.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     *  \param data a reference to the buffer where the received data must be 
+     *  copied. The necessary memory for this buffer must be allocated before 
+     *  calling this function and have enough size to store all the desired data.
+     *  If this buffer is not initialized, the function throws an exception.
+     *
+     *  \param len a positive interger that indicates the number of byte to be
+     *  read from the communication device. This value must be at most the length 
+     *  of the data buffer provided to the function.
+     *
+     *  \return an integer with the number of bytes actually read. These number 
+     *  coincide with the desired number if there is enough data in the internal 
+     *  queue, but it could be smaller if not.
+     */ 
+    int hard_read(unsigned char *data, int len);
+    /**
+     * \brief Function to actually write to the device
+     *
+     * This function is automatically called when the base class write() function
+     * is called. It must try to write the desired ammount of data to the communication 
+     * device without blocking. Also it must return the number of bytes actually
+     * written to the communication device since they may be different from the
+     * desired value.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     *  \param data a reference to the buffer with the data must be send to the 
+     *  device. The necessary memory for this buffer must be allocated before 
+     *  calling this function and have enough size to store all the desired data.
+     *  If this buffer is not initialized, the function throws an exception.
+     *
+     *  \param len a positive interger that indicates the number of byte to be
+     *  written to the communication device. This value must be at most the length 
+     *  of the data buffer provided to the function.
+     *
+     *  \return an integer with the number of bytes actually written. These number 
+     *  coincide with the desired number if there is enough data in the internal 
+     *  queue, but it could be smaller if not.
+     */ 
+    int hard_write(unsigned char *data, int len);
+    /**
+     * \brief Function to actually get the number of bytes availables
+     *
+     * This function is called when the new data received event is activated.
+     * It must get the number of data bytes available from the communication
+     * device and return its value without blocking.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \return an integer with the number of bytes available in the receive queue. 
+     * This value can be 0 if there is no data available, but there is ni upper
+     * limit in its value.
+     */ 
+    void hard_close(void);
+    /**
+     * \brief Function to actually wait for a given communication event
+     *
+     * This function is called in the internal communciation thread to wait for 
+     * any event on the communuication device. It must check for any event on the
+     * device (reception or error) and return the corresponding identifier. When 
+     * an event is activated, this function must return to allow the base class 
+     * to handle it, and the it is called again to wait for the next event.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     *
+     * \return -1 if there has been any error or else the identifier of the 
+     *         communciation event:
+     *
+     * - 1 for the new data received event
+     * - 2 for the error event
+     */ 
+    int hard_get_num_data(void);
+    /**
+     * \brief Function to actually close the device
+     *
+     * This function is called when the base class close() funciton is called. It
+     * must free the device handle initialized by the open() function and also free
+     * any other resource allocated by the inherited class.
+     *
+     * This function can throw any CCommException object exception or else any
+     * exception class defined by the inherited class.
+     */ 
+    int hard_wait_comm_event(void);
+  public:
+    /**
+     * \brief Constructor
+     *
+     * 
+     */ 
+    CFTDI(const std::string& comm_id);
+    /**
+     * \brief operator << overloading
+     *
+     * This operator allow to show important information about the FTDI device 
+     * associated to the class on any ostream obejct (the standard output, a file, 
+     * etc...).
+     *
+     * \param out A reference to an output device in which to show the desired 
+     *            information.
+     *
+     * \param ftdi A reference to a CFTDIServer object with the information to be
+     *               displayed.
+     *
+     * \return an object with the desired information already formatted. In this case
+     *         it has the number of devices and the information on each of them.
+     */
+    friend std::ostream& operator<< (std::ostream& out,CFTDI& ftdi);
+    ~CFTDI();
+};
+
+#endif
diff --git a/src/usb_ftdi/ftdiserver.cpp b/src/usb_ftdi/ftdiserver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a0c9acc81c7ca04372358d513be2d86ff2318cd4
--- /dev/null
+++ b/src/usb_ftdi/ftdiserver.cpp
@@ -0,0 +1,247 @@
+#include "ftdiexceptions.h"
+#include "ftdiserver.h"
+#include "ftd2xx.h"
+
+CFTDIServer *CFTDIServer::pinstance=NULL;
+
+CFTDIServer::CFTDIServer()
+{
+  this->scan_bus();
+}
+
+CFTDIServer::CFTDIServer(const CFTDIServer& object)
+{
+}
+
+CFTDIServer& CFTDIServer::operator = (const CFTDIServer& object)
+{
+  return *this->pinstance;
+}
+
+CFTDIServer *CFTDIServer::instance(void)
+{
+  if (CFTDIServer::pinstance == NULL)
+  {
+    CFTDIServer::pinstance = new CFTDIServer(); // Creamos la instancia
+  }
+  return CFTDIServer::pinstance; // Retornamos la dirección de la instancia
+}
+
+void CFTDIServer::add_custom_PID(int PID)
+{
+  FT_STATUS status;
+  int i=0;
+
+  for(i=0;i<this->custom_PID.size();i++)
+  {
+    if(this->custom_PID[i]==PID)
+      return;
+  }
+  this->custom_PID.push_back(PID);
+  if((status=FT_SetVIDPID(FTDI_VID,PID))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,error_messages[status]);
+  }
+  else
+  {
+    this->scan_bus();
+  }
+}
+
+void CFTDIServer::scan_bus(void)
+{
+  FT_DEVICE_LIST_INFO_NODE *dev;
+  TDevice_info dev_info;
+  DWORD num_devs=0;
+  FT_STATUS status;
+  int i=0;
+
+  if((status=FT_CreateDeviceInfoList(&num_devs))!=FT_OK)
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,error_messages[status]);
+  }
+  else
+  {
+    this->devices.clear();
+    if(num_devs>0)
+    {
+      dev=new FT_DEVICE_LIST_INFO_NODE[num_devs];
+      if((status=FT_GetDeviceInfoList(dev,&num_devs))!=FT_OK)
+      {
+        /* handle exceptions */
+        throw CFTDIServerException(_HERE_,error_messages[status]);
+      }
+      for(i=0;i<num_devs;i++)
+      {
+        if(dev[i].Flags&0x00000001)
+          dev_info.opened=true;
+        else
+          dev_info.opened=false;
+        if(dev[i].Flags&0x00000002)
+          dev_info.high_speed=true;
+        else
+          dev_info.high_speed=false;
+        dev_info.type=dev[i].Type;
+        dev_info.id=dev[i].ID;
+        dev_info.location=dev[i].LocId;
+        dev_info.serial_number=dev[i].SerialNumber;
+        dev_info.description=dev[i].Description;
+        this->devices.push_back(dev_info);
+      }
+    }
+  }
+}
+
+int CFTDIServer::get_num_devices(void)
+{
+  return this->devices.size();
+}
+
+std::vector<int> CFTDIServer::get_ids_by_description(const std::string& desc)
+{
+  std::string description;
+  std::vector<int> ids;
+  int num=0,i=0;
+
+  num=this->get_num_devices();
+  for(i=0;i<num;i++)
+  {
+    description=this->get_description(i);
+    if(description.find(desc)!=std::string::npos)
+      ids.push_back(i);
+  }
+
+  return ids;
+}
+
+bool CFTDIServer::is_opened(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].opened;
+}
+
+bool CFTDIServer::is_high_speed(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].high_speed;
+}
+
+unsigned long int CFTDIServer::get_type(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].type;
+}
+
+unsigned long int CFTDIServer::get_id(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].id;
+}
+
+unsigned long int CFTDIServer::get_location(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].location;
+}
+
+std::string& CFTDIServer::get_serial_number(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].serial_number;
+}
+
+std::string& CFTDIServer::get_description(int index)
+{
+  if(index<0 || index>this->devices.size())
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"There exist no USB device with the given index.\n");
+  }
+  else
+    return this->devices[index].description;
+}
+
+CFTDI *CFTDIServer::get_device(std::string& serial_desc)
+{
+  std::string dev_name;
+  CFTDI *ftdi_device;
+  int i=0;
+
+  if(serial_desc.size()==0)
+  {
+    /* handle exceptions */
+    throw CFTDIServerException(_HERE_,"Invalid serial number or description - empty string.\n");
+  }
+  else
+  {
+    for(i=0;i<this->devices.size();i++)
+    {
+      if(this->devices[i].serial_number==serial_desc || this->devices[i].description==serial_desc)
+      {
+        dev_name="FTDI_";
+        dev_name+=serial_desc;
+        ftdi_device=new CFTDI(dev_name);
+        ftdi_device->open((void *)&serial_desc);
+        return ftdi_device;
+      }
+    }
+  }
+}
+
+std::ostream& operator<< (std::ostream &out,CFTDIServer &server)
+{
+  int i=0;
+
+  out << "Number of FTDI devices detected: " << server.devices.size() << std::endl;
+  for(i=0;i<server.devices.size();i++)
+  { 
+    out << "Device " << i << std::endl;
+    if(server.devices[i].opened)
+      out << "The device is opened" << std::endl;
+    else
+      out << "The device is closed" << std::endl;
+    if(server.devices[i].high_speed)
+      out << "The device is high speed" << std::endl;
+    else
+      out << "The device is full speed" << std::endl;
+    out << "Type: " << server.devices[i].type << std::endl;
+    out << "Device id: " << server.devices[i].id << std::endl;
+    out << "Location: " << server.devices[i].location << std::endl;
+    out << "Serial number: " << server.devices[i].serial_number << std::endl;
+    out << "Description: " << server.devices[i].description << std::endl;
+  }
+
+  return out;
+}
diff --git a/src/usb_ftdi/ftdiserver.h b/src/usb_ftdi/ftdiserver.h
new file mode 100644
index 0000000000000000000000000000000000000000..0897388ffa7a178d203a8e5341d60478e8f7fdb1
--- /dev/null
+++ b/src/usb_ftdi/ftdiserver.h
@@ -0,0 +1,395 @@
+#ifndef _FTDI_SERVER
+#define _FTDI_SERVER
+
+#include <vector>
+#include <iostream>
+#include "ftdimodule.h"
+#include "mutex.h"
+
+const int FTDI_VID=0x0403;
+const int DEFAULT_FTDI_PID[]={0x6001,0x6010,0x6006};
+
+/**
+ * \brief structure with information about a device
+ *
+ * This structure holds information about one of the devices available on a system.
+ * This strcucture is first initialized when the device is first detected, and then
+ * it is stored in the internal device list.
+ */
+typedef struct
+{
+  /**
+   * \brief opened flag
+   *
+   * This flag indicates if the USB device is opened by the system or any other
+   * application. It will anly be possible to use devices that are not currently
+   * opened by any othe process. Trying to do so will throw an exception.
+   */ 
+  bool opened;
+  /**
+   * \brief High speed flag
+   *
+   * This flag indicates if the corresponding device supports the high speed 
+   * specification of the USB (true) or not (false).
+   */ 
+  bool high_speed;
+  /**
+   * \brief Type of the USB device
+   */  
+  unsigned long int type;
+  /**
+   * \brief USB device identification
+   */  
+  unsigned long int id;
+  /**
+   * \brief location of the device on the bus
+   */
+  unsigned long int location;
+  /**
+   * \brief Serial number of the device
+   */ 
+  std::string serial_number;
+  /**
+   * \brief Decription of the device
+   */  
+  std::string description;
+}TDevice_info;
+
+/**
+ * \brief Global event server
+ *
+ * This class implements an FTDI device server which is global to the application
+ * and also only one instance exist that is shared by all obects requiring 
+ * access to an FTDI device.
+ *
+ * Each FTDI device is identified by a VID and PID combination. At construction
+ * time this server searches the system for devices with the default VID and PID
+ * combinations provided by the manufacturer. If there exist devices with 
+ * different VID and PID combinations it is necessary to call the add_custom_PID()
+ * function, which rescans the system for available devices and adds them into
+ * the internal list.
+ *
+ * The get_num_devices() function can be used to retrieve the number of FTDI
+ * devices available on the system. To actually get one CFTDI class object to
+ * handle the desired device it is necessary to call the get_device() function,
+ * either providing the location of the desired device, the serial number or
+ * its description. It will be impossible to get an object of a device that it 
+ * is already in use by the system or any other application. 
+ *
+ * This class uses exceptions to report errors. The name of the exception 
+ * class associated to this class is CFTDIServerException. For a more detailes
+ * descritpion, see the corresponding documentation.
+ *
+ */
+class CFTDIServer
+{
+  private:
+    /**
+     * \brief Reference to the unique instance of this class
+     *
+     * This reference points to the unique instance of this class. By default 
+     * it is set to NULL, and it is initialized in the first call to the 
+     * instance() function. after that, successive calls to rhat function
+     * will return the pointer to the previously created object.
+     */ 
+    static CFTDIServer* pinstance;
+    /**
+     * \brief Information on all FTDI devices available
+     *
+     * This list have important information on all FTDI devices available on
+     * the system with one of the default or custom PID values. The information
+     * include:
+     *
+     * - Opened flag (as a boolean)
+     * - High speed flag (as a boolean) 
+     * - Device type (as an unsigned long int)
+     * - Device id (as an unisgned long int)
+     * - Device location (as an int)
+     * - Serial number (as a string)
+     * - Description (as a string)
+     *
+     * This list if first initialized at construction time with the devices
+     * presnt with the default PID values. When new PID values are added and
+     * FTDI devices with those PID values are present, the list is expanded
+     * wiht the information of the new devices.
+     *
+     */ 
+    std::vector<TDevice_info> devices;
+    /**
+     * \brief List of all custom PID values
+     *
+     * This list has all the PID added by the user. Initially it is empty,
+     * and it is updated any time the add_custom_PID() function is called.
+     */  
+    std::vector<int> custom_PID;
+  protected:
+    /**
+     * \brief Default constructor
+     *
+     * This constructor initializes the available FTDI devices list with the 
+     * default VID and PID combinations. This list can only be modified when
+     * a new PID is added and the sustem is rescaned for new devices.
+     *
+     * The reference to the newly created object is not modified. This constructor 
+     * is only called once and from inside the instance() function. It can not
+     * be called directly by the user since it is declared as protected.
+     *
+     */ 
+    CFTDIServer();
+    /** 
+     * \brief Copy constructor
+     *
+     * This constructor is used to initialize a new object with the contents of
+     * an existing one. Since there could be only one instance of this class,
+     * only the pinstance attribute must be copied, but since it is static
+     * nothing is to be done in this constructor.
+     *
+     * \param object an existing instance of a CFTDIServer class which has been
+     *               already initialized.
+     *
+     */ 
+    CFTDIServer(const CFTDIServer& object);
+    /**
+     * \brief assign operator overloading
+     *
+     * This function overloads the assign operator for this class. Since there 
+     * could be only one instance of this class, only the pinstance attribute 
+     * must be copied, but since it is static, nothing is to be done.
+     *
+     * \param object an existing instance of a CFTDIServer class which has been
+     *               already initialized.
+     */ 
+    CFTDIServer& operator = (const CFTDIServer& object);
+  public:
+    /**
+     * \brief Function to get a reference to the unique instance
+     *
+     * This function returns a reference to the only instance of the singleton.
+     * When it is first called, a new object of this class is created, and the
+     * successive calls only return a reference to the previously created
+     * object.
+     *
+     * Since this function is static, it can be call anywhere in the code so
+     * all objects can access the unique event handler. 
+     *
+     * \return A reference to the only instance of this class. This reference 
+     *         must not be freed until the application ends. 
+     *  
+     */ 
+    static CFTDIServer* instance(void);
+    /**
+     * \brief Function to add new PID values
+     *
+     * This function can be used to include new VID and PID combinations. By
+     * default the FTDI driver only recognises devices with the default PID
+     * values. Some manufacturers provide their own PID, so it is necessary to 
+     * include it using this function.
+     *
+     * When this function is called, the system is rescaned to find any available
+     * FTDI device with the provided PID. In case there is any, the internal 
+     * device list is expanded with the new information. If there is no device
+     * with the provided PID this function does nothing.
+     *
+     * This class uses exceptions to report errors. The name of the exception 
+     * class associated to this class is CFTDIServerException. For a more detailes
+     * descritpion, see the corresponding documentation.
+     *
+     * \param PID a positive value corresponding to the desired PID value. This
+     *            value must be the one provided by the manufacturer.
+     */ 
+    void add_custom_PID(int PID);
+    /**
+     * \brief function to scan the bus
+     * 
+     * This function can be used to scan the USB bus for FTDI devices. When it is
+     * called, it automatically updates all the internal information regarding any
+     * FTDI devices connected to the USB port of a computer. 
+     *
+     * This function is also called internally at contruction time and when a new
+     * PID is added. It can also be called by the user to update the local information
+     * when there are changes on the bus (a device has been connected or disconnected).
+     *
+     * This class uses exceptions to report errors. The name of the exception 
+     * class associated to this class is CFTDIServerException. For a more detailes
+     * descritpion, see the corresponding documentation.
+     */
+    void scan_bus(void);
+    /**
+     * \brief Function to get the number of available FTDI devices
+     *
+     * This function return to total number of FTDI devices present in the system
+     * with any of the default or custom PID values. Some of the devices may be
+     * used by the system or other applications. In this case, they can not be 
+     * accessed, but they are listed anyway.
+     *
+     * This class uses exceptions to report errors. The name of the exception 
+     * class associated to this class is CFTDIServerException. For a more detailes
+     * descritpion, see the corresponding documentation.
+     *
+     * \return The number of devices available on the system
+     */ 
+    int get_num_devices(void);
+    /**
+     * \brief Function to check if teh device is opened
+     *
+     * This function returna wether the device located at the given position of the
+     * internal list is opened or not.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     *
+     * \return a boolean that indicates if the device is opened (true) or not (false).
+     */ 
+    bool is_opened(int index);
+    /**
+     * \brief Function to check the maximum speed supported
+     *
+     * This function returns wether the device located at the given position of the
+     * internal list supports high speed modes or not.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     *
+     * \return a boolean that indicates if the device supports high speed modes (true)
+     *         or not (false).
+     */ 
+    bool is_high_speed(int index);
+    /**
+     * \brief Function to get the type of the device
+     *
+     * This function returns the type of the USB device located at the given position
+     * of the internal list.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     * 
+     * \return an integer which represents the type of the USB device.
+     */ 
+    unsigned long int get_type(int index);
+    /**
+     * \brief Function to get the identifiers of the devices with a given description
+     *
+     * This function returns a vector with the absolute indexes of all the FTDI 
+     * devices that matches a given description or that contain a given string in 
+     * their description. This function is usefull when trying to access devices
+     * of a given type.
+     *
+     * If no devices are present with the given description, an empty vector is
+     * returned
+     *
+     * \param desc a null terminated string with the whole desired description or
+     *             a subset of it. 
+     *
+     * \return a vector with the absolute indexes of all the devices matching 
+     *         the given description. If no devices are found, the returned 
+     *         vector is empty.
+     *
+     */
+    std::vector<int> get_ids_by_description(const std::string &desc);
+    /**
+     * \brief Function to get the device identifier
+     *
+     * This function returns the identifier of the USB device located at the given 
+     * position of the internal list.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     * 
+     * \return an integer which represents the identifier of the USB device.
+     *
+     */ 
+    unsigned long int get_id(int index);
+    /**
+     * \brief Function to get the location of the device on teh bus
+     *
+     * This function returns the location of the USB device on the USB bus, which is 
+     * located at the given position of the internal list.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     * 
+     * \return an integer which represents the location of the USB device on the bus.
+     */ 
+    unsigned long int get_location(int index);
+    /**
+     * \brief Function to get the serial number of the device
+     *
+     * This function return the serial number of the USB device located at the given 
+     * position of the internal list as a string.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     * 
+     * \return a string with the serial number of the USB device.
+     */
+    std::string& get_serial_number(int index);
+    /**
+     * \brief Function to get the description of the device
+     *
+     * This function return the description of the USB device located at the given 
+     * position of the internal list as a string.
+     *
+     * \param index is an integer with the position on the internal list of the 
+     *              desired device. This value must be between 0 and the number of
+     *              devices on the list -1.
+     * 
+     * \return a string with the description of the USB device.
+     */ 
+    std::string& get_description(int index);
+    /**
+     * \brief Function to get a new CFTDI object
+     *
+     * Function to get a CFTDI class object associated to the desired FTDI device.
+     * In this case the desired FTDI device is identified by either its serial number
+     * or its description. The serial number is in general the best way to select
+     * the desired device since it is unique. 
+     *
+     * However, the description may be shared by several devices of the same kind. 
+     * In this second case, the first device found on the list is returned.
+     * If the desired device is already being used by the system or any other 
+     * application this function will fail throwing an exception of the
+     * CFTDIServer class. Otherwise, a new CFTDI object is returned. 
+     *
+     * The CFTDI object returned by this function is already opened using the
+     * serial number or description provided to the function. The name of the 
+     * returned object is created by appending the provided serial number or
+     * description to "FTDI_" to have a unique identifier for each device.
+     *
+     * This class uses exceptions to report errors. The name of the exception 
+     * class associated to this class is CFTDIServerException. For a more detailes
+     * descritpion, see the corresponding documentation.
+     *
+     * \param serial_desc a string with either the serial number or the description
+     *                    of the desired FTDI device.
+     *
+     * \return on success this function returns a pointer a newly created CFTDI
+     *         object associated to the desired FTDI device. The calling process
+     *         is responsible for destroying the returned obejct.
+     */ 
+    CFTDI *get_device(std::string& serial_desc);
+    /**
+     * \brief operator << overloading
+     *
+     * This operator allow to show important information about the class and the
+     * information of all FTDI devices available on any ostream obejct (the standard
+     * output, a file, etc...).
+     *
+     * \param out A reference to an output device in which to show the desired 
+     *            information.
+     *
+     * \param server A reference to a CFTDIServer object with the information to be
+     *               displayed.
+     *
+     * \return an object with the desired information already formatted. In this case
+     *         it has the number of devices and the information on each of them.
+     */ 
+    friend std::ostream& operator<< (std::ostream &out,CFTDIServer &server);
+};
+
+#endif