Index: /BAORadio/libindi/libindi/.directory
===================================================================
--- /BAORadio/libindi/libindi/.directory	(revision 502)
+++ /BAORadio/libindi/libindi/.directory	(revision 502)
@@ -0,0 +1,5 @@
+[Dolphin]
+Timestamp=2010,11,5,21,27,5
+
+[Settings]
+ShowDotFiles=false
Index: /BAORadio/libindi/libindi/BAOControl/.directory
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/.directory	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/.directory	(revision 502)
@@ -0,0 +1,2 @@
+[Dolphin]
+Timestamp=2010,11,5,22,3,10
Index: /BAORadio/libindi/libindi/BAOControl/ClientSocket.cpp
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/ClientSocket.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/ClientSocket.cpp	(revision 502)
@@ -0,0 +1,64 @@
+// Implementation of the ClientSocket class
+
+#include "ClientSocket.h"
+#include "SocketException.h"
+
+
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+ClientSocket::ClientSocket ( std::string host, int port )
+{
+  if ( ! Socket::create() )
+    {
+      throw SocketException ( "Could not create client socket." );
+    }
+
+  if ( ! Socket::connect ( host, port ) )
+    {
+      throw SocketException ( "Could not bind to port." );
+    }
+}
+
+
+const ClientSocket& ClientSocket::operator << ( const std::string& s ) const
+{
+  if ( ! Socket::send ( s ) )
+    {
+     // throw SocketException ( "Could not write to socket." );
+    }
+
+  return *this;
+
+}
+
+
+const ClientSocket& ClientSocket::operator >> ( std::string& s ) const
+{
+  if ( ! Socket::recv ( s ) )
+    {
+    //   throw SocketException ( "Could not read from socket." );
+    }
+
+  return *this;
+}
+
+
+void ClientSocket::recv( std::string& s ) 
+{
+  if ( ! Socket::recv ( s ) )
+    {
+      sleep(1);
+
+      if (! Socket::shutdown() ) std::cout << "shutdown impossible.\n";
+
+      if (! Socket::create() ) std::cout << "create impossible.\n";
+
+      if (! Socket::connect((std::string)"192.168.0.1", 8000)) { std::cout << "connect impossible.\n"; Socket::shutdown(); } else {   std::cout << "Reconnexion reussie.\n"; }
+    }
+}
+
Index: /BAORadio/libindi/libindi/BAOControl/ClientSocket.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/ClientSocket.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/ClientSocket.h	(revision 502)
@@ -0,0 +1,28 @@
+// Definition of the ClientSocket class
+
+#ifndef ClientSocket_class
+#define ClientSocket_class
+
+#include "Socket.h"
+
+struct Position
+{
+   int x;
+   int y;
+};
+
+class ClientSocket : private Socket
+{
+ public:
+
+  ClientSocket ( std::string host, int port );
+  virtual ~ClientSocket(){};
+
+  const ClientSocket& operator << ( const std::string& ) const;
+  const ClientSocket& operator >> ( std::string& ) const;
+
+void recv( std::string& s ); 
+};
+
+
+#endif
Index: /BAORadio/libindi/libindi/BAOControl/Makefile
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/Makefile	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/Makefile	(revision 502)
@@ -0,0 +1,21 @@
+# Makefile for the socket programming example
+#
+
+CC=g++
+
+BAOControl_objects =  baocontrol.o ClientSocket.o Socket.o filetools.o exception.o astro.o
+
+
+all : BAOControl
+
+
+BAOControl: $(BAOControl_objects)
+	g++ -o BAOControl $(BAOControl_objects) -lpthread -lX11
+
+Socket: Socket.cpp
+ClientSocket: ClientSocket.cpp
+Astro: astro.cpp
+baocontrol: baocontrol.cpp
+
+clean:
+	rm -f *.o *.cpp~ *.c~ *.h~ BAOControl
Index: /BAORadio/libindi/libindi/BAOControl/Socket.cpp
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/Socket.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/Socket.cpp	(revision 502)
@@ -0,0 +1,226 @@
+// Implementation of the Socket class.
+
+
+#include "Socket.h"
+#include "string.h"
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <iostream>
+#include <netinet/tcp.h>
+
+
+
+
+
+Socket::Socket() :
+        m_sock ( -1 )
+{
+
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+
+}
+
+Socket::~Socket()
+{
+    if ( is_valid() )
+        ::close ( m_sock );
+}
+
+bool Socket::create()
+{
+    m_sock = socket ( AF_INET,
+                      SOCK_STREAM,
+                      0); //IPPROTO_TCP
+
+    if ( ! is_valid() )
+        return false;
+
+
+   //  TIME_WAIT - argh
+    int on = 1;
+
+    if ( setsockopt ( m_sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) return false;
+
+    if (setsockopt(m_sock, SOL_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)) <0) return false;
+
+    return true;
+}
+
+
+bool Socket::shutdown()
+{
+  int ret = 0;
+
+  if ( is_valid() )
+      ret =  ::shutdown ( m_sock, 2 );
+  
+  m_sock=-1;
+
+  if ( ret == 0 ) return true;
+
+  return false;
+}
+
+
+bool Socket::bind ( const int port )
+{
+    if ( ! is_valid() ) return false;
+    
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_addr.s_addr = INADDR_ANY;
+    m_addr.sin_port =  htons ( port );
+
+    int bind_return = ::bind ( m_sock,
+                               ( struct sockaddr * ) &m_addr,
+                               sizeof ( m_addr ) );
+
+
+    if ( bind_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::listen() const
+{
+    if ( ! is_valid() ) return false;
+    
+    int listen_return = ::listen ( m_sock, MAXCONNECTIONS );
+
+    if ( listen_return == -1 ) return false;
+    
+    return true;
+}
+
+
+bool Socket::accept ( Socket& new_socket ) const
+{
+    int addr_length = sizeof ( m_addr );
+    
+    new_socket.m_sock = ::accept ( m_sock, ( sockaddr * ) &m_addr, ( socklen_t * ) &addr_length );
+
+    if ( new_socket.m_sock <= 0 ) return false;
+        
+    return true;
+}
+
+
+bool Socket::send ( const std::string s ) const
+{
+    int status = ::send ( m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
+    
+    if ( status == -1 ) return false;
+        
+    return true;    
+}
+
+
+int Socket::recv ( std::string& s ) const
+{
+    int sel;
+    fd_set r;
+    struct timeval timeout;
+
+    if ( ! is_valid() ) return false;
+    
+    s="";
+
+    timeout.tv_sec = 0; // initialise le timeout, ici  les secondes
+    timeout.tv_usec = 1; // les microsecondes
+
+    FD_ZERO(&r); // initialise la liste de fd
+    FD_SET(m_sock, &r); // ajoute la socket dans la liste des fd
+    sel = select(m_sock + 1, &r, NULL, NULL, &timeout);
+    if (sel < 0) // select a rencontrÃ© un problÃšme
+    {
+        return -1;
+    }
+    else if (sel == 0) // timeout
+    {
+	return 1;
+    }
+    else // quelque chose est Ã  lire sur un file descriptor
+    {
+        if (FD_ISSET(m_sock, &r)) // si la socket est prÃªte Ã  Ãªtre lue
+        {
+            char buf [ MAXRECV + 1 ];
+
+            s = "";
+
+            memset ( buf, 0, MAXRECV + 1 );
+
+            int status = ::recv ( m_sock, buf, MAXRECV, 0 );
+
+            if ( status == -1 )
+            {
+	         // lÃ , nous ne sommes pas en prÃ©sence d'une vraie erreur
+		 // car le mode non-bloquant est activÃ© ici
+		 // (consulter la doc de la fct recv...)
+                 if (errno == EAGAIN )
+		 {
+	           return 0;
+		 }
+		 
+		 return -1;
+            }
+            else if ( status == 0 )
+            {
+                return 0;
+            }
+            else
+            {
+                s = buf;
+                return status;
+            }
+        }
+    }
+}
+
+
+
+bool Socket::connect ( const std::string host, const int port )
+{
+    if ( ! is_valid() ) return false;
+
+    memset ( &m_addr,
+             0,
+             sizeof ( m_addr ) );
+
+    m_addr.sin_family = AF_INET;
+    m_addr.sin_port = htons ( port );
+
+    int status = inet_pton ( AF_INET, host.c_str(), &m_addr.sin_addr );
+
+    if ( errno == EAFNOSUPPORT ) return false;
+
+
+    status = ::connect ( m_sock, ( sockaddr * ) &m_addr, sizeof ( m_addr ) );
+
+    if ( status == 0 ) return true;
+    
+    return false;
+}
+
+void Socket::set_non_blocking ( const bool b )
+{
+    int opts;
+
+    opts = fcntl ( m_sock,F_GETFL );
+
+    if ( opts < 0 )
+    {
+        return;
+    }
+
+    if ( b )
+        opts = ( opts | O_NONBLOCK );
+    else
+        opts = ( opts & ~O_NONBLOCK );
+
+    fcntl ( m_sock,
+            F_SETFL,opts );
+
+}
Index: /BAORadio/libindi/libindi/BAOControl/Socket.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/Socket.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/Socket.h	(revision 502)
@@ -0,0 +1,61 @@
+// Definition of the Socket class
+
+#ifndef Socket_class
+#define Socket_class
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string>
+#include <arpa/inet.h>
+#include <iostream>
+
+
+const int MAXHOSTNAME = 200;
+const int MAXCONNECTIONS = 5;
+const int MAXRECV = 5000;
+
+
+
+class Socket
+{
+ public:
+  Socket();
+  virtual ~Socket();
+
+
+  // Server initialization
+  bool create();
+  bool bind ( const int port );
+  bool listen() const;
+  bool accept ( Socket& ) const;
+
+  // Client initialization
+  bool connect ( const std::string host, const int port );
+
+  // Data Transimission
+  bool send ( const std::string ) const;
+  int recv ( std::string& ) const;
+
+
+  void set_non_blocking ( const bool );
+
+  bool is_valid() const { return m_sock != -1; }
+
+  bool shutdown();
+
+ private:
+
+  int m_sock;
+  sockaddr_in m_addr;
+
+
+
+
+};
+
+
+#endif
Index: /BAORadio/libindi/libindi/BAOControl/SocketException.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/SocketException.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/SocketException.h	(revision 502)
@@ -0,0 +1,23 @@
+// SocketException class
+
+
+#ifndef SocketException_class
+#define SocketException_class
+
+#include <string>
+
+class SocketException
+{
+ public:
+  SocketException ( std::string s ) : m_s ( s ) {};
+  ~SocketException (){};
+
+  std::string description() { return m_s; }
+
+ private:
+
+  std::string m_s;
+
+};
+
+#endif
Index: /BAORadio/libindi/libindi/BAOControl/astro.cpp
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/astro.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/astro.cpp	(revision 502)
@@ -0,0 +1,210 @@
+#include "astro.h"
+
+////////////////////
+// Routines Astro //
+////////////////////
+
+Astro::Astro()
+{
+    Longitude=0.0;
+    Latitude=0.0;
+    Lst=0.0;
+    JJ=0.0;
+    CorP=0.0;
+    CorEP=0.0;
+    Annee=0.0;
+    Mois=0.0;
+    Jour=0.0;
+    Heu=0.0;
+    Min=0.0;
+    Sec=0.0;
+    ep=0.0;
+    hs=0.0;
+    UTCP=0.0;
+    tsl=0.0;
+}
+
+Astro::~Astro()
+{
+}
+
+
+//0<=Angle<=2*PI
+double Astro::VerifAngle(double Angle)
+{
+    Angle=fmod(Angle, Pi2);
+    if (Angle<0.0) Angle+=Pi2;
+
+    return(Angle);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//Nutation
+
+void Astro::Nutation()
+{
+    double T,L,LP,M,MP,O,L2,LP2,O2;
+
+    T=(JJ-2415020.0)/36525.0;
+
+    L=(279.6967+(36000.7689+0.000303*T)*T)*Pidiv180;
+    LP=(270.4342+(481267.8831-0.001133*T)*T)*Pidiv180;
+    M=(358.4758+(35999.0498-0.000150*T)*T)*Pidiv180;
+    MP=(296.1046+(477198.8491+0.009192*T)*T)*Pidiv180;
+    O=(259.1833+(-1934.1420+0.002078*T)*T)*Pidiv180;
+
+    L2=2.0*L;
+    LP2=2.0*LP;
+    O2=2.0*O;
+
+    CorP=-(17.2327+0.01737*T)*sin(O)
+         -(1.2729+0.00013*T)*sin(L2)
+         +0.2088*sin(O2)
+         -0.2037*sin(LP2)
+         +(0.1261-0.00031*T)*sin(M)
+         +0.0675*sin(MP)
+         -(0.0497-0.00012*T)*sin(L2+M)
+         -0.0342*sin(LP2-O)
+         -0.0261*sin(LP2+MP)
+         +0.0214*sin(L2-M)
+         -0.0149*sin(L2-LP2+MP)
+         +0.0124*sin(L2-O)
+         +0.0114*sin(LP2-MP);
+
+    CorEP=(9.2100+0.00091*T)*cos(O)
+          +(0.5522-0.00029*T)*cos(L2)
+          -0.0904*cos(O2)
+          +0.0884*cos(LP2)
+          +0.0216*cos(L2+M)
+          +0.0183*cos(LP2-O)
+          +0.0113*cos(LP2+MP)
+          -0.0093*cos(L2-M)
+          -0.0066*cos(L2-O);
+
+    CorP=CorP/3600.0*Pidiv180;
+    CorEP=CorEP/3600.0*Pidiv180;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// calcul Jour julien
+
+void Astro::CalculJJ(double Heure)
+{
+
+    long y, a, b, c, e, m;
+
+    long year = (long)Annee;
+    int month = (int)Mois;
+    double day = Jour + Heure;
+
+
+    y = year + 4800;
+
+    m = month;
+    if ( m <= 2 )
+    {
+        m += 12;
+        y -= 1;
+    }
+    e = (306 * (m+1))/10;
+
+    a = y/100;
+    if ( year <= 1582L )
+    {
+        if ( year == 1582L )
+        {
+            if ( month < 10 )
+                goto julius;
+            if ( month > 10)
+                goto gregor;
+            if ( day >= 15 )
+                goto gregor;
+        }
+julius:
+
+        b = -38;
+    }
+    else
+    {
+
+gregor:
+        b = (a/4) - a;
+    }
+
+    c = (36525L * y)/100;
+
+    JJ = b + c + e + day - 32167.5;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//ObliquitÃ©
+
+void Astro::Obliquite(double JJ)
+{
+    double T;
+
+    T = (JJ-2415020.0) / 36525.0;
+
+    ep = (23.452294+ (((0.000000503 * T ) - 0.00000164 ) * T - 0.0130125 ) * T ) * Pidiv180;
+}
+
+///////////////////////////////////////////////////////////////////////
+//Temps sidÃ©ral local
+
+double Astro::TSL(double JJ, double HeureSiderale, double Longitude)
+{
+    double rd,T;
+
+    T = (JJ - 2415020.0 ) / 36525.0;
+    rd = 0.276919398 + ( 100.0021359 + 0.000001075 * T ) * T;
+    rd += HeureSiderale;
+    rd *= Pi2;
+    rd += CorP * cos(ep);
+    rd -= Longitude;
+
+    return VerifAngle(rd);
+}
+
+
+void Astro::CalculTSL()
+{
+    hs=(Heu+Min/60.0+Sec/3600.0)/24.0;
+
+    hs-=UTCP/24.0;
+
+    CalculJJ(hs);
+
+    Obliquite(JJ);
+
+    Nutation();
+
+    tsl=TSL(JJ, hs, Longitude);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//Azimut et hauteur Ã  partir de AR et Dec
+
+void Astro::Azimut(double ts, double Latitude, double Ar, double De, double *azi, double *hau)
+{
+    double ah, ht, a1, az, zc, ac;
+
+    ah=ts-Ar;
+
+    zc=sin(Latitude)*sin(De)+cos(Latitude)*cos(De)*cos(ah);
+    ht=atan(zc/sqrt((-zc*zc)+1.0));
+
+    a1=cos(De)*sin(ah)/cos(ht);
+    ac=(-cos(Latitude)*sin(De)+sin(Latitude)*cos(De)*cos(ah))/cos(ht);
+    az=atan(a1/sqrt((-a1*a1)+1.0));
+    if (ac<0.0) az=Pi-az;
+
+    az=VerifAngle(Pi+az);
+
+    *azi=az;
+    *hau=ht;
+}
+
Index: /BAORadio/libindi/libindi/BAOControl/astro.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/astro.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/astro.h	(revision 502)
@@ -0,0 +1,54 @@
+// Definition of the Astro class
+// Franck RICHARD
+// BAORadio
+
+#ifndef Astro_class
+#define Astro_class
+
+#include "math.h"
+
+//////////////////////////////
+// Constantes MathÃ©matiques //
+//////////////////////////////
+
+#define Pi		3.14159265358979323846264338327
+#define Pidiv180	0.01745329251994329576923690768
+#define N180divPi	57.2957795130823208767981548141
+#define Pi2          	6.28318530717958647692528676655
+#define Pidiv2		1.57079632679489661923132169163
+
+
+class Astro
+{
+public:
+    Astro();
+    ~Astro();
+
+    double VerifAngle(double Angle);
+    void  Azimut(double ts, double Latitude, double Ar, double De, double *azi, double *hau);
+    void  CalculJJ(double Heure);
+    double TSL(double JJ,double HeureSiderale,double Longitude);
+    void Nutation();
+    void Obliquite(double JJ);
+    void CalculTSL();
+    
+    double Longitude;
+    double Latitude;
+    double Lst;
+    double JJ;
+    double CorP;
+    double CorEP;
+    double Annee;
+    double Mois;
+    double Jour;
+    double Heu;
+    double Min;
+    double Sec;
+    double ep;
+    double hs;
+    double UTCP;
+    double tsl;
+};
+
+
+#endif
Index: /BAORadio/libindi/libindi/BAOControl/baocontrol.cpp
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/baocontrol.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/baocontrol.cpp	(revision 502)
@@ -0,0 +1,1189 @@
+/********************/
+/* BAOCONTROL       */
+/*                  */
+/********************/
+
+
+#include "baocontrol.h"
+
+
+/* Affiche Ã  l'Ã©cran (si AfficheEcran==true) et sauvegarde dans le fichier 
+   BAOControl.log le message contenu dans la variable chaine */
+void Affiche(std::string chaine, bool AfficheEcran)
+{
+    FILE *pFile = NULL;
+
+    pFile = fopen ("BAOControl.log", "a");
+
+    if (AfficheEcran) std::cout << chaine;
+    
+    fprintf (pFile, chaine.c_str());
+
+    os.str("");
+
+    fclose (pFile);
+}
+
+
+/*Affiche les messages d'erreur en rouge */
+void Erreur(std::string chaine)
+{
+    std::cout << red;
+    Affiche(chaine, true);
+    std::cout << black;
+}
+
+
+/*initialise une fenÃªtre graphique */
+void initialiserFenetre()
+{
+    XGCValues gcv;
+    XFontStruct * fd;
+    
+    /*contacte le serveur*/
+    if ((d = XOpenDisplay(getenv("DISPLAY"))) == NULL)
+    {
+        Erreur("Impossible de contacter le serveur\n\n");
+        exit(1);
+    }
+
+    /*crÃ©e une fenÃªtre*/
+    w = XCreateSimpleWindow(d, RootWindow(d, DefaultScreen(d)),
+                            0, 0, larg, haut,
+                            2, BlackPixel(d, DefaultScreen(d)),
+                            WhitePixel(d, DefaultScreen(d)));
+	
+    /* Creation du double buffer */
+    db = XCreatePixmap(d, w, larg, haut, DefaultDepth(d, DefaultScreen(d)));
+
+    /*chargement d'une police de caractÃšres*/
+    if ((fd=XLoadQueryFont(d, "fixed")) == NULL)
+    {
+        Erreur("Impossible de charger la police fixed\n\n");
+        exit(1);
+    }
+
+    /*crÃ©ation d'un contexte graphique*/
+    gcv.font = fd->fid;
+    gcv.foreground = BlackPixel(d, DefaultScreen(d));
+    noir = XCreateGC(d, w, GCFont | GCForeground, &gcv);
+
+    gcv.foreground = 200*255;
+    vert = XCreateGC(d, w, GCFont | GCForeground, &gcv);
+
+    gcv.foreground = 255*256*256;
+    rouge = XCreateGC(d, w, GCFont | GCForeground, &gcv);
+
+    gcv.foreground = 200*256*256+200*256+200;
+    gris = XCreateGC(d, w, GCFont | GCForeground, &gcv);
+
+    /*affiche la fenÃªtre */
+    XMapWindow(d, w);
+}
+
+
+/* Dessine les Ã©lÃ©ments de la fenÃªtre graphique */
+void Dessiner()
+{
+    char chaine[100];
+    GC color;
+
+    /* On efface la fenÃªtre */
+    XSetForeground(d, noir, WhitePixel(d, DefaultScreen(d)));
+    XFillRectangle(d, db, noir, 0, 0, larg, haut);
+    XSetForeground(d, noir, BlackPixel(d, DefaultScreen(d)));
+
+    /* Affichage de la date et de l'heure */
+    int h=astro->Heu;
+    int m=astro->Min;
+    int s=astro->Sec;
+    int j=astro->Jour;
+    
+    if (s==60) {
+        s=0;
+        m++;
+        if (m==60) {
+            m=0;
+            h++;
+            if (h==24) {
+                h=0;
+                j++;
+            }
+        }
+    }    
+    
+    sprintf(chaine, "%02i:%02i:%02i TU    %02i/%02.0f/%04.0f    JJ=%10.5f",
+            h, m, s, j, astro->Mois, astro->Annee, astro->JJ);
+
+    XDrawString(d, db, noir, 10, 10, chaine, strlen(chaine));
+
+    if (run)
+    {
+        sprintf(chaine, "Prochaine etape dans %4.1fs", (objets[runnum].JJ-astro->JJ)*3600.0*24.0);
+
+        if ((objets[runnum].JJ-astro->JJ)*3600.0*24.0 >= 0.0) XDrawString(d, db, noir, 350, 10, chaine, strlen(chaine));
+    }
+
+    /*affichage des cercles d'Ã©tat*/
+    for (int i=0; i <20; i++)
+    {
+        for (int j=0; j<5; j++)
+        {
+            switch(Antennes[20*j+i].ok)
+	    {
+	      case 1 : color=vert; break;
+	      case 2 : color=rouge; break;
+	      default: color=gris; break;
+	    }
+            XFillArc(d, db ,color, 10+i*30, 20+j*30, 15, 15, 0, 360*64);
+            XDrawArc(d, db ,noir, 10+i*30, 20+j*30, 15, 15, 0, 360*64);
+        }
+    }
+
+
+    /*Affichage des messages d'erreur*/
+    if (lognum>15)
+    {
+        for (int i=lognum-1; i>lognum-16; i--)
+        {
+            if ((logs[i].find("Err")!=string::npos)
+                    || (logs[i].find("ALERTE")!=string::npos)) color=rouge;
+            else color=vert;
+            XDrawString(d, db, color, 10, 15*12+(i-lognum+15)*12, logs[i].c_str(), strlen(logs[i].c_str()));
+        }
+    }
+    else
+    {
+        for (int i=0; i<lognum; i++)
+        {
+            if ((logs[i].find("Err")!=string::npos)
+                    || (logs[i].find("ALERTE")!=string::npos)) color=rouge;
+            else color=vert;
+            XDrawString(d, db, color, 10, 15*12+i*12, logs[i].c_str(), strlen(logs[i].c_str()));
+        }
+    }
+    
+    XCopyArea(d, db, w, noir, 0, 0, larg, haut, 0, 0); 
+          
+    /* on force le rafraichissement de l'Ã©cran */
+    XFlush(d);
+}
+
+
+/* Gestion des messages concernant la fenÃªtre graphique */
+void rouler(char* reponse)
+{
+    XEvent e;
+
+    if (XCheckWindowEvent(d, w, ExposureMask, &e))
+    {
+        switch (e.type)
+        {
+        default:
+            //std::cout << "J'ai reÃ§u un Ã©vÃšnement " <<  e.type << std::endl
+            break;
+        case Expose :
+            Dessiner();
+            break;
+        }
+    }
+}
+
+
+/* RÃ©cupÃšre les messages envoyÃ©s par indi_BAO */
+void LireReponse()
+{
+    std::string reponse, decomp;
+    std::stringstream os;
+    bool test=false;
+
+    *client_socket >> reponse;
+
+    if (reponse.find("message")!=string::npos)
+    {
+        /* on ne garde que la partie intÃ©ressante */
+        reponse=reponse.substr(reponse.find("message")+9);
+
+        reponse=reponse.substr(0, reponse.find("\""));
+
+	/*rÃ©cupÃšre l'adresse ip de l'antenne */
+        if (reponse.find(". (Antennes connectees")!=string::npos)
+        {
+            decomp=reponse.substr(0, reponse.find(". (Antennes connectees"));
+            decomp=decomp.substr(decomp.rfind(".")+1);
+
+	    /*si cette antenne est dÃ©jÃ  connectÃ©e, on change son Ã©tat */
+            for (int i=0; i<numAntenne; i++)
+            {
+                if (atoi(decomp.c_str()) == Antennes[i].ip)
+                {
+                    Antennes[i].ok=1;
+                    test=true;
+		    break;
+                }
+            }
+
+            /*ou on ajoute son Ã©tat */
+            if (!test)
+            {
+                Antennes[numAntenne].ip=atoi(decomp.c_str());
+                Antennes[numAntenne].ok=1;
+                numAntenne++;
+            }
+        }
+
+        /*erreur sur une antenne -> on change son Ã©tat dans la fenÃªtre */
+        if  ((reponse.find("ALERTE antenne ")!=string::npos) || (reponse.find("Erreur sur l antenne ")!=string::npos))
+        {
+            decomp=reponse.substr(0, reponse.find(" :"));
+            decomp=decomp.substr(decomp.rfind(".")+1);
+
+            for (int i=0; i<numAntenne; i++)
+            {
+                if (atoi(decomp.c_str()) == Antennes[i].ip)
+                {
+                    Antennes[i].ok=2;
+                }
+            }
+        }
+
+        /* On sauvegarde le message dans le tableau log */
+        os << lognum << " : " << reponse;
+	
+	Affiche(os.str(), false);
+	Affiche("\n", false);
+
+        logs[lognum++]=os.str();
+	if (lognum>=MAXLOG-1) lognum=0;
+	  
+	/*on actualise la fenÃªtre */
+        Dessiner();
+    }
+
+    rouler((char *)reponse.c_str());
+}
+
+
+/* Est-ce que la rÃ©ponse du pilote indi_BAO
+est conforme Ã  ce que l'on attendait ? */
+bool VerifReponse(std::string reponseattendue)
+{
+    std::string reponse;
+
+    usleep(10000); // attendre 10 ms pour laisser le temps au pilote indi_BAO de rÃ©pondre
+
+    *client_socket >> reponse;
+
+    if (reponse.find(reponseattendue)==string::npos)
+    {   
+        //rÃ©ponse inconnue -> une erreur ?
+        os << "RÃ©ponse du pilote indi_BAO :" << std::endl << reponse
+                  << std::endl << std::endl << std::endl;
+	Erreur(os.str());	  
+    }
+
+    return true;
+}
+
+
+/*RÃ©cupÃ©ration de la date et de l'heure 
+ et calcul du jour julien et du tsl */
+void CalculJourJulien()
+{
+    struct tm date;
+    time_t t;
+    struct timeval tv;
+    struct timezone tz;
+
+    time(&t);
+    date=*gmtime(&t);
+    gettimeofday(&tv, &tz);
+
+    astro->Annee=(double)(date.tm_year+1900);
+    astro->Mois=(double)(date.tm_mon+1);
+    astro->Jour=(double)date.tm_mday;
+    astro->Heu=(double)date.tm_hour;
+    astro->Min=(double)date.tm_min;
+    astro->Sec=(double)date.tm_sec+tv.tv_usec/1.0E6;
+    astro->UTCP=0.0;//(double)date.tm_isdst;
+
+    //Calcul du temps sidÃ©ral local et du JJ
+
+    astro->CalculTSL();
+}
+
+
+/* gestion du thread permettant l'actualisation de la fenÃªtre graphique
+ et la rÃ©cupÃ©ration des messages d'indi_BAO */
+void *my_thread_process (void * arg)
+{
+    while (NoExit)
+    {
+        CalculJourJulien();
+
+	//Execution d'un fichier de mouvements
+        if (run && numobjets>1 && runnum<numobjets)
+        {
+	    /* On lance l'exÃ©cution des mouvements programmÃ©s */
+            if (astro->JJ>=objets[runnum].JJ && !objets[runnum].exec)
+            {
+                if (runnum==1) Affiche("DÃ©but de l'exÃ©cution du fichier de mouvements\n\n", true);
+                os << "Suivi de l'objet nÂ°" << runnum << std::endl;
+		Affiche(os.str(), true);
+                objets[runnum].exec=true;
+
+                Goto(objets[runnum].ad, objets[runnum].de, Transit);
+            }
+
+            /*on arrive Ã  la fin du mouvements i */
+            if (astro->JJ>=objets[runnum].JJ+objets[runnum].Duree/3600.0/24.0)
+            {
+                Abort();
+
+		/*fin de la commande run */
+                if (runnum+1>=numobjets)
+                {
+                    Affiche("Fin de l'execution du fichier de mouvements\n\n", true);
+		    std::cout << std::endl << blue << ">";
+                    run=false;
+                    runnum=1;
+                    numobjets=1;
+
+		    /*on sort du programme dans le cas ./BAOControl -r fileName */
+                    if (exitrun) NoExit=false;
+                }
+                else
+                {
+                    runnum++;
+                }
+            }
+        }
+
+        LireReponse();
+
+        Dessiner();
+
+        usleep(100000); //100 ms
+    }
+
+    pthread_exit (0);
+}
+
+
+
+/* DÃ©composition et vÃ©rification des dates, heures, AD et dÃ©clinaisons 
+ type = 0 -> DÃ©clinaison/latitude
+ type = 1 -> longitude
+ type = 2 -> AD ou heure
+ type = 3 -> date */
+bool Decomposition(std::string chaine, char type, float *a1, float *a2, float *a3)
+{
+    std::string car, s;
+    int pos1, pos2;
+    float a, b, c;
+
+    if (type==3) car="/"; else car=":";
+    
+    /* Y a-t-il 2 caractÃšres : ou / Ã  la suite ? */
+    int test=0;
+    for (int i=0; i<chaine.length(); i++) if (chaine[i]==car[0]) test++;
+    if (test<2) return false;
+
+    s=chaine.substr(0, chaine.find(car));
+
+    a=atoi(s.c_str());
+     
+    s=chaine.substr(chaine.find(car)+1, chaine.rfind(car)-chaine.find(car)-1);
+    
+    b=atoi(s.c_str());
+
+    s=chaine.substr(chaine.rfind(car)+1);
+
+    c=atoi(s.c_str());
+
+    if (type <3)
+    {
+        if ((type==0) && (a>90.0 || a<-90.0)) return false;
+        if ((type==1) && (a>180.0 || a<-180.0)) return false;
+        if ((type==2) && (a>23.0 || a<0.0)) return false;
+        if (b<0.0 || b>59.0) return false;
+        if (c<0.0 || c>=60.0) return false;
+    }
+    else
+    {
+        if (a<0.0 || a>31.0) return false;
+        if (b<0.0 || b>12.0) return false;
+    }
+
+    if (a1!=NULL) *a1=a;
+    if (a2!=NULL) *a2=b;
+    if (a3!=NULL) *a3=c;
+
+    return true;
+}
+
+/* isole les diffÃ©rents Ã©lÃ©ments de la commande saisie par l'utilisateur */
+bool DecompositionCommande(std::string chaine, std::string commande, std::string *chaine1, std::string *chaine2)
+{
+    size_t pos;
+
+    pos = chaine.find(commande);
+
+    if (pos!=string::npos)
+    {
+        pos+=commande.length();
+
+        chaine=chaine.substr(pos);
+
+        while (chaine[0] == ' ') chaine=chaine.substr(1);
+
+        *chaine1=chaine.substr(0,chaine.find(" "));
+
+        if (chaine2!=NULL)
+        {
+            pos = chaine.find(" ");
+
+            if (pos!=string::npos)
+            {
+                chaine=chaine.substr(pos+1);
+
+                while (chaine[0] == ' ') chaine=chaine.substr(1);
+
+                *chaine2=chaine.substr(0, chaine.find(" "));
+            }
+        }
+    }
+
+    return true;
+}
+
+
+/*Envoie la longitude et la latitude du lieu d'observation au pilote indi_BAO */
+bool EncoyerCoordGeographiques()
+{
+    try
+    {
+        *client_socket << "<newNumberVector device=\"BAO\" name=\"GEOGRAPHIC_COORD\">";
+        *client_socket << "<oneNumber name=\"LAT\">";
+        *client_socket << Latitude;
+        *client_socket << "</oneNumber>";
+        *client_socket << "<oneNumber name=\"LONG\">";
+        *client_socket << Longitude;
+        *client_socket << "</oneNumber>";
+        *client_socket << "</newNumberVector>";
+
+        if (!VerifReponse("name=\"GEOGRAPHIC_COORD\" state=\"Ok\""))
+        {
+            Erreur("ERREUR fct EncoyerCoordGeographiques : pas de rÃ©ponse du pilote indi_BAO.\n\n");
+
+            return false;
+        }
+    }
+
+    catch ( SocketException& e )
+    {
+        os << "Exception was caught:" << e.description() << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    std::cout << "Les coordonnÃ©es gÃ©ographiques ont bien Ã©tÃ© envoyÃ©es au pilote indi_BAO"  << std::endl << std::endl;
+
+    return true;
+}
+
+
+/* Place les antennes en position de repos */
+bool Park()
+{
+    try
+    {
+        *client_socket << "<newSwitchVector device=\"BAO\" name=\"\" >";
+        *client_socket << "<oneSwitch name=\"PARK\">";
+        *client_socket << "On";
+        *client_socket << "</oneSwitch>";
+        *client_socket << "</newSwitchVector>";
+
+        if (!VerifReponse("Envoi de la commande Park"))
+        {
+            Erreur("La commande PARK a Ã©chouÃ©.\n\n");;
+
+            return false;
+        }
+    }
+    catch ( SocketException& e)
+    {
+        os << e.description() << "\n";
+	Erreur(os.str());
+        return false;
+    }
+
+    Affiche("Le pilote indi_BAO a bien reÃ§u la commande PARK.\n\n", true);
+
+    return true;
+}
+
+
+/* Annule le mouvement en cours */
+bool Abort()
+{
+    try
+    {
+        *client_socket << "<newSwitchVector device=\"BAO\" name=\"ABORT_MOTION\" >";
+        *client_socket << "<oneSwitch name=\"ABORT\">";
+        *client_socket << "On";
+        *client_socket << "</oneSwitch>";
+        *client_socket << "</newSwitchVector>";
+
+        if (!VerifReponse("name=\"ABORT_MOTION\" state=\"Ok\""))
+        {
+            Erreur("L'annulation a Ã©chouÃ©.\n\n");
+
+            return false;
+        }
+    }
+    catch ( SocketException& e)
+    {
+        os << e.description() << "\n";
+	Erreur(os.str());
+        return false;
+    }
+
+    Affiche("Le pilote indi_BAO a bien reÃ§u la commande ABORT.\n\n", true);
+
+    return true;
+}
+
+/*aller aux coordonnÃ©es ar et dec dans le mode transit ou tracking */
+bool Goto(std::string ar, std::string dec, bool Transit)
+{
+    try
+    {
+        *client_socket << "<newSwitchVector device=\"BAO\" name=\"ON_COORD_SET\">";
+        *client_socket << "<oneSwitch name=\"TRANSIT\">";
+        if (Transit) *client_socket << "On";
+        else *client_socket << "Off";
+        *client_socket << "</oneSwitch>";
+
+        *client_socket << "<oneSwitch name=\"TRACKING\">";
+        if (Transit)  *client_socket << "Off";
+        else *client_socket << "On";
+        *client_socket << "</oneSwitch>";
+        *client_socket << "</newSwitchVector>";
+
+        if (!VerifReponse("name=\"ON_COORD_SET\""))
+        {
+            Erreur("Le changement de mode TRANSIT/TRACKING a Ã©chouÃ©.\n\n");
+
+            return false;
+        }
+
+        *client_socket << "<newNumberVector device=\"BAO\" name=\"EQUATORIAL_EOD_COORD_REQUEST\">";
+        *client_socket << "<oneNumber name=\"RA\">";
+        *client_socket << ar;
+        *client_socket << "</oneNumber>";
+        *client_socket << "<oneNumber name=\"DEC\">";
+        *client_socket << dec;
+        *client_socket << "</oneNumber>";
+        *client_socket << "</newNumberVector>";
+
+        if (!VerifReponse("name=\"EQUATORIAL_EOD_COORD_REQUEST\""))
+        {
+            Erreur("Le transfert des coordonnÃ©es de l'objet a Ã©chouÃ©.\n\n");
+
+            return false;
+        }
+    }
+    catch ( SocketException& e)
+    {
+        os << e.description() << "\n";
+	Erreur(os.str());
+        return false;
+    }
+
+    os << "Les nouvelles coordonnÃ©es AD=" << ar << "  DEC=" << dec << " ont Ã©tÃ© envoyÃ©es au pilote indi_BAO.\n\n";
+    Affiche(os.str(), true);
+
+    return true;
+}
+
+
+/*se connecter ou se dÃ©connecter au pilote indi_BAO */
+bool Connect(bool connect)
+{
+    try
+    {
+        *client_socket << "<newSwitchVector device=\"BAO\" name=\"CONNECTION\">";
+
+        if (connect) *client_socket << "<oneSwitch name=\"CONNECT\">";
+        else *client_socket << "<oneSwitch name=\"DISCONNECT\">";
+
+        *client_socket << "On";
+        *client_socket << "</oneSwitch>";
+        *client_socket << "</newSwitchVector>";
+
+        if (connect)
+        {
+            if (!VerifReponse("BAORadio is online"))
+            {
+                Erreur("La connexion a Ã©chouÃ©.\n\n");
+
+                return false;
+            }
+        }
+        else
+        {
+            if (!VerifReponse("BAORadio is offline"))
+            {
+                Erreur("La dÃ©connexion a Ã©chouÃ©.\n\n");
+
+                return false;
+            }
+        }
+    }
+
+    catch ( SocketException& e )
+    {
+        os << "Exception was caught:" << e.description() << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    if (connect)
+    {
+        Affiche("La connexion a Ã©tÃ© Ã©tablie avec le pilote indi_BAO.\n\n", true);
+
+        EncoyerCoordGeographiques();
+    }
+    else
+    {
+        Affiche("Confirmation de la dÃ©connexion avec le pilote indi_BAO.\n\n", true);
+    }
+
+    return true;
+}
+
+
+/* Lecture des mouvements planifiÃ©s dans le fichier fileName */
+bool LectureFichierMouvements(char * fileName)
+{
+    char * section =(char * )malloc(80);
+    char * key = (char *)malloc(80);
+    char * chaine = (char *)malloc(80);
+    char * value;
+    
+    Astro * AstroJJ;
+    
+    float a1, a2, a3, h;
+
+    numobjets=1;
+
+    os << "Lecture du fichier " << fileName << std::endl << std::endl;
+    Affiche(os.str(), true);
+
+    strcpy(section, "objet 1");
+    strcpy(key, "date");
+
+    while ((readINI(section, key, &value, fileName)) && (numobjets<MAXOBJETS))
+    {
+        os << "object nÂ°" << numobjets << std::endl;
+	Affiche(os.str(), true);
+
+        strcpy(key, "date");
+
+        if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 3, &a1, &a2, &a3)))
+        {
+            os << "Date du dÃ©but de l'observation : le " << value;
+	    Affiche(os.str(), true);
+
+	    AstroJJ = new Astro();
+	    
+            AstroJJ->Jour=a1;
+            AstroJJ->Mois=a2;
+            AstroJJ->Annee=a3;
+
+            AstroJJ->CalculJJ(0.0);
+
+            objets[numobjets].JJ=AstroJJ->JJ;
+	    
+	    delete AstroJJ;
+        }
+        else
+        {
+            os << "La date de la rubrique [objet " << numobjets << "] est incorrecte !" << std::endl;
+	    Erreur(os.str());	    
+            return false;
+        }
+
+        strcpy(key, "heure");
+
+        if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 2, &a1, &a2, &a3)))
+        {
+            os << " Ã  " <<  value ;
+	    Affiche(os.str(), true);
+
+            objets[numobjets].JJ+=(a1+a2/60.0+a3/3600.0)/24.0;
+	    
+	    sprintf(chaine, " TU  -> JJ=%10.5f\n", objets[numobjets].JJ);
+	    
+	    Affiche(chaine, true);
+	    
+	    for (int i=1; i<numobjets; i++)
+	    {
+	      if (objets[i].JJ==objets[numobjets].JJ)
+	      {
+		os << "Attention, les observations des objets " << i << " et " << numobjets << " sont dÃ©finies Ã  la mÃªme date !\n";
+		Erreur(os.str());
+	      }
+	      
+	      if (objets[i].JJ+objets[i].Duree/3600/24.0>objets[numobjets].JJ)
+	      {
+		os << "Attention, les observations des objets " << i << " et " << numobjets << " se chevauchent !\n";
+		Erreur(os.str());
+	      }
+	    }
+        }
+        else
+        {
+            os << "L'heure de la rubrique [objet " << numobjets << "] est incorrecte !" << std::endl;
+	    Erreur(os.str());
+            return false;
+        }
+
+
+
+
+        strcpy(key, "duree");
+
+        objets[numobjets].Duree=0.0;
+
+        if (readINI(section, key, &value, fileName))
+        {
+           os << "DurÃ©e de l'observation : " << value << " secondes" << std::endl;
+	   Affiche(os.str(), true);
+
+           objets[numobjets].Duree=atof(value);
+        }
+        else
+        {
+            os << "La duree d'observation de la rubrique [objet " << numobjets << "] est incorrecte !" << std::endl;
+	    Erreur(os.str());
+            return false;
+        }
+
+
+        strcpy(key, "ad");
+
+        strcpy(objets[numobjets].ad, "");
+
+        if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 2, NULL, NULL, NULL)))
+        {
+            os << "Ascension droite de l'objet : " << value << std::endl;
+	    Affiche(os.str(), true);
+	    
+            strcpy(objets[numobjets].ad, value);
+        }
+        else
+        {
+            os << "L'ascension droite de la rubrique [objet " << numobjets << "] est incorrecte !" << std::endl;
+	    Erreur(os.str());
+            return false;
+        }
+
+
+        strcpy(key, "de");
+
+        strcpy(objets[numobjets].de, "");
+
+        if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 0, NULL, NULL, NULL)))
+        {
+            os << "DÃ©clinaison de l'objet : " << value << std::endl << std::endl;
+	    Affiche(os.str(), true);
+
+            strcpy(objets[numobjets].de, value);
+        }
+        else
+        {
+            os << "La dÃ©clinaison de la rubrique [objet " << numobjets << "] est incorrecte !" << std::endl;
+	    Erreur(os.str());
+            return false;
+        }
+
+        objets[numobjets].exec=false;
+
+        numobjets++;
+
+        sprintf(section, "objet %i", numobjets);
+
+    }
+    
+
+    return true;
+}
+
+/*Execute le fichier de mouvements */
+bool Run(std::string fichier)
+{
+    bool exec=LectureFichierMouvements((char *)fichier.c_str());
+
+    CalculJourJulien();
+
+    if (exec && numobjets>1)
+    {
+        if (objets[numobjets-1].JJ+objets[numobjets-1].Duree/3600.0/24.0 < astro->JJ)
+        {
+            Erreur("Le fichier contient des dates qui sont toutes pÃ©rimÃ©es. ExÃ©cution annulÃ©e.\n\n");
+            if (exitrun) NoExit=false;
+            return false;
+        }
+        else
+        {
+            os << "Execution du fichier " << fichier << " en attente..." << std::endl << std::endl;
+            Affiche(os.str(), true);
+            run=true;
+        }
+    }
+    else
+    {
+        os << std::endl << "Le fichier " << fichier << " contient des erreurs ou n'existe pas...\n" << std::endl << std::endl;
+        Erreur(os.str());
+	if (exitrun) NoExit=false;
+        return false;
+    }
+
+    return true;
+}
+
+
+/*identification des commandes entrÃ©es par l'utilisateur */
+void DecodageEntreesUtilisateur(std::string chaine)
+{
+    std::string ar, de, fichier;
+
+
+    if (chaine.find("goto")!=string::npos)
+    {
+        if (DecompositionCommande(chaine, "goto", &ar, &de) && Decomposition(ar, 2, NULL, NULL, NULL) && Decomposition(de, 0, NULL, NULL, NULL))
+        {
+            Goto(ar, de, Transit);
+        }
+        else
+        {
+            Erreur("Erreur goto : le format de la commande est goto AD DEC\n \
+                    L AD doit Ãªtre de la forme xx:yy:zz   (ex: 12:00:03 pour 12h 0m 3s)\n \
+                    La dÃ©clinaison doit Ãªtre de la forme +/-xx:yy:zz (ex: -12:50:01 pour -12Â° 50' 01'')\n\n");
+        }
+    }
+    
+    
+    if (chaine.find("abort")!=string::npos)
+    {
+        Abort();
+
+        if (chaine.find("run")!=string::npos)
+        {
+            run=false;
+            runnum=1;
+            numobjets=1;
+
+            Affiche("Annulation de l'exÃ©cution du fichier de mouvements.\n\n", true);
+	    
+	    return;
+        }
+    }
+    
+
+    if (chaine.find("run")!=string::npos)
+    {
+        if (DecompositionCommande(chaine, "run", &fichier, NULL))
+        {
+            Run(fichier);
+        }
+        else
+        {
+            Erreur("Erreur run : la commande run doit Ãªtre suivie par un nom de fichier.\n\n");
+        }
+    }
+    
+
+    if (chaine.find("connect")!=string::npos)
+    {
+        Connect(chaine.find("disconnect")==string::npos);
+    }
+        
+
+    if (chaine.find("transit")!=string::npos)
+    {
+        Affiche("Mode transit activÃ©.\n\n", true);
+
+        Transit=true;
+    }
+    
+
+    if (chaine.find("tracking")!=string::npos)
+    {
+        Affiche("Mode tracking activÃ©.\n\n", true);
+
+        Transit=false;
+    }
+    
+
+    if (chaine.find("park")!=string::npos)
+    {
+        Park();
+    }
+    
+
+   
+    
+
+    if (chaine.find("help")!=string::npos)
+    {
+        std::cout << std::endl;
+
+        std::cout << "connect : connecte le pilote INDI" << std::endl;
+        std::cout << "disconnect : ferme la connexion avec le pilote INDI" << std::endl;
+        std::cout << "goto AD Dec : pointe l'objet aux coordonnÃ©es AD Dec" << std::endl;
+        std::cout << "transit : mode de suivi transit" << std::endl;
+        std::cout << "tracking : mode de suivi tracking" << std::endl;
+        std::cout << "run filename : execute le fichier filename" << std::endl;
+        std::cout << "abort run : annule l'exÃ©cution du fichier de mouvements" << std::endl;
+        std::cout << "abort : annule le mouvement en cours" << std::endl;
+        std::cout << "park : place les antennes en position de repos" << std::endl;
+        std::cout << "exit : sortir de BAOControl" << std::endl;
+
+        std::cout << std::endl;
+    }
+    
+
+    if (chaine.find("exit")!=string::npos)
+    {
+        Connect (false);
+
+        NoExit=false;
+    }
+}
+
+
+/* chargement des paramÃštres dans le fichier params */
+bool ChargementParametres()
+{
+    char * section =(char * )malloc(80);
+    char * key = (char *)malloc(80);
+    char * value;
+    char * fileName = (char *)malloc(sizeof(char)*255);
+
+
+    Affiche("Lecture du fichier de configuration 'params' :\n\n", true);
+
+    strcpy(fileName,"params");
+
+    strcpy(section, "connexion indi");
+
+    strcpy(key, "serveur");
+
+    strcpy(Serveur, "");
+
+    if (readINI(section, key, &value, fileName))
+    {
+        strcpy(Serveur, value);
+        os << "serveur=" << Serveur << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "Nom du serveur invalide !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    strcpy(key, "port");
+
+    if (readINI(section, key, &value, fileName))
+    {
+        Port=atoi(value);
+        os << "port=" << Port << std::endl << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "NumÃ©ro de port incorrect !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    strcpy(section, "coordonnees geographiques");
+
+    strcpy(Latitude, "");
+    strcpy(Longitude, "");
+    
+    strcpy(key, "latitude");
+
+    if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 0, NULL, NULL, NULL)))
+    {
+        strcpy(Latitude, value);
+        os << "latitude=" << Latitude << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "La latitude est incorrecte !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    strcpy(key, "longitude");
+
+    if ((readINI(section, key, &value, fileName)) && (Decomposition(value, 1, NULL, NULL, NULL)))
+    {
+        strcpy(Longitude, value);
+        os << "longitude=" << Longitude << std::endl << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "La longitude est incorrecte !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    strcpy(section, "transit");
+
+    strcpy(key, "delai");
+
+    if (readINI(section, key, &value, fileName))
+    {
+        delaitransit=atoi(value);
+        os << "delai transit= " << delaitransit << " sec" << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "Le paramÃštre transit est incorrect !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    strcpy(section, "tracking");
+
+    strcpy(key, "delai");
+
+    if (readINI(section, key, &value, fileName))
+    {
+        delaitracking=atoi(value);
+        os << "delai tracking= " << delaitracking << " sec" << std::endl << std::endl;
+        Affiche(os.str(), true);
+    }
+    else
+    {
+        os << "Le paramÃštre tracking est incorrect !" << std::endl;
+        Erreur(os.str());
+        return false;
+    }
+
+    return true;
+}
+
+
+
+int main(int argc, char **argv)
+{
+    std::string chaine;
+
+    pthread_t th1;
+
+    if (argc >1)
+    {
+        if (strstr(argv[1], "-h")!=NULL)
+        {
+            std::cout << "usage :\n \
+       BAOControl -h ou --help : affiche l'aide\n \
+       BAOControl -r FileName : execute les mouvements dÃ©finis dans le fichier FileName\n\n";
+
+            return 0;
+        }
+    }
+
+    for (int i=0; i<MAXANTENNES; i++)
+    {
+        Antennes[i].ok=0;
+        Antennes[i].ip=0;
+    }
+
+    for (int i=0; i<MAXOBJETS; i++)
+    {
+        objets[i].JJ=0;
+        objets[i].exec=false;
+    }
+
+
+    Affiche("\n\n\n\n\n\n \
+    ************************\n \
+    *      BAO Control     *\n \
+    *         v0.1         *\n \
+    *      10/11/2010      *\n \
+    ************************\n\n", true);
+
+    if (!ChargementParametres())
+    {
+        Erreur("Le fichier de configuration 'params' contient des erreurs ou n'existe pas. Merci de vÃ©rifier.\n");
+        exit(1);
+    }
+
+    client_socket = new ClientSocket("localhost", Port );
+
+    
+    Connect(true);
+
+    if (argc == 1)  std::cout << "Tapez help pour obtenir des infos sur les commandes disponibles.\n" << std::endl;
+
+    initialiserFenetre();
+
+    XSelectInput(d,w, ExposureMask );
+
+    if (pthread_create(&th1, NULL, my_thread_process, NULL) < 0) {
+        Erreur("Impossible de crÃ©er le thread\n");
+        exit (1);
+    }
+    
+    astro = new Astro();
+
+    if (argc == 3)
+    {
+        if (strstr(argv[1], "-r")!=NULL)
+        {
+            exitrun=true;
+
+            Run(argv[2]);
+
+            do
+            {
+
+            } while (NoExit);
+        }
+        else
+        {
+            Erreur("Usage incorrect\n\n");
+        }
+    }
+    else
+    {
+
+        do
+        {
+            std::cout << blue << '>';
+            getline(std::cin, chaine);
+            std::cout << black;
+
+            for (int i=0; i<chaine.size();++i) chaine[i] = tolower(chaine[i]);
+
+            DecodageEntreesUtilisateur(chaine);
+        }
+        while (NoExit);
+    }
+
+    delete astro;
+    delete client_socket;
+
+    return 0;
+}
Index: /BAORadio/libindi/libindi/BAOControl/baocontrol.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/baocontrol.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/baocontrol.h	(revision 502)
@@ -0,0 +1,97 @@
+#include <iostream>
+#include <string.h>
+#include <sstream>
+#include "ClientSocket.h"
+#include "SocketException.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <X11/Xlib.h>
+#include "filetools.h"
+#include "astro.h"
+#include "math.h"
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+#define red "\033[0;31m"
+#define blue "\033[0;34m"
+#define green "\033[0;32m"
+#define black "\033[0;30m"
+
+#define MAXLOG 1000
+#define MAXOBJETS 100
+#define MAXANTENNES 100
+
+#define larg 600
+#define haut 10+30*12
+
+using namespace std;
+
+
+struct DefAntenne
+{
+    unsigned char ip;
+
+    char ok;
+};
+
+struct DefObjets
+{
+    double JJ;
+    double Duree;
+    char ad[10];
+    char de[10];
+    bool exec;
+};
+
+
+char Latitude[80];
+char Longitude[80];
+char Serveur[80];
+
+std::string logs[MAXLOG];
+
+std::stringstream os;
+
+int Port=0;
+int delaitransit=0;
+int delaitracking=0;
+int lognum=0;
+int numAntenne=0;
+int numobjets=0;
+int runnum=1;
+
+struct DefAntenne Antennes[MAXANTENNES];
+struct DefObjets objets[MAXOBJETS];
+
+bool NoExit=true;
+bool Transit=false;
+bool run=false;
+bool exitrun=false;
+
+ClientSocket *client_socket;
+Astro *astro;
+
+Display * d;
+Window w;
+Pixmap db;
+GC noir, vert, rouge, gris;
+
+
+void initialiserFenetre();
+void Dessiner();
+void rouler(char* reponse);
+void LireReponse();
+void *my_thread_process (void * arg);
+bool Decomposition(std::string chaine, char type, float *a1, float *a2, float *a3);
+bool DecompositionCommande(std::string chaine, std::string commande, std::string *chaine1, std::string *chaine2);
+bool EncoyerCoordGeographiques();
+bool Connect(bool connect);
+bool Park();
+bool Abort();
+bool Goto(std::string ar, std::string dec, bool Transit);
+bool LectureFichierMouvements(char * fileName);
+bool Run(std::string fichier);
+void DecodageFonction(std::string chaine);
+bool ChargementParametres(); 
Index: /BAORadio/libindi/libindi/BAOControl/exception.c
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/exception.c	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/exception.c	(revision 502)
@@ -0,0 +1,36 @@
+/* exception.c */
+/* fonctions de manipulation de la pile */
+
+#include "exception.h"
+
+except *_exceptions = NULL;
+
+/* empile */
+
+void push_exc(){
+  except* layer;
+  layer = (except*) malloc(sizeof(except));
+  if(layer == NULL){
+    fprintf(stderr,"[push_exc()]Erreur d'allocation memoire pour la pile");
+  }
+  layer->super = _exceptions;
+  _exceptions = layer;
+}
+
+/* depile */
+
+void pop_exc(int ex){
+  except* super;
+  super = _exceptions->super;
+  free(_exceptions);
+  _exceptions = super;
+  if(ex){
+    if(_exceptions){
+      longjmp(_exceptions->ctx, ex);
+    }
+    else{
+      fprintf(stderr, "Exception non geree : %d\n", ex);
+      exit(-1);
+    }
+  }
+}
Index: /BAORadio/libindi/libindi/BAOControl/exception.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/exception.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/exception.h	(revision 502)
@@ -0,0 +1,54 @@
+/* exception.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#ifndef __EXCEPTION__
+#define __EXCEPTION__  1
+
+/* exceptions de base */
+
+#define ERR_MALLOC     10
+#define NULL_POINTEUR  11
+#define ERR_FOPEN      12
+
+/*prototypes*/
+
+/* definition des structures de donnees de gestion de la pile des contextes 
+   et des macros TRY, CATCH, et ENDTRY */
+
+
+/* liste chainee des contextes */
+typedef struct except_ctx 
+{
+  jmp_buf ctx;
+  struct except_ctx* super;
+} except;
+extern except* _exceptions;
+
+/* les macros */
+#define TRY { \
+  int exc; \
+  push_exc(); \
+  exc = setjmp(_exceptions->ctx); \
+  switch(exc){ \
+  case 0:
+
+#define CATCH(X) \
+  break; \
+  case(X): \
+  exc = 0;
+
+#define ENDTRY \
+  break; \
+  default: \
+  pop_exc(exc); }\
+  }
+
+#define THROW(X) longjmp(_exceptions->ctx, X)
+
+
+void push_exc();
+void pop_exc(int);
+
+#endif
Index: /BAORadio/libindi/libindi/BAOControl/filetools.c
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/filetools.c	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/filetools.c	(revision 502)
@@ -0,0 +1,1066 @@
+/*filetools.c*/
+
+#include "filetools.h"
+
+#define MAX_LENGHT 255
+
+/******************************************************
+ * NOM:              readINI                          *
+ * SPECIFICATION:                                     *
+ *   retourne la valeur de la cle du                  *
+ *               fichier dont la structure est celle  *
+ *               d'un fichier .ini windows            *
+ * ARGUMENTS:                                         *
+ * >section: le nom de la section sans les crochets   *
+ * >key: nom de la cle de la section                  *
+ * >pStr: pointeur pour mettre le resultat            *
+ *       allocation memoire effectuee                 *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:0 si echec 1 si oui               *
+ ******************************************************/
+int
+readINI (char *sectionName, char *pKeyName, char **ppStr, char *fileName)
+{
+  INI *pIni = NULL;
+  SECTION *pSection = NULL;
+  KEY *pKey = NULL;
+  int trouve = 0;
+  char *pSectionName = NULL;
+  int offset = 0;
+  //pStr = resultValue;
+  TRY
+  {
+    trouve = 0;
+    pIni = _loadINI (fileName);
+    /*recherche de la section */
+    offset = strlen (sectionName) + 3;
+    pSectionName = (char *) m_malloc (sizeof (char) * offset);
+    pSectionName[0] = '[';
+    strcpy (pSectionName + 1, sectionName);
+    pSectionName[strlen (sectionName) + 1] = ']';
+    pSectionName[offset - 1]='\0';
+
+    pSection = _findSECTION (pIni, pSectionName);
+
+    if (pSection != NULL)
+      {
+        /*recherche de la cle */
+        pKey = _findKEY (pSection, pKeyName);
+        if (pKey != NULL)
+        {
+          *ppStr = (char *) m_malloc (sizeof (char) * strlen (pKey->value) + 2);
+          strcpy (*ppStr, pKey->value);
+          (*ppStr)[strlen (pKey->value)] = '\0';
+          trouve = 1;
+        }
+      }
+  }
+  CATCH (ERR_FOPEN)
+  {
+    printf ("impossible d'ouvrir le fichier %s\n", fileName);
+    ppStr = NULL;
+  }
+  CATCH (ERR_MALLOC)
+  {
+    perror ("Probleme d'allocation memoire");
+    exit (EXIT_FAILURE);
+  }  
+  ENDTRY;
+  
+  
+  return trouve;
+}
+
+/******************************************************
+ * NOM:                delINI                         *
+ * SPECIFICATION:                                     *
+ *  seule la cle de la section est supprimee          *
+ *  si la section est vide, elle est supprimee        *
+ * ARGUMENTS:                                         *
+ * >section: le nom de la section sans les crochets   *
+ * >key: nom de la cle de la section                  *
+ * >pStr: pointeur pour mettre la valeur de la cle    *
+ *       avant sa suppression                         *
+ *       allocation memoire effectuee                 *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * 1 si reussite de la suppression, 0 sinon           *
+ ******************************************************/
+int
+delINI (char *sectionName, char *pKeyName, char **ppStr, char *fileName)
+{
+  INI *pIni = NULL;
+  SECTION *pSection = NULL;
+  KEY *pKey = NULL;
+  int del = 0;
+  char *pSectionName = NULL;
+  int offset = 0;
+  //pStr = resultValue;
+  TRY
+  {
+
+    pIni = _loadINI (fileName);
+    /*recherche de la section */
+    offset = strlen (sectionName) + 3;
+    pSectionName = (char *) m_malloc (sizeof (char) * offset);
+    pSectionName[0] = '[';
+    strcpy (pSectionName + 1, sectionName);
+    pSectionName[strlen (sectionName) + 1] = ']';
+    pSectionName[offset - 1];
+
+    pSection = _findSECTION (pIni, pSectionName);
+
+    if (pSection != NULL)
+      {
+	if (pKeyName == NULL)
+	  {
+	    /*on supprime toute la section */
+
+	    pKey = _lastKEY (pSection);
+	    while (pKey != NULL)
+	      {
+		_delKEY (pKey);
+		pKey = _lastKEY (pSection);
+	      }
+	    _delSECTION (pSection);
+	    del = 1;
+	  }
+	else
+	  {
+	    /*recherche de la cle si indiquee */
+	    pKey = _findKEY (pSection, pKeyName);
+	    if (pKey != NULL)
+	      {
+		(*ppStr) =
+		  (char *) m_malloc (sizeof (char) * strlen (pKey->value) +
+				     2);
+		strcpy (*ppStr, pKey->value);
+		(*ppStr)[strlen (pKey->value)] = '\0';
+		if (_delKEY (pKey))
+		  {
+		    /*si la cle supprimee etait la derniere de la section */
+		    _delSECTION (pSection);
+		  }
+		del = 1;
+	      }
+	  }
+      }
+    if (del)
+      {
+	_saveINI (pIni);
+      }
+  }
+  CATCH (ERR_FOPEN)
+  {
+    printf ("impossible d'ouvrir le fichier %s\n", fileName);
+    (*ppStr) = NULL;
+  }
+  CATCH (ERR_MALLOC)
+  {
+    perror ("Probleme d'allocation memoire");
+    exit (EXIT_FAILURE);
+  }
+  ENDTRY;
+
+  return del;
+}
+
+/******************************************************
+ * NOM:                writeINI                       *
+ * SPECIFICATION:                                     *
+ *  si la section n'existe pas elle est cree          *
+ *  si la cle n'existe pas elle est cree              *
+ *  et la valeur de la cle est initialisee            *
+ *  sinon la cle existante de la section existante est*
+ *  mise a jour                                       * 
+ * ARGUMENTS:                                         *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ *  NULL si echec ou keyValue si reussite             *
+ ******************************************************/
+char *
+writeINI (char *sectionName, char *keyName, char *keyValue, char *fileName)
+{
+  char *pSectionName = NULL;
+  char *pKeyName = NULL;
+  char *pKeyValue = NULL;
+  INI *pIni = NULL;
+  SECTION *pSection = NULL;
+  KEY *pKey = NULL;
+  TRY
+  {
+    pKeyName = (char *) m_malloc (sizeof (char) * strlen (keyName) + 1);
+    pSectionName =
+      (char *) m_malloc (sizeof (char) * strlen (sectionName) + 3);
+    if (keyValue != NULL)
+      {
+	pKeyValue = (char *) m_malloc (sizeof (char) * strlen (keyValue) + 1);
+	strcpy (pKeyValue, keyValue);
+	pKeyValue[strlen (keyValue)] = '\0';
+      }
+    else
+      {
+	pKeyValue = (char *) m_malloc (sizeof (char));
+	pKeyValue[0] = '\0';
+      }
+    strcpy (pKeyName, keyName);
+    pSectionName[0] = '[';
+    strcpy (pSectionName + 1, sectionName);
+    pSectionName[strlen (sectionName) + 1] = ']';
+    pSectionName[strlen (sectionName) + 2] = '\0';
+    /*chargement */
+    pIni = _loadINI (fileName);
+
+  }
+  CATCH (ERR_FOPEN)
+  {
+    printf ("Erreur en ouvrant le fichier .ini:%s\n", fileName);
+    exit (EXIT_FAILURE);
+  }
+  CATCH (ERR_MALLOC)
+  {
+    perror ("Probleme d'allocation memoire");
+    exit (EXIT_FAILURE);
+  }
+  ENDTRY;
+
+  /*recherche de la section */
+  pSection = _findSECTION (pIni, pSectionName);
+  /*recherche de la cle */
+  if (pSection != NULL)
+    {
+      pKey = _findKEY (pSection, pKeyName);
+      if (pKey != NULL)
+	{
+	  pKey->value =
+	    (char *) realloc (pKey->value,
+			      sizeof (char) * strlen (pKeyName) + 1);
+	  if (pKey->value == NULL)
+	    {
+	      perror ("probleme de reallocation memoire");
+	      exit (EXIT_FAILURE);
+	    }
+	  strcpy (pKey->value, pKeyValue);
+	}
+      else
+	{
+	  /*cle pas trouve dans la section, on ajoute la cle a la section */
+	  pKey = _newKEY (pKeyName, pKeyValue);
+	  _addKEY (pSection, pKey);
+	}
+    }
+  else
+    {
+      /*section pas trouve, on la cree avec sa cle */
+      pSection = _newSECTION (pSectionName);
+      _addSECTION (pIni, pSection);
+      pKey = _newKEY (pKeyName, pKeyValue);
+      _addKEY (pSection, pKey);
+
+    }
+  TRY
+  {
+
+    /*sauvegarde */
+    _saveINI (pIni);
+
+  }
+  CATCH (ERR_FOPEN)
+  {
+    printf ("erruer sur le fichier %s", pIni->fileName);
+  }
+  ENDTRY;
+
+  /*nettoyage */
+
+  free (pIni);
+  free (pSection);
+  free (pKey);
+  free (pKeyName);
+  free (pSectionName);
+  pIni = NULL;
+  pKeyName = NULL;
+  pSectionName = NULL;
+  return pKeyValue;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _delKEY                            *
+ * SPECIFICATION:                                     *
+ * ARGUMENTS:                                         *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ *  1 si derniere cellule, 0 sinon, -1 si probleme    *
+ ******************************************************/
+int
+_delKEY (KEY * pKey)
+{
+  int result = 0;
+  if (pKey != NULL)
+    {
+      /*la cle n'est pas la premiere */
+      if (pKey->prev != pKey)
+	{
+	  if (pKey->next != pKey)
+	    {
+	      /*la cle n'est pas la derniere */
+	      pKey->prev->next = pKey->next;
+	    }
+	  else
+	    {
+	      result = 1;
+	      pKey->prev->next = pKey->prev;
+	    }
+	}
+      else
+	{
+	  if (pKey->next != pKey)
+	    {
+	      /*la cle n'est pas non plus la derniere */
+	      pKey->parent->fils = pKey->next;
+	    }
+	  else
+	    {
+	      result = 1;
+	      pKey->parent->fils = NULL;
+	    }
+	}
+      _freeKEY (pKey);
+      return result;
+    }
+  else
+    {
+      result = -1;
+      return result;
+    }
+}
+
+
+/******************************************************
+ * NOM:                                               *
+ *                 _delSECTION                        *
+ * SPECIFICATION:                                     *
+ * ARGUMENTS:                                         *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ *  pointeur sur la section                           *
+ ******************************************************/
+int
+_delSECTION (SECTION * pSection)
+{
+  if (pSection != NULL)
+    {
+      /*la cle n'est pas la premiere */
+      if (pSection->prev != pSection)
+	{
+	  /*la cle n'est pas la derniere */
+	  if (pSection->next != pSection)
+	    {
+	      pSection->prev->next = pSection->next;
+	    }
+	  else
+	    {
+	      pSection->prev->next = pSection->prev;
+	    }
+	}
+      else
+	{
+	  /*la cle n'estpas nonplus la derniere */
+	  if (pSection->next != pSection)
+	    {
+	      pSection->parent->fils = pSection->next;
+	      pSection->next->prev = pSection->next;
+	    }
+	  else
+	    {
+	      pSection->parent->fils = NULL;
+	    }
+	}
+      _freeSECTION (pSection);
+      return 1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+/************************
+ * liberation memoire   *
+ ************************/
+void
+_freeKEY (KEY * pKey)
+{
+  if (pKey != NULL)
+    {
+      pKey->parent = NULL;
+      pKey->next = NULL;
+      pKey->prev = NULL;
+      if (pKey->value != NULL)
+	{
+	  free (pKey->value);
+	}
+      if (pKey->name != NULL)
+	{
+	  free (pKey->name);
+	}
+      free (pKey);
+    }
+}
+void
+_freeSECTION (SECTION * pSection)
+{
+  if (pSection != NULL)
+    {
+      pSection->parent = NULL;
+      pSection->next = NULL;
+      pSection->prev = NULL;
+      if (pSection->name != NULL)
+	{
+	  free (pSection->name);
+	}
+      free (pSection);
+    }
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _newKEY                            *
+ * SPECIFICATION:                                     *
+ *  allocation d'une nouvelle cle                     *
+ * ARGUMENTS:                                         *
+ * le nom et la valeur de la cle                      *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la cle, NULL sinon                    *
+ ******************************************************/
+KEY *
+_newKEY (char *pKeyName, char *pKeyValue)
+{
+  KEY *pKey;
+  TRY
+  {
+    pKey = (KEY *) m_malloc (sizeof (KEY));
+
+    pKey->name = (char *) m_malloc (sizeof (char) * strlen (pKeyName) + 1);
+    pKey->value = (char *) m_malloc (sizeof (char) * strlen (pKeyValue) + 1);
+  }
+  CATCH (ERR_MALLOC)
+  {
+    perror ("Probleme d'allocation memoire");
+    exit (EXIT_FAILURE);
+  }
+  ENDTRY;
+
+  strcpy (pKey->name, pKeyName);
+  strcpy (pKey->value, pKeyValue);
+  pKey->parent = NULL;
+  pKey->prev = pKey;
+  pKey->next = pKey;
+
+
+  return pKey;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _newSECTION                        *
+ * SPECIFICATION:                                     *
+ *  allocation d'une nouvelle section                 *
+ * ARGUMENTS:                                         *
+ * le nom de la section                               *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la section, NULL sinon                *
+ ******************************************************/
+SECTION *
+_newSECTION (char *pSectionName)
+{
+  SECTION *pSection;
+  TRY
+  {
+    pSection = (SECTION *) m_malloc (sizeof (SECTION));
+
+    pSection->name =
+      (char *) m_malloc (sizeof (char) * strlen (pSectionName) + 1);
+  }
+  CATCH (ERR_MALLOC)
+  {
+    perror ("Probleme d'allocation memoire");
+    exit (EXIT_FAILURE);
+  }
+  ENDTRY;
+
+  strcpy (pSection->name, pSectionName);
+  pSection->parent = NULL;
+  pSection->fils = NULL;
+  pSection->prev = pSection;
+  pSection->next = pSection;
+  return pSection;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _findSECTION                       *
+ * SPECIFICATION:                                     *
+ *  trouver la section dans une struture INI          *
+ * ARGUMENTS:                                         *
+ * la structure INI, le nom de la section avec ses [ ]*
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la section, NULL sinon                *
+ ******************************************************/
+SECTION *
+_findSECTION (INI * pIni, char *pSectionName)
+{
+  SECTION *pSection = NULL;
+  pSection = pIni->fils;
+  while ((pSection != NULL) && (strcmp (pSection->name, pSectionName) != 0))
+    {
+      if (pSection == pSection->next)
+	{
+	  pSection = NULL;
+	}
+      else
+	{
+	  pSection = pSection->next;
+	}
+    }
+  return pSection;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _findKEY                           *
+ * SPECIFICATION:                                     *
+ *  trouver la cle dans une struture SECTION          *
+ * ARGUMENTS:                                         *
+ * la structure SECTION, le nom de la cle             *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la cle, NULL sinon                    *
+ ******************************************************/
+KEY *
+_findKEY (SECTION * pSection, char *pKeyName)
+{
+  KEY *pKey = NULL;
+  pKey = pSection->fils;
+  while ((pKey != NULL) && (strcmp (pKey->name, pKeyName) != 0))
+    {
+      if (pKey == pKey->next)
+	{
+	  pKey = NULL;
+	}
+      else
+	{
+	  pKey = pKey->next;
+	}
+    }
+  return pKey;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _lastKEY                           *
+ * SPECIFICATION:                                     *
+ *  trouver la derniere cle dans une struture SECTION *
+ * ARGUMENTS:                                         *
+ * la structure SECTION                               *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la cle, NULL sinon                    *
+ ******************************************************/
+KEY *
+_lastKEY (SECTION * pSection)
+{
+  KEY *pKey_pred = NULL;
+  KEY *pKey = NULL;
+  pKey = pSection->fils;
+  pKey_pred = pKey;
+  while (pKey != NULL)
+    {
+      pKey_pred = pKey;
+      if (pKey == pKey->next)
+	{
+	  pKey = NULL;
+	}
+      else
+	{
+	  pKey = pKey->next;
+	}
+    }
+  return pKey_pred;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _lastSECTION                       *
+ * SPECIFICATION:                                     *
+ *  trouver la derniere section dans une INI          *
+ * ARGUMENTS:                                         *
+ * la structure INI                                   *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la section, NULL sinon                *
+ ******************************************************/
+SECTION *
+_lastSECTION (INI * pIni)
+{
+  SECTION *pSection_pred = NULL;
+  SECTION *pSection = NULL;
+  pSection = pIni->fils;
+  pSection_pred = pSection;
+  while (pSection != NULL)
+    {
+      pSection_pred = pSection;
+      if (pSection == pSection->next)
+	{
+	  pSection = NULL;
+	}
+      else
+	{
+	  pSection = pSection->next;
+	}
+    }
+  return pSection_pred;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _addSECTION                        *
+ * SPECIFICATION:                                     *
+ *  ajoute une section en derniere place dans une INI *
+ *  la section ne doit pas appartenir a une INI       *
+ * ARGUMENTS:                                         *
+ * la structure INI, la structure SECTION             * 
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la section, NULL sinon                *
+ ******************************************************/
+SECTION *
+_addSECTION (INI * pIni, SECTION * pSection)
+{
+  SECTION *pSection_last = NULL;
+
+  if (pSection->parent != NULL)
+    {
+      return NULL;
+    }
+  else
+    {
+      pSection_last = _lastSECTION (pIni);
+      pSection->parent = pIni;
+      if (pSection_last != NULL)
+	{
+	  pSection_last->next = pSection;
+	  pSection->prev = pSection_last;
+	}
+      else
+	{
+	  pIni->fils = pSection;
+	}
+      return pSection;
+    }
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _addKEY                            *
+ * SPECIFICATION:                                     *
+ *  ajoute une cle en derniere place dans une SECTION *
+ *  la section ne doit pas appartenir a une SECTION   *
+ * ARGUMENTS:                                         *
+ * la structure KEY, la structure SECTION             *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * pointeur sur la cle, NULL sinon                *
+ ******************************************************/
+KEY *
+_addKEY (SECTION * pSection, KEY * pKey)
+{
+  KEY *pKey_last = NULL;
+
+  if (pKey->parent != NULL)
+    {
+      return NULL;
+    }
+  else
+    {
+
+      pKey_last = _lastKEY (pSection);
+      pKey->parent = pSection;
+      if (pKey_last != NULL)
+	{
+	  pKey_last->next = pKey;
+	  pKey->prev = pKey_last;
+	}
+      else
+	{
+	  pSection->fils = pKey;
+	}
+      pKey->next = pKey;
+      return pKey;
+    }
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 saveINI                            *
+ * SPECIFICATION:                                     *
+ *  sauvegarde de la structure INI dans son fichier   *
+ *  Attention, ecrase l'ancien fichier                *
+* ARGUMENTS:                                         *
+*  pointeur sur la structure INI a sauvegarder       *
+* ENVIRONNEMENT:                                     *
+* VALEUR RETOURNEE:                                  *
+*  -1 si un probleme a eu lieu, 0 sinon              *
+******************************************************/
+int
+_saveINI (INI * pIni)
+{
+  FILE *pFile = NULL;
+  char *str = NULL;
+  SECTION *pSection_pred = NULL, *pSection = NULL;
+  KEY *pKey_pred = NULL, *pKey = NULL;
+  int offset = 0;
+
+  pFile = fopen (pIni->fileName, "w");
+  if (pFile == NULL)
+    THROW (ERR_FOPEN);
+  //printf("#SAUVEGARDE Fichier INI#\n");
+  //printf("# %s #\n\n",pIni->fileName);
+  if (pIni->fils != NULL)
+    {
+      pSection = pIni->fils;
+      do
+	{
+
+	  fprintf (pFile, pSection->name);
+	  fprintf (pFile, "\n");
+	  pKey = pSection->fils;
+	  do
+	    {
+
+	      offset = strlen (pKey->name) + strlen (pKey->value) + 2;
+
+	      TRY
+	      {
+		str = (char *) m_malloc (sizeof (char) * offset);
+	      }
+	      CATCH (ERR_MALLOC)
+	      {
+		perror ("probleme d'allocation memoire");
+		exit (EXIT_FAILURE);
+	      }
+	      ENDTRY;
+	      memset (str, 0, offset);
+	      strcpy (str, pKey->name);
+	      offset = strlen (pKey->name);
+	      strcpy (str + offset, "=");
+	      offset = strlen (pKey->name) + 1;
+	      strcpy (str + offset, pKey->value);
+	      fprintf (pFile, str);
+	      fprintf (pFile, "\n");
+	      pKey_pred = pKey;
+	      pKey = pKey->next;
+	      free (str);
+	    }
+	  while (pKey != pKey_pred);
+
+	  pSection_pred = pSection;
+	  pSection = pSection->next;
+	}
+      while (pSection != pSection_pred);
+    }
+  /*nettoyage */
+  fclose (pFile);
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                  loadINI                           *
+ * SPECIFICATION:                                     *
+ *  Charge le contenu d'un fichier .ini en memoire    *
+ * ARGUMENTS:                                         *
+ *  nom du fichier                                    *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ *  pointeur sur la structure INI contenant le fichier*
+ *  .ini avec les structures decrites dans le .h      *
+ * EXCEPTION:                                         *
+ * ERR_FOPEN, ERR_MALLOC
+ ******************************************************/
+INI *
+_loadINI (char *fileName)
+{
+  FILE *pFile = NULL;
+  char *pBuf;
+  int nbRead = 0;
+  SECTION *pSection = NULL;
+  KEY *pKey = NULL;
+
+  INI *pIni = NULL;
+  pBuf = (char *) m_malloc (sizeof (char) * MAX_LENGHT);
+
+  pFile = fopen (fileName, "r");
+  if (pFile == NULL)
+    {
+      pFile = fopen (fileName, "a");
+      if (pFile == NULL)
+	THROW (ERR_FOPEN);	/*encore NULL !!? la! il y a vraiment un probleme !! */
+    }
+
+  pIni = (INI *) m_malloc (sizeof (INI));
+  pIni->fileName = (char *) m_malloc (sizeof (char) * strlen (fileName) + 1);
+  strcpy (pIni->fileName, fileName);
+  pIni->fils = NULL;
+  /* on lit ligne par ligne */
+  nbRead = readline (pFile, pBuf);
+  while (nbRead != -1)
+    {
+
+      if ((pBuf[0] == '[') && (pBuf[strlen (pBuf) - 1] == ']'))
+	{
+	  /* une section */
+	  pSection = NULL;
+
+	  pSection = _newSECTION (pBuf);
+	  _addSECTION (pIni, pSection);
+	}
+
+      /* les cles de la section */
+      while (((nbRead = readline (pFile, pBuf)) !=-1) && (pBuf[0] != '['))
+	{
+	  int ind = 0;
+	  pKey = NULL;
+	  if ((ind = _isKey (pBuf)) >= 0)
+	    {
+
+	      char *strName = NULL;
+	      strName = (char *) m_malloc (sizeof (char) * ind + 1);
+	      strncpy (strName, pBuf, ind);
+	      strName[ind] = '\0';
+	      pKey = _newKEY (strName, pBuf + ind + 1);
+	      _addKEY (pSection, pKey);
+	    }
+	}
+    }
+
+  /*nettoyage */
+  free (pBuf);
+  fclose (pFile);
+  return pIni;
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                 _isKey                             *
+ * SPECIFICATION:                                     *
+ *  determine si une chaine est une cle valide        *
+ * ARGUMENTS:                                         *
+ *  pointeur sur la chaine                            *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ *  indice du signe '=' si oui, -1 sinon              *
+ ******************************************************/
+int
+_isKey (char *str)
+{
+  int ind = 0;
+  for (ind; (ind < strlen (str)) && (str[ind] != '='); ind++);
+  if (str[ind] == '=')
+    return ind;
+  else
+    return -1;
+}
+
+
+/******************************************************
+ * NOM:                                               *
+ *                  _printINI                         *
+ * SPECIFICATION:                                     *
+ * affiche a l'ecran le contenu de structure INI      *
+ * ARGUMENTS:                                         *
+ *  pointeur sur la structure INI                     *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ ******************************************************/
+void
+_printINI (INI * pIni)
+{
+  SECTION *pSection_pred = NULL;
+  SECTION *pSection = NULL;
+  printf ("#Fichier INI#\n");
+  printf ("# %s #\n\n", pIni->fileName);
+  pSection = pIni->fils;
+  if (pSection != NULL)
+    {
+      do
+	{
+	  _printSECTION (pSection);
+	  pSection_pred = pSection;
+	  pSection = pSection->next;
+	}
+      while (pSection != pSection_pred);
+    }
+  printf ("\n#Fin du fichier INI#\n");
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                  _printSECTION                     *
+ * SPECIFICATION:                                     *
+ * affiche a l'ecran le contenu de structure SECTION  *
+ * ARGUMENTS:                                         *
+ *  pointeur sur la structure SECTION                 *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ ******************************************************/
+void
+_printSECTION (SECTION * pSection)
+{
+  KEY *pKey = NULL;
+  KEY *pKey_pred = NULL;
+  printf ("%s\n", pSection->name);
+  pKey = pSection->fils;
+  if (pKey != NULL)
+    {
+      do
+	{
+	  _printKEY (pKey);
+	  pKey_pred = pKey;
+	  pKey = pKey->next;
+	}
+      while (pKey != pKey_pred);
+    }
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                  _printKEY                         *
+ * SPECIFICATION:                                     *
+ * affiche a l'ecran le contenu de structure SECTION  *
+ * ARGUMENTS:                                         *
+ *  pointeur sur la structure SECTION                 *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ ******************************************************/
+void
+_printKEY (KEY * pKey)
+{
+  printf ("%s=%s\n", pKey->name, pKey->value);
+}
+
+/******************************************************
+ * NOM:                                               *
+ *                  printINI                          *
+ * SPECIFICATION:                                     *
+ * affiche a l'ecran le contenu du fichier .ini       *
+ * ARGUMENTS:                                         *
+ *  nom du fichier                                    *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ ******************************************************/
+void
+printINI (char *file)
+{
+  INI *pIni = NULL;
+  TRY
+  {
+    pIni = _loadINI (file);
+  }
+  CATCH (ERR_MALLOC)
+  {
+    printf ("Erreur d'allocation memoire en chargeant le fichier .ini:%s\n",
+	    file);
+    exit (EXIT_FAILURE);
+  }
+  CATCH (ERR_FOPEN)
+  {
+    printf ("Erreur en ouvrant le fichier .ini:%s\n", file);
+    exit (EXIT_FAILURE);
+  }
+  ENDTRY;
+  _printINI (pIni);
+  free (pIni);
+}
+
+/******************************************************
+ * NOM:                 jumpline                      *
+ * SPECIFICATION:                                     *
+ * fonction permettant de sauter des lignes dans le   *
+ * fichier a partir de la position courante dans le   *
+ * fichier                                            *
+ * ARGUMENTS:                                         *
+ * nombre de lignes a saute, pointeur sur le fichier  *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE: nombre de lignes sautees         *
+ ******************************************************/
+
+int
+jumpline (int nbline, FILE * pfile)
+{
+  int compteur = 0, c;
+
+  while ((compteur < nbline) && ((c = getc (pfile)) != EOF))
+    {
+      if (c == '\n')
+	compteur++;
+    }
+  return (compteur);
+}
+
+/******************************************************
+ * NOM:                readline                       *
+ * SPECIFICATION:                                     *
+ * recupere la ligne courante du fichier et renvoie le*
+ * nombre de caracteres lus                           *
+ * ARGUMENTS:                                         *
+ * pointeur sur le fichier a lire                     *
+ * pointeur sur le tableau recevant la ligne          *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ * nombre de caracteres lus                           *
+ ******************************************************/
+int
+readline (FILE * pfile, char *tab)
+{
+  int nbchar = 0;
+  char c;
+  while ((c = getc (pfile)) != '\n')
+    {
+      if (c == EOF)
+	{
+	  break;	  
+	}
+      tab[nbchar++] = c;
+    }
+  tab[nbchar] = '\0';
+  
+  while (nbchar>0 && tab[nbchar-1]==' ') { tab[--nbchar] = '\0';}
+  
+  while (tab[0]==' ') for (int i=1; i<=nbchar; i++) tab[i-1]=tab[i];
+  
+  if (c == EOF) nbchar=-1;
+  
+  return (nbchar);
+}
+
+/******************************************************
+ * NOM:                m_malloc                       *
+ * SPECIFICATION:                                     *
+ *  clone de malloc renvoyant une exception           *
+ * ARGUMENTS:                                         *
+ * ENVIRONNEMENT:                                     *
+ * VALEUR RETOURNEE:                                  *
+ ******************************************************/
+void *
+m_malloc (size_t size)
+{
+  void *ptr = malloc (size);
+  if (ptr == NULL)
+    THROW (ERR_MALLOC);
+  else
+    return ptr;
+}
Index: /BAORadio/libindi/libindi/BAOControl/filetools.h
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/filetools.h	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/filetools.h	(revision 502)
@@ -0,0 +1,109 @@
+/*******************************************************
+                          filetools.h
+                          -----------
+    begin                : Wed Dec 13 2000
+    copyright            : (C) 2000 by Sylvain Le Petit 
+    email                : sylvainlepetit@wanadoo.fr
+ *******************************************************/
+#include <stdio.h>
+#include <string.h>
+#include "exception.h"
+/* Structures de donnees */
+
+
+typedef struct section
+{
+  char *name;
+  struct key *fils;
+  struct ini *parent;
+  struct section *prev;
+  struct section *next;
+
+}
+SECTION;
+
+typedef struct key
+{
+  char *name;
+  char *value;
+  SECTION *parent;
+  struct key *prev;
+  struct key *next;
+}
+KEY;
+
+typedef struct ini
+{
+  char *fileName;
+  SECTION *fils;
+}
+INI;
+
+/* declaration des prototypes*/
+ /*PUBLIC*/ int jumpline (int nbline, FILE * pfile);
+int readline (FILE * pfile, char *tab);
+/*************************************************************************
+gestion des fichier .ini
+**************************************************************************/
+
+int readINI (char *section, char *key, char **ppStr, char *fileName);
+/*******************************************************************************
+ lire une valeur
+
+section: nom de la section
+key : nom de la cle
+ppStr: adresse du pointeur sur la valeur de la cle retour, NULL si pas trouve, memoire allouee dans la fonction
+fileName : nom du fichier contenant les cles, pas forcement xxx.ini c'est pas obligatoire
+
+**********************************************************************************/
+
+
+char *writeINI (char *section, char *key, char *pKeyValue, char *fileName);
+/*******************************************************************************
+  ecrire une cle avec sa valeur, que se soit une nouvelle cle ou un mise a jour
+c'est pareil
+
+section: nom de la section
+key : nom de la cle
+pKeyValue: valeur de la cle, evitez de mettre NULL pas encore tester ce cas limite
+fileName : nom du fichier contenant les cles, pas forcement xxx.ini c'est pas obligatoire
+
+ *******************************************************************************/
+
+int delINI (char *sectionName, char *pKeyName, char **ppStr, char *fileName);
+/*************************************************************************/
+/* permet de supprimer une cle ou une section complete                   */
+/* >suppression d'une cle, donner le nomde la section et le nom de la cle*/
+/*  si la section est vide elle est supprimee                            */
+/* >suppression d'une section complete, mettre NULL comme nom de cle     */
+/*************************************************************************/
+
+void printINI (char *fileName);
+/*****************************************************************/
+/*  permet d'afficher le contenu du fichier .ini, seulement les: */
+/*  [section]                                                    */
+/*  cle=valeur                                                   */
+/*****************************************************************/
+
+
+
+/*PRIVATE: ne pas utiliser directement*/
+int _saveINI (INI * ini);
+INI *_loadINI (char *fileName);
+void _printINI (INI * pIni);
+void _printSECTION (SECTION * pSection);
+void _printKEY (KEY * pKey);
+KEY *_newKEY (char *pKeyName, char *pKeyValue);
+SECTION *_newSECTION (char *pSectionName);
+SECTION *_findSECTION (INI * pIni, char *pSectionName);
+KEY *_findKEY (SECTION * pSection, char *pKeyName);
+KEY *_lastKEY (SECTION * pSection);
+SECTION *_lastSECTION (INI * pIni);
+SECTION *_addSECTION (INI * pIni, SECTION * pSection);
+KEY *_addKEY (SECTION * pSection, KEY * pKey);
+int _isKey (char *str);
+void *m_malloc (size_t size);	/*renvoi l'exception ERR_MALLOC */
+void _freeKEY (KEY * pKey);
+void _freeSECTION (SECTION * pSection);
+int _delKEY (KEY * pKey);
+int _delSECTION (SECTION * pSection);
Index: /BAORadio/libindi/libindi/BAOControl/mouvements
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/mouvements	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/mouvements	(revision 502)
@@ -0,0 +1,13 @@
+[objet 1]
+date=07/11/2010
+heure=14:19:00
+duree=30
+ad=12:25:00
+de=88:00:00
+
+[objet 2]
+date=07/11/2010
+heure=14:19:31
+duree=30
+ad=00:25:00
+de=89:00:00
Index: /BAORadio/libindi/libindi/BAOControl/params
===================================================================
--- /BAORadio/libindi/libindi/BAOControl/params	(revision 502)
+++ /BAORadio/libindi/libindi/BAOControl/params	(revision 502)
@@ -0,0 +1,15 @@
+[connexion indi] 
+serveur=localhost
+port=7624 
+
+[coordonnees geographiques]
+latitude=48:41:56
+longitude=2:10:13
+
+[transit]
+delai=100
+
+[tracking]
+delai=5
+
+
Index: /BAORadio/libindi/libindi/libs/indibase/baseclient.cpp
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/baseclient.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/baseclient.cpp	(revision 502)
@@ -0,0 +1,499 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "baseclient.h"
+#include "basedriver.h"
+#include "indicom.h"
+
+#include <errno.h>
+
+#define MAXINDIBUF 64
+
+INDI::BaseClient::BaseClient()
+{
+    cServer = "localhost";
+    cPort   = 7624;
+
+}
+
+
+INDI::BaseClient::~BaseClient()
+{
+
+    disconnect();
+
+}
+
+void INDI::BaseClient::setServer(const char * hostname, unsigned int port)
+{
+    cServer = hostname;
+    cPort   = port;
+
+}
+
+void INDI::BaseClient::watchDevice(const char * deviceName)
+{
+    cDeviceNames.push_back(deviceName);
+}
+
+bool INDI::BaseClient::connect()
+{
+    struct sockaddr_in serv_addr;
+    struct hostent *hp;
+
+    /* lookup host address */
+    hp = gethostbyname(cServer.c_str());
+    if (!hp)
+    {
+        herror ("gethostbyname");
+        return false;
+    }
+
+    /* create a socket to the INDI server */
+    (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr;
+    serv_addr.sin_port = htons(cPort);
+    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+    {
+        perror ("socket");
+        return false;
+    }
+
+    /* connect */
+    if (::connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0)
+    {
+        perror ("connect");
+        return false;
+    }
+
+    /* prepare for line-oriented i/o with client */
+    svrwfp = fdopen (sockfd, "w");
+    svrrfp = fdopen (sockfd, "r");
+
+    int result = pthread_create( &listen_thread, NULL, &INDI::BaseClient::listenHelper, this);
+
+    if (result != 0)
+    {
+        perror("thread");
+        return false;
+    }
+
+    return true;
+}
+
+void INDI::BaseClient::disconnect()
+{
+    char errmsg[MAXRBUF];
+    removeDevice(NULL, errmsg);
+    if (lillp)
+        delLilXML(lillp);
+    lillp = NULL;
+    pthread_cancel(listen_thread);
+    close(sockfd);
+    if (svrwfp)
+        fclose(svrwfp);
+    svrwfp = NULL;
+    if (svrrfp)
+        fclose(svrrfp);
+    svrrfp = NULL;
+}
+
+INDI::BaseDriver * INDI::BaseClient::getDevice(const char * deviceName)
+{
+    vector<INDI::BaseDriver *>::const_iterator devi;
+    for ( devi = cDevices.begin(); devi != cDevices.end(); devi++)
+        if (!strcmp(deviceName, (*devi)->deviceName()))
+            return (*devi);
+
+    return NULL;
+}
+
+void * INDI::BaseClient::listenHelper(void *context)
+{
+  (static_cast<INDI::BaseClient *> (context))->listenINDI();
+}
+
+void INDI::BaseClient::listenINDI()
+{
+    char msg[MAXRBUF];
+    char buffer[MAXINDIBUF];
+    int n=0, err_code=0;
+
+    if (cDeviceNames.empty())
+       fprintf(svrwfp, "<getProperties version='%g'/>\n", INDIV);
+    else
+    {
+        vector<string>::const_iterator stri;
+        for ( stri = cDeviceNames.begin(); stri != cDeviceNames.end(); stri++)
+            fprintf(svrwfp, "<getProperties version='%g' device='%s'/>\n", INDIV, (*stri).c_str());
+    }
+
+    fflush (svrwfp);
+
+    lillp = newLilXML();
+
+    /* read from server, exit if find all requested properties */
+    while (1)
+    {
+        n = fread(buffer, 1, MAXINDIBUF, svrrfp);
+
+        if (n ==0)
+        {
+            if (ferror(svrrfp))
+                perror ("read");
+            else
+                fprintf (stderr,"INDI server %s/%d disconnected\n", cServer.c_str(), cPort);
+
+            serverDisconnected();
+            return;
+        }
+
+        for (int i=0; i < n; i++)
+        {
+            XMLEle *root = readXMLEle (lillp, buffer[i], msg);
+            if (root)
+            {
+                if ( (err_code = dispatchCommand(root, msg)) < 0)
+                {
+                     // Silenty ignore property duplication errors
+                     if (err_code != INDI_PROPERTY_DUPLICATED)
+                     {
+                         IDLog("Dispatch command error: %s\n", msg);
+                         prXMLEle (stderr, root, 0);
+                     }
+                }
+
+               delXMLEle (root);	/* not yet, delete and continue */
+            }
+            else if (msg[0])
+            {
+               fprintf (stderr, "Bad XML from %s/%d: %s\n%s\n", cServer.c_str(), cPort, msg, buffer);
+               return;
+            }
+        }
+    }
+}
+
+int INDI::BaseClient::dispatchCommand(XMLEle *root, char * errmsg)
+{
+    if  (!strcmp (tagXMLEle(root), "message"))
+        return messageCmd(root, errmsg);
+    else if  (!strcmp (tagXMLEle(root), "delProperty"))
+        return delPropertyCmd(root, errmsg);
+
+    /* Get the device, if not available, create it */
+    INDI::BaseDriver *dp = findDev (root, 1, errmsg);
+    if (dp == NULL)
+    {
+        strcpy(errmsg,"No device available and none was created");
+        return INDI_DEVICE_NOT_FOUND;
+    }
+
+    if ((!strcmp (tagXMLEle(root), "defTextVector"))  ||
+       (!strcmp (tagXMLEle(root), "defNumberVector")) ||
+       (!strcmp (tagXMLEle(root), "defSwitchVector")) ||
+       (!strcmp (tagXMLEle(root), "defLightVector"))  ||
+       (!strcmp (tagXMLEle(root), "defBLOBVector")))
+        return dp->buildProp(root, errmsg);
+    else if (!strcmp (tagXMLEle(root), "setTextVector") ||
+             !strcmp (tagXMLEle(root), "setNumberVector") ||
+             !strcmp (tagXMLEle(root), "setSwitchVector") ||
+             !strcmp (tagXMLEle(root), "setLightVector") ||
+             !strcmp (tagXMLEle(root), "setBLOBVector"))
+            return dp->setValue(root, errmsg);
+
+    return INDI_DISPATCH_ERROR;
+}
+
+/* delete the property in the given device, including widgets and data structs.
+ * when last property is deleted, delete the device too.
+ * if no property name attribute at all, delete the whole device regardless.
+ * return 0 if ok, else -1 with reason in errmsg[].
+ */
+int INDI::BaseClient::delPropertyCmd (XMLEle *root, char * errmsg)
+{
+    XMLAtt *ap;
+    INDI::BaseDriver *dp;
+
+    /* dig out device and optional property name */
+    dp = findDev (root, 0, errmsg);
+    if (!dp)
+        return INDI_DEVICE_NOT_FOUND;
+
+    checkMsg(root, dp);
+
+    ap = findXMLAtt (root, "name");
+
+    /* Delete property if it exists, otherwise, delete the whole device */
+    if (ap)
+        return dp->removeProperty(valuXMLAtt(ap));
+    // delete the whole device
+    else
+        return removeDevice(dp->deviceName(), errmsg);
+}
+
+int INDI::BaseClient::removeDevice( const char * devName, char * errmsg )
+{
+    std::vector<INDI::BaseDriver *>::iterator devicei = cDevices.begin();
+
+    while (devicei != cDevices.end())
+    {
+      if (devName == NULL || !strcmp(devName, (*devicei)->deviceName()))
+      {
+          cDevices.erase(devicei);
+          delete (*devicei);
+          return 0;
+      }
+
+      devicei++;
+    }
+
+    snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
+    return INDI_DEVICE_NOT_FOUND;
+}
+
+INDI::BaseDriver * INDI::BaseClient::findDev( const char * devName, char * errmsg )
+{
+
+    std::vector<INDI::BaseDriver *>::const_iterator devicei;
+
+    for (devicei = cDevices.begin(); devicei != cDevices.end(); devicei++)
+    {
+        if (!strcmp(devName, (*devicei)->deviceName()))
+         return (*devicei);
+
+    }
+
+    snprintf(errmsg, MAXRBUF, "Device %s not found", devName);
+    return NULL;
+}
+
+/* add new device */
+INDI::BaseDriver * INDI::BaseClient::addDevice (XMLEle *dep, char * errmsg)
+{
+    INDI::BaseDriver *dp;
+    XMLAtt *ap;
+    char * device_name;
+
+    /* allocate new INDI::BaseDriver */
+    ap = findXMLAtt (dep, "device");
+    if (!ap)
+    {
+        strncpy(errmsg, "Unable to find device attribute in XML element. Cannot add device.", MAXRBUF);
+        return NULL;
+    }
+
+    device_name = valuXMLAtt(ap);
+
+    dp = new INDI::BaseDriver();
+    dp->setMediator(this);
+    dp->setDeviceName(device_name);
+
+    cDevices.push_back(dp);
+
+    newDevice();
+
+    /* ok */
+    return dp;
+}
+
+INDI::BaseDriver * INDI::BaseClient::findDev (XMLEle *root, int create, char * errmsg)
+{
+    XMLAtt *ap;
+    INDI::BaseDriver *dp;
+    char *dn;
+
+    /* get device name */
+    ap = findXMLAtt (root, "device");
+    if (!ap)
+    {
+        snprintf(errmsg, MAXRBUF, "No device attribute found in element %s", tagXMLEle(root));
+        return (NULL);
+    }
+
+    dn = valuXMLAtt(ap);
+
+    dp = findDev(dn, errmsg);
+
+    if (dp)
+        return dp;
+
+    /* not found, create if ok */
+    if (create)
+        return (addDevice (root, errmsg));
+
+    snprintf(errmsg, MAXRBUF, "INDI: <%s> no such device %s", tagXMLEle(root), dn);
+    return NULL;
+}
+
+/* a general message command received from the device.
+ * return 0 if ok, else -1 with reason in errmsg[].
+ */
+int INDI::BaseClient::messageCmd (XMLEle *root, char * errmsg)
+{
+    checkMsg (root, findDev (root, 0, errmsg));
+    return (0);
+}
+
+/* add message to queue
+ * N.B. don't put carriage control in msg, we take care of that.
+ */
+void INDI::BaseClient::checkMsg (XMLEle *root, INDI::BaseDriver *dp)
+{
+    XMLAtt *ap;
+    ap = findXMLAtt(root, "message");
+
+    if (ap)
+        doMsg(root, dp);
+}
+
+/* Store msg in queue */
+void INDI::BaseClient::doMsg (XMLEle *msg, INDI::BaseDriver *dp)
+{
+    XMLAtt *message;
+    XMLAtt *time_stamp;
+    char msgBuffer[MAXRBUF];
+
+    if (dp == NULL)
+        return;
+
+    /* prefix our timestamp if not with msg */
+    time_stamp = findXMLAtt (msg, "timestamp");
+
+    if (time_stamp)
+        snprintf(msgBuffer, MAXRBUF, "%s ", valuXMLAtt(time_stamp));
+    else
+        snprintf(msgBuffer, MAXRBUF, "%s ", timestamp());
+
+    /* finally! the msg */
+    message = findXMLAtt(msg, "message");
+
+    if (!message) return;
+
+    // Prepend to the log
+   dp->addMessage(msgBuffer);
+   dp->addMessage(valuXMLAtt(message));
+   dp->addMessage("\n");
+\
+}
+
+void INDI::BaseClient::sendNewText (ITextVectorProperty *tvp)
+{
+    fprintf(svrwfp, "<newTextVector\n");
+    fprintf(svrwfp, "  device='%s'\n", tvp->device);
+    fprintf(svrwfp, "  name='%s'\n>", tvp->name);
+
+    for (int i=0; i < tvp->ntp; i++)
+    {
+        fprintf(svrwfp, "  <oneText\n");
+        fprintf(svrwfp, "    name='%s'>\n", tvp->tp[i].name);
+        fprintf(svrwfp, "      %s\n", tvp->tp[i].text);
+        fprintf(svrwfp, "  </oneText>\n");
+    }
+    fprintf(svrwfp, "</newTextVector>\n");
+
+    fflush(svrwfp);
+}
+
+void INDI::BaseClient::sendNewNumber (INumberVectorProperty *nvp)
+{
+    fprintf(svrwfp, "<newNumberVector\n");
+    fprintf(svrwfp, "  device='%s'\n", nvp->device);
+    fprintf(svrwfp, "  name='%s'\n>", nvp->name);
+
+    for (int i=0; i < nvp->nnp; i++)
+    {
+        fprintf(svrwfp, "  <oneNumber\n");
+        fprintf(svrwfp, "    name='%s'>\n", nvp->np[i].name);
+        fprintf(svrwfp, "      %g\n", nvp->np[i].value);
+        fprintf(svrwfp, "  </oneNumber>\n");
+    }
+    fprintf(svrwfp, "</newNumberVector>\n");
+
+   fflush(svrwfp);
+}
+
+void INDI::BaseClient::sendNewSwitch (ISwitchVectorProperty *svp, ISwitch *sp)
+{
+    fprintf(svrwfp, "<newSwitchVector\n");
+
+    fprintf(svrwfp, "  device='%s'\n", svp->device);
+    fprintf(svrwfp, "  name='%s'>\n", svp->name);
+    fprintf(svrwfp, "  <oneSwitch\n");
+    fprintf(svrwfp, "    name='%s'>\n", sp->name);
+    fprintf(svrwfp, "      %s\n", (sp->s == ISS_ON) ? "On" : "Off");
+    fprintf(svrwfp, "  </oneSwitch>\n");
+
+    fprintf(svrwfp, "</newSwitchVector>\n");
+
+    fflush(svrwfp);
+}
+
+void INDI::BaseClient::startBlob( const char *devName, const char *propName, const char *timestamp)
+{
+    fprintf(svrwfp, "<newBLOBVector\n");
+    fprintf(svrwfp, "  device='%s'\n", devName);
+    fprintf(svrwfp, "  name='%s'\n", propName);
+    fprintf(svrwfp, "  timestamp='%s'>\n",  timestamp);
+}
+
+void INDI::BaseClient::sendOneBlob( const char *blobName, unsigned int blobSize, const char *blobFormat, unsigned char * blobBuffer)
+{
+    fprintf(svrwfp, "  <oneBLOB\n");
+    fprintf(svrwfp, "    name='%s'\n", blobName);
+    fprintf(svrwfp, "    size='%d'\n", blobSize);
+    fprintf(svrwfp, "    format='%s'>\n", blobFormat);
+
+    for (unsigned i = 0; i < blobSize; i += 72)
+        fprintf(svrwfp, "    %.72s\n", blobBuffer+i);
+
+    fprintf(svrwfp, "   </oneBLOB>\n");
+}
+
+void INDI::BaseClient::finishBlob()
+{
+    fprintf(svrwfp, "</newBLOBVector>\n");
+    fflush(svrwfp);
+
+}
+
+void INDI::BaseClient::setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop)
+{
+    char blobOpenTag[64];
+
+    if (dev)
+    {
+        if (prop)
+            snprintf(blobOpenTag, 64, "<enableBLOB device='%s' name='%s'>", dev, prop);
+        else
+            snprintf(blobOpenTag, 64, "<enableBLOB device='%s'>", dev);
+    }
+    else
+        snprintf(blobOpenTag, 64, "<enableBLOB>", dev, prop);
+
+
+    switch (blobH)
+    {
+    case B_NEVER:
+        fprintf(svrwfp, "%sNever</enableBLOB>\n", blobOpenTag);
+        break;
+    case B_ALSO:
+        fprintf(svrwfp, "%sAlso</enableBLOB>\n", blobOpenTag);
+        break;
+    case B_ONLY:
+        fprintf(svrwfp, "%sOnly</enableBLOB>\n", blobOpenTag);
+        break;
+    }
+
+    fflush(svrwfp);
+}
+
+
+
Index: /BAORadio/libindi/libindi/libs/indibase/baseclient.h
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/baseclient.h	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/baseclient.h	(revision 502)
@@ -0,0 +1,159 @@
+#ifndef INDIBASECLIENT_H
+#define INDIBASECLIENT_H
+
+#include <vector>
+#include <map>
+#include <string>
+
+#include "indiapi.h"
+#include "indidevapi.h"
+#include "indibase.h"
+
+#define MAXRBUF 2048
+
+using namespace std;
+
+/**
+ * \class INDI::BaseClient
+   \brief Class to provide basic client functionality.
+
+   BaseClient enables accelerated development of INDI Clients by providing a framework that facilitates communication, device
+   handling, and event notification. By subclassing BaseClient, clients can quickly connect to an INDI server, and query for
+   a set of INDI::BaseDriver devices, and read and write properties seamlessly. Event driven programming is possible due to
+   notifications upon reception of new devices or properties.
+
+   \attention All notifications functions defined in INDI::BaseMediator must be implemented in the client class even if
+   they are not used because these are pure virtual functions.
+   \author Jasem Mutlaq
+
+ */
+class INDI::BaseClient : public INDI::BaseMediator
+{
+public:
+    enum { INDI_DEVICE_NOT_FOUND=-1, INDI_PROPERTY_INVALID=-2, INDI_PROPERTY_DUPLICATED = -3, INDI_DISPATCH_ERROR=-4 };
+
+    BaseClient();
+    virtual ~BaseClient();
+
+    /** \brief Set the server host name and port
+        \param hostname INDI server host name or IP address.
+        \param port INDI server port.
+    */
+    void setServer(const char * hostname, unsigned int port);
+
+    /** \brief Add a device to the watch list.
+
+        A client may select to receive notifications of only a specific device or a set of devices.
+        If the client encounters any of the devices set via this function, it will create a corresponding
+        INDI::BaseDriver object to handle them. If no devices are watched, then all devices owned by INDI server
+        will be created and handled.
+    */
+    void watchDevice(const char * deviceName);
+
+
+    /** \brief Connect to INDI server.
+
+        \returns True if the connection is successful, false otherwise.
+        \note This function blocks until connection is either successull or unsuccessful.
+    */
+    bool connect();
+
+    /** \brief Disconnect from INDI server.
+
+        Disconnects from INDI servers. Any devices previously created will be deleted and memory cleared.
+    */
+    void disconnect();
+
+
+    /** \param deviceName Name of device to search for in the list of devices owned by INDI server,
+         \returns If \e deviceName exists, it returns an instance of the device. Otherwise, it returns NULL.
+    */
+    INDI::BaseDriver * getDevice(const char * deviceName);
+
+    /** \returns Returns a vector of all devices created in the client.
+    */
+    const vector<INDI::BaseDriver *> & getDevices() const { return cDevices; }
+
+    /** \brief Set Binary Large Object policy mode
+
+      Set the BLOB handling mode for the client. The client may either recieve:
+      <ul>
+      <li>Only BLOBS</li>
+      <li>BLOBs mixed with normal messages</li>
+      <li>Normal messages only, no BLOBs</li>
+      </ul>
+
+      If \e dev and \e prop are supplied, then the BLOB handling policy is set for this particular device and property.
+      if \e prop is NULL, then the BLOB policy applies to the whole device.
+      if \e dev is NULL, then the BLOB policy applies to all devices owned by INDI server.
+
+      \param blobH BLOB handling policy
+      \param dev name of device
+      \param prop name of property
+    */
+    void setBLOBMode(BLOBHandling blobH, const char *dev = NULL, const char *prop = NULL);
+
+    // Update
+    static void * listenHelper(void *context);
+
+protected:
+
+    /** \brief Dispatch command received from INDI server to respective devices handled by the client */
+    int dispatchCommand(XMLEle *root, char* errmsg);
+
+    /** \brief Remove device */
+    int removeDevice( const char * devName, char * errmsg );
+
+    /** \brief Delete property command */
+    int delPropertyCmd (XMLEle *root, char * errmsg);
+
+    /** \brief Find and return a particular device */
+    INDI::BaseDriver * findDev( const char * devName, char * errmsg);
+    /** \brief Add a new device */
+    INDI::BaseDriver * addDevice (XMLEle *dep, char * errmsg);
+    /** \brief Find a device, and if it doesn't exist, create it if create is set to 1 */
+    INDI::BaseDriver * findDev (XMLEle *root, int create, char * errmsg);
+
+    /**  Process messages */
+    int messageCmd (XMLEle *root, char * errmsg);
+    /**  Process messages */
+    void checkMsg (XMLEle *root, INDI::BaseDriver *dp);
+    /**  Process messages */
+    void doMsg (XMLEle *msg, INDI::BaseDriver *dp);
+
+    /** \brief Send new Text command to server */
+    void sendNewText (ITextVectorProperty *pp);
+    /** \brief Send new Number command to server */
+    void sendNewNumber (INumberVectorProperty *pp);
+    /** \brief Send new Switch command to server */
+    void sendNewSwitch (ISwitchVectorProperty *pp, ISwitch *lp);
+    /** \brief Send opening tag for BLOB command to server */
+    void startBlob( const char *devName, const char *propName, const char *timestamp);
+    /** \brief Send ONE blob content to server */
+    void sendOneBlob( const char *blobName, unsigned int blobSize, const char *blobFormat, unsigned char * blobBuffer);
+    /** \brief Send closing tag for BLOB command to server */
+    void finishBlob();
+
+private:
+
+    // Listen to INDI server and process incoming messages
+    void listenINDI();
+
+    // Thread for listenINDI()
+    pthread_t listen_thread;
+
+    vector<INDI::BaseDriver *> cDevices;
+    vector<string> cDeviceNames;
+
+    string cServer;
+    unsigned int cPort;
+
+    // Parse & FILE buffers for IO
+    int sockfd;
+    LilXML *lillp;			/* XML parser context */
+    FILE *svrwfp;			/* FILE * to talk to server */
+    FILE *svrrfp;			/* FILE * to read from server */
+
+};
+
+#endif // INDIBASECLIENT_H
Index: /BAORadio/libindi/libindi/libs/indibase/basedriver.cpp
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/basedriver.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/basedriver.cpp	(revision 502)
@@ -0,0 +1,959 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+
+#include "basedriver.h"
+#include "baseclient.h"
+#include "indicom.h"
+#include "base64.h"
+
+INDI::BaseDriver::BaseDriver()
+{
+    mediator = NULL;
+    lp = newLilXML();
+}
+
+
+INDI::BaseDriver::~BaseDriver()
+{
+    std::vector<INumberVectorProperty *>::const_iterator numi;
+    std::vector<ISwitchVectorProperty *>::const_iterator switchi;
+    std::vector<ITextVectorProperty *>::const_iterator texti;
+    std::vector<ILightVectorProperty *>::const_iterator lighti;
+    std::vector<IBLOBVectorProperty *>::const_iterator blobi;
+
+    delLilXML (lp);
+    pAll.clear();
+
+    for ( numi = pNumbers.begin(); numi != pNumbers.end(); numi++)
+        delete (*numi);
+
+   for ( switchi = pSwitches.begin(); switchi != pSwitches.end(); switchi++)
+        delete (*switchi);
+
+   for ( texti = pTexts.begin(); texti != pTexts.end(); texti++)
+        delete (*texti);
+
+   for ( lighti = pLights.begin(); lighti != pLights.end(); lighti++)
+        delete (*lighti);
+
+   for ( blobi = pBlobs.begin(); blobi != pBlobs.end(); blobi++)
+        delete (*blobi);
+}
+
+INumberVectorProperty * INDI::BaseDriver::getNumber(const char *name)
+{
+    std::vector<INumberVectorProperty *>::const_iterator numi;
+
+    for ( numi = pNumbers.begin(); numi != pNumbers.end(); numi++)
+        if (!strcmp(name, (*numi)->name))
+            return *numi;
+
+    return NULL;
+
+}
+
+ITextVectorProperty * INDI::BaseDriver::getText(const char *name)
+{
+    std::vector<ITextVectorProperty *>::const_iterator texti;
+
+    for ( texti = pTexts.begin(); texti != pTexts.end(); texti++)
+        if (!strcmp(name, (*texti)->name))
+            return *texti;
+
+    return NULL;
+}
+
+ISwitchVectorProperty * INDI::BaseDriver::getSwitch(const char *name)
+{
+    std::vector<ISwitchVectorProperty *>::const_iterator switchi;
+
+    for ( switchi = pSwitches.begin(); switchi != pSwitches.end(); switchi++)
+        if (!strcmp(name, (*switchi)->name))
+            return *switchi;
+
+    return NULL;
+
+}
+
+ILightVectorProperty * INDI::BaseDriver::getLight(const char *name)
+{
+    std::vector<ILightVectorProperty *>::const_iterator lighti;
+
+    for ( lighti = pLights.begin(); lighti != pLights.end(); lighti++)
+        if (!strcmp(name, (*lighti)->name))
+            return *lighti;
+
+    return NULL;
+
+}
+
+IBLOBVectorProperty * INDI::BaseDriver::getBLOB(const char *name)
+{
+    std::vector<IBLOBVectorProperty *>::const_iterator blobi;
+
+    for ( blobi = pBlobs.begin(); blobi != pBlobs.end(); blobi++)
+        if (!strcmp(name, (*blobi)->name))
+            return *blobi;
+
+    return NULL;
+}
+
+void * INDI::BaseDriver::getProperty(const char *name, INDI_TYPE & type)
+{
+    std::vector<pOrder>::const_iterator orderi;
+
+    INumberVectorProperty *nvp;
+    ITextVectorProperty *tvp;
+    ISwitchVectorProperty *svp;
+    ILightVectorProperty *lvp;
+    IBLOBVectorProperty *bvp;
+    int i=0;
+
+    for (i=0, orderi = pAll.begin(); orderi != pAll.end(); orderi++, i++)
+    {
+        switch ( (*orderi).type)
+        {
+        case INDI_NUMBER:
+            nvp = static_cast<INumberVectorProperty *>((*orderi).p);
+            if (!strcmp(name, nvp->name))
+            {
+                type = INDI_NUMBER;
+                return (*orderi).p;
+            }
+
+             break;
+        case INDI_TEXT:
+             tvp = static_cast<ITextVectorProperty *>((*orderi).p);
+             if (!strcmp(name, tvp->name))
+             {
+                 type = INDI_TEXT;
+                 return (*orderi).p;
+             }
+             break;
+        case INDI_SWITCH:
+             svp = static_cast<ISwitchVectorProperty *>((*orderi).p);
+             if (!strcmp(name, svp->name))
+             {
+                 type = INDI_SWITCH;
+                 return (*orderi).p;
+             }
+             break;
+        case INDI_LIGHT:
+             lvp = static_cast<ILightVectorProperty *>((*orderi).p);
+             if (!strcmp(name, lvp->name))
+             {
+                 type = INDI_LIGHT;
+                 return (*orderi).p;
+             }
+             break;
+        case INDI_BLOB:
+             bvp = static_cast<IBLOBVectorProperty *>((*orderi).p);
+             if (!strcmp(name, bvp->name))
+             {
+                 type = INDI_BLOB;
+                 return (*orderi).p;
+             }
+             break;
+        }
+    }
+
+    return NULL;
+}
+
+int INDI::BaseDriver::removeProperty(const char *name)
+{
+    std::vector<pOrder>::iterator orderi;
+
+    INumberVectorProperty *nvp;
+    ITextVectorProperty *tvp;
+    ISwitchVectorProperty *svp;
+    ILightVectorProperty *lvp;
+    IBLOBVectorProperty *bvp;
+
+    for (orderi = pAll.begin(); orderi != pAll.end(); orderi++)
+    {
+        switch ( (*orderi).type)
+        {
+        case INDI_NUMBER:
+            nvp = static_cast<INumberVectorProperty *>((*orderi).p);
+            if (!strcmp(name, nvp->name))
+            {
+                 pAll.erase(orderi);
+                 delete (nvp);
+                 return 0;
+             }
+             break;
+        case INDI_TEXT:
+             tvp = static_cast<ITextVectorProperty *>((*orderi).p);
+             if (!strcmp(name, tvp->name))
+             {
+                  pAll.erase(orderi);
+                  delete (tvp);
+                  return 0;
+              }
+             break;
+        case INDI_SWITCH:
+             svp = static_cast<ISwitchVectorProperty *>((*orderi).p);
+             if (!strcmp(name, svp->name))
+             {
+                  pAll.erase(orderi);
+                  delete (svp);
+                  return 0;
+              }
+             break;
+        case INDI_LIGHT:
+             lvp = static_cast<ILightVectorProperty *>((*orderi).p);
+             if (!strcmp(name, lvp->name))
+             {
+                  pAll.erase(orderi);
+                  delete (lvp);
+                  return 0;
+              }
+             break;
+        case INDI_BLOB:
+             bvp = static_cast<IBLOBVectorProperty *>((*orderi).p);
+             if (!strcmp(name, bvp->name))
+             {
+                  pAll.erase(orderi);
+                  delete (bvp);
+                  return 0;
+              }
+             break;
+        }
+    }
+
+    return INDI_PROPERTY_INVALID;
+}
+
+void INDI::BaseDriver::buildSkeleton(const char *filename)
+{
+    char errmsg[MAXRBUF];
+    FILE *fp = NULL;
+    XMLEle *root = NULL, *fproot = NULL;
+
+    fp = fopen(filename, "r");
+
+    if (fp == NULL)
+    {
+        IDLog("Unable to build skeleton. Error loading file %s: %s\n", filename, strerror(errno));
+        return;
+    }
+
+    fproot = readXMLFile(fp, lp, errmsg);
+
+    if (fproot == NULL)
+    {
+        IDLog("Unable to parse skeleton XML: %s", errmsg);
+        return;
+    }
+
+    //prXMLEle(stderr, fproot, 0);
+
+    for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0))
+            buildProp(root, errmsg);
+
+
+
+    /**************************************************************************/
+
+}
+
+int INDI::BaseDriver::buildProp(XMLEle *root, char *errmsg)
+{
+    IPerm perm;
+    IPState state;
+    ISRule rule;
+    XMLEle *ep = NULL;
+    char *rtag, *rname, *rdev;
+    INDI_TYPE type;
+    double timeout=0;
+
+    rtag = tagXMLEle(root);
+
+    /* pull out device and name */
+    if (crackDN (root, &rdev, &rname, errmsg) < 0)
+        return -1;
+
+    if (!deviceID[0])
+    {
+        if (getenv("INDIDEV"))
+            strncpy(deviceID, getenv("INDIDEV"), MAXINDINAME);
+        else
+            strncpy(deviceID, rdev, MAXINDINAME);
+    }
+
+    if (getProperty(rname, type) != NULL)
+        return INDI::BaseClient::INDI_PROPERTY_DUPLICATED;
+
+    if (crackIPerm(findXMLAttValu(root, "perm"), &perm) < 0)
+    {
+        IDLog("Error extracting %s permission (%s)", rname, findXMLAttValu(root, "perm"));
+        return -1;
+    }
+
+    timeout = atoi(findXMLAttValu(root, "timeout"));
+
+    if (crackIPState (findXMLAttValu(root, "state"), &state) < 0)
+    {
+        IDLog("Error extracting %s state (%s)", rname, findXMLAttValu(root, "state"));
+        return -1;
+    }
+
+    if (!strcmp (rtag, "defNumberVector"))
+    {
+
+        INumberVectorProperty *nvp = new INumberVectorProperty;
+        INumber *np = NULL;
+        int n=0;
+
+        strncpy(nvp->device, deviceID, MAXINDIDEVICE);
+        strncpy(nvp->name, rname, MAXINDINAME);
+        strncpy(nvp->label, findXMLAttValu(root, "label"), MAXINDILABEL);
+        strncpy(nvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP);
+
+        nvp->p       = perm;
+        nvp->s       = state;
+        nvp->timeout = timeout;
+
+    /* pull out each name/value pair */
+    for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++)
+    {
+        if (!strcmp (tagXMLEle(ep), "defNumber"))
+        {
+            np = (INumber *) realloc(np, (n+1) * sizeof(INumber));
+
+            np[n].nvp = nvp;
+
+            XMLAtt *na = findXMLAtt (ep, "name");
+
+            if (na)
+            {
+                if (f_scansexa (pcdataXMLEle(ep), &(np[n].value)) < 0)
+                    IDLog("%s: Bad format %s\n", rname, pcdataXMLEle(ep));
+                else
+                {
+
+                    strncpy(np[n].name, valuXMLAtt(na), MAXINDINAME);
+
+                    na = findXMLAtt (ep, "label");
+                    if (na)
+                      strncpy(np[n].label, valuXMLAtt(na),MAXINDILABEL);
+                    na = findXMLAtt (ep, "format");
+                    if (na)
+                        strncpy(np[n].format, valuXMLAtt(na), MAXINDIFORMAT);
+
+                   na = findXMLAtt (ep, "min");
+                   if (na)
+                       np[n].min = atof(valuXMLAtt(na));
+                   na = findXMLAtt (ep, "max");
+                   if (na)
+                       np[n].max = atof(valuXMLAtt(na));
+                   na = findXMLAtt (ep, "step");
+                   if (na)
+                       np[n].step = atof(valuXMLAtt(na));
+
+                }
+            }
+        }
+    }
+
+    if (n > 0)
+    {
+        nvp->nnp = n;
+        nvp->np  = np;
+        pNumbers.push_back(nvp);
+        pOrder o = { INDI_NUMBER, nvp };
+        pAll.push_back(o);
+        IDLog("Adding number property %s to list.\n", nvp->name);
+    }
+    else
+        IDLog("%s: newNumberVector with no valid members\n",rname);
+}
+  else if (!strcmp (rtag, "defSwitchVector"))
+        {
+            ISwitchVectorProperty *svp = new ISwitchVectorProperty;
+            ISwitch *sp = NULL;
+            int n=0;
+
+            strncpy(svp->device, deviceID, MAXINDIDEVICE);
+            strncpy(svp->name, rname, MAXINDINAME);
+            strncpy(svp->label, findXMLAttValu(root, "label"), MAXINDILABEL);
+            strncpy(svp->group, findXMLAttValu(root, "group"), MAXINDIGROUP);
+
+            if (crackISRule(findXMLAttValu(root, "rule"), (&svp->r)) < 0)
+                svp->r = ISR_1OFMANY;
+
+            svp->p       = perm;
+            svp->s       = state;
+            svp->timeout = timeout;
+
+
+        /* pull out each name/value pair */
+        for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++)
+        {
+            if (!strcmp (tagXMLEle(ep), "defSwitch"))
+            {
+                sp = (ISwitch *) realloc(sp, (n+1) * sizeof(ISwitch));
+
+                sp[n].svp = svp;
+
+                XMLAtt *na = findXMLAtt (ep, "name");
+
+                if (na)
+                {
+                    crackISState(pcdataXMLEle(ep), &(sp[n].s));
+                    strncpy(sp[n].name, valuXMLAtt(na), MAXINDINAME);
+
+                    na = findXMLAtt (ep, "label");
+                    if (na)
+                        strncpy(sp[n].label, valuXMLAtt(na),MAXINDILABEL);
+                 }
+            }
+        }
+
+        if (n > 0)
+        {
+            svp->nsp = n;
+            svp->sp  = sp;
+            pSwitches.push_back(svp);
+            pOrder o = { INDI_SWITCH, svp };
+            pAll.push_back(o);
+            IDLog("Adding Switch property %s to list.\n", svp->name);
+        }
+        else
+            IDLog("%s: newSwitchVector with no valid members\n",rname);
+    }
+
+else if (!strcmp (rtag, "defTextVector"))
+    {
+
+        ITextVectorProperty *tvp = new ITextVectorProperty;
+        IText *tp = NULL;
+        int n=0;
+
+        strncpy(tvp->device, deviceID, MAXINDIDEVICE);
+        strncpy(tvp->name, rname, MAXINDINAME);
+        strncpy(tvp->label, findXMLAttValu(root, "label"), MAXINDILABEL);
+        strncpy(tvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP);
+
+        tvp->p       = perm;
+        tvp->s       = state;
+        tvp->timeout = timeout;
+
+    /* pull out each name/value pair */
+    for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++)
+    {
+        if (!strcmp (tagXMLEle(ep), "defText"))
+        {
+            tp = (IText *) realloc(tp, (n+1) * sizeof(IText));
+
+            tp[n].tvp = tvp;
+
+            XMLAtt *na = findXMLAtt (ep, "name");
+
+            if (na)
+            {
+                tp[n].text = (char *) malloc(pcdatalenXMLEle(ep)*sizeof(char));
+                strncpy(tp[n].text, pcdataXMLEle(ep), pcdatalenXMLEle(ep));
+                strncpy(tp[n].name, valuXMLAtt(na), MAXINDINAME);
+
+                na = findXMLAtt (ep, "label");
+                if (na)
+                    strncpy(tp[n].label, valuXMLAtt(na),MAXINDILABEL);
+             }
+        }
+    }
+
+    if (n > 0)
+    {
+        tvp->ntp = n;
+        tvp->tp  = tp;
+        pTexts.push_back(tvp);
+        pOrder o = { INDI_TEXT, tvp };
+        pAll.push_back(o);
+        IDLog("Adding Text property %s to list.\n", tvp->name);
+    }
+    else
+        IDLog("%s: newTextVector with no valid members\n",rname);
+}
+else if (!strcmp (rtag, "defLightVector"))
+    {
+
+        ILightVectorProperty *lvp = new ILightVectorProperty;
+        ILight *lp = NULL;
+        int n=0;
+
+        strncpy(lvp->device, deviceID, MAXINDIDEVICE);
+        strncpy(lvp->name, rname, MAXINDINAME);
+        strncpy(lvp->label, findXMLAttValu(root, "label"), MAXINDILABEL);
+        strncpy(lvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP);
+
+        lvp->s       = state;
+
+    /* pull out each name/value pair */
+    for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++)
+    {
+        if (!strcmp (tagXMLEle(ep), "defLight"))
+        {
+            lp = (ILight *) realloc(lp, (n+1) * sizeof(ILight));
+
+            lp[n].lvp = lvp;
+
+            XMLAtt *na = findXMLAtt (ep, "name");
+
+            if (na)
+            {
+                crackIPState(pcdataXMLEle(ep), &(lp[n].s));
+                strncpy(lp[n].name, valuXMLAtt(na), MAXINDINAME);
+
+                na = findXMLAtt (ep, "label");
+                if (na)
+                    strncpy(lp[n].label, valuXMLAtt(na),MAXINDILABEL);
+
+             }
+        }
+    }
+
+    if (n > 0)
+    {
+        lvp->nlp = n;
+        lvp->lp  = lp;
+        pLights.push_back(lvp);
+        pOrder o = { INDI_LIGHT, lvp };
+        pAll.push_back(o);
+        IDLog("Adding Light property %s to list.\n", lvp->name);
+    }
+    else
+        IDLog("%s: newLightVector with no valid members\n",rname);
+}
+else if (!strcmp (rtag, "defBLOBVector"))
+    {
+
+        IBLOBVectorProperty *bvp = new IBLOBVectorProperty;
+        IBLOB *bp = NULL;
+        int n=0;
+
+        strncpy(bvp->device, deviceID, MAXINDIDEVICE);
+        strncpy(bvp->name, rname, MAXINDINAME);
+        strncpy(bvp->label, findXMLAttValu(root, "label"), MAXINDILABEL);
+        strncpy(bvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP);
+
+        bvp->s       = state;
+
+    /* pull out each name/value pair */
+    for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++)
+    {
+        if (!strcmp (tagXMLEle(ep), "defBLOB"))
+        {
+            bp = (IBLOB *) realloc(bp, (n+1) * sizeof(IBLOB));
+
+            bp[n].bvp = bvp;
+
+            XMLAtt *na = findXMLAtt (ep, "name");
+
+            if (na)
+            {
+                strncpy(bp[n].name, valuXMLAtt(na), MAXINDINAME);
+
+                na = findXMLAtt (ep, "label");
+                if (na)
+                    strncpy(bp[n].label, valuXMLAtt(na),MAXINDILABEL);
+
+                na = findXMLAtt (ep, "format");
+                if (na)
+                    strncpy(bp[n].label, valuXMLAtt(na),MAXINDIBLOBFMT);
+
+                // Initialize everything to zero
+
+                bp[n].blob    = NULL;
+                bp[n].size    = 0;
+                bp[n].bloblen = 0;
+             }
+
+        }
+    }
+
+    if (n > 0)
+    {
+        bvp->nbp = n;
+        bvp->bp  = bp;
+        pBlobs.push_back(bvp);
+        pOrder o = { INDI_BLOB, bvp };
+        pAll.push_back(o);
+        IDLog("Adding BLOB property %s to list.\n", bvp->name);
+    }
+    else
+        IDLog("%s: newBLOBVector with no valid members\n",rname);
+ }
+
+return (0);
+
+}
+
+bool INDI::BaseDriver::isConnected()
+{
+    ISwitchVectorProperty *svp = getSwitch("CONNECTION");
+    if (!svp)
+        return false;
+
+    ISwitch * sp = IUFindSwitch(svp, "CONNECT");
+
+    if (!sp)
+        return false;
+
+    if (sp->s == ISS_ON)
+        return true;
+    else
+        return false;
+
+}
+
+void INDI::BaseDriver::setConnected(bool status)
+{
+    ISwitch *sp = NULL;
+    ISwitchVectorProperty *svp = getSwitch("CONNECTION");
+    if (!svp)
+        return;
+
+    IUResetSwitch(svp);
+
+    // Connect
+    if (status)
+    {
+        sp = IUFindSwitch(svp, "CONNECT");
+        if (!sp)
+            return;
+        sp->s = ISS_ON;
+    }
+    // Disconnect
+    else
+    {
+        sp = IUFindSwitch(svp, "DISCONNECT");
+        if (!sp)
+            return;
+        sp->s = ISS_ON;
+    }
+
+    svp->s = IPS_OK;
+}
+
+/*
+ * return 0 if ok else -1 with reason in errmsg
+ */
+int INDI::BaseDriver::setValue (XMLEle *root, char * errmsg)
+{
+    XMLAtt *ap;
+    XMLEle *ep;
+    char *rtag, *name;
+    double timeout;
+    IPState state;
+    bool stateSet=false, timeoutSet=false;
+
+    rtag = tagXMLEle(root);
+
+    ap = findXMLAtt (root, "name");
+    if (!ap)
+    {
+        snprintf(errmsg, MAXRBUF, "INDI: <%s> unable to find name attribute", tagXMLEle(root));
+        return (-1);
+    }
+
+    name = valuXMLAtt(ap);
+
+    /* set overall property state, if any */
+    ap = findXMLAtt (root, "state");
+    if (ap)
+    {
+        if (crackIPState(valuXMLAtt(ap), &state) != 0)
+        {
+            snprintf(errmsg, MAXRBUF, "INDI: <%s> bogus state %s for %s", tagXMLEle(root),
+                     valuXMLAtt(ap), name);
+            return (-1);
+        }
+
+        stateSet = true;
+    }
+
+    /* allow changing the timeout */
+    ap = findXMLAtt (root, "timeout");
+    if (ap)
+    {
+        timeout = atof(valuXMLAtt(ap));
+        timeoutSet = true;
+    }
+
+    if (!strcmp(rtag, "setNumberVector"))
+    {
+        INumberVectorProperty *nvp = getNumber(name);
+        if (nvp == NULL)
+        {
+            snprintf(errmsg, MAXRBUF, "INDI: Could not find property %s in %s", name, deviceID);
+            return -1;
+        }
+
+        if (stateSet)
+            nvp->s = state;
+
+        if (timeoutSet)
+            nvp->timeout = timeout;
+
+       for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+        {
+           INumber *np =  IUFindNumber(nvp, findXMLAttValu(ep, "name"));
+           if (!np)
+               continue;
+
+          np->value = atof(pcdataXMLEle(ep));
+
+          // Permit changing of min/max
+          if (findXMLAtt(ep, "min"))
+              np->min = atof(findXMLAttValu(ep, "min"));
+          if (findXMLAtt(ep, "max"))
+              np->max = atof(findXMLAttValu(ep, "max"));
+       }
+
+       if (mediator)
+           mediator->newNumber(nvp);
+
+       return 0;
+    }
+    else if (!strcmp(rtag, "setTextVector"))
+    {
+        ITextVectorProperty *tvp = getText(name);
+        if (tvp == NULL)
+            return -1;
+
+        if (stateSet)
+            tvp->s = state;
+
+        if (timeoutSet)
+            tvp->timeout = timeout;
+
+       for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+        {
+           IText *tp =  IUFindText(tvp, findXMLAttValu(ep, "name"));
+           if (!tp)
+               continue;
+
+           IUSaveText(tp, pcdataXMLEle(ep));
+       }
+
+       if (mediator)
+           mediator->newText(tvp);
+
+       return 0;
+    }
+    else if (!strcmp(rtag, "setSwitchVector"))
+    {
+        ISState swState;
+        ISwitchVectorProperty *svp = getSwitch(name);
+        if (svp == NULL)
+            return -1;
+
+        if (stateSet)
+            svp->s = state;
+
+        if (timeoutSet)
+            svp->timeout = timeout;
+
+       for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+        {
+           ISwitch *sp =  IUFindSwitch(svp, findXMLAttValu(ep, "name"));
+           if (!sp)
+               continue;
+
+           if (crackISState(pcdataXMLEle(ep), &swState) == 0)
+               sp->s = swState;
+        }
+
+       if (mediator)
+           mediator->newSwitch(svp);
+
+       return 0;
+    }
+    else if (!strcmp(rtag, "setLightVector"))
+    {
+        IPState lState;
+        ILightVectorProperty *lvp = getLight(name);
+        if (lvp == NULL)
+            return -1;
+
+        if (stateSet)
+            lvp->s = state;
+
+       for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0))
+        {
+           ILight *lp =  IUFindLight(lvp, findXMLAttValu(ep, "name"));
+           if (!lp)
+               continue;
+
+           if (crackIPState(pcdataXMLEle(ep), &lState) == 0)
+               lp->s = lState;
+        }
+
+       if (mediator)
+           mediator->newLight(lvp);
+
+       return 0;
+
+    }
+    else if (!strcmp(rtag, "setBLOBVector"))
+    {
+        IBLOBVectorProperty *bvp = getBLOB(name);
+        if (bvp == NULL)
+            return -1;
+
+        if (stateSet)
+            bvp->s = state;
+
+        if (timeoutSet)
+            bvp->timeout = timeout;
+
+        return setBLOB(bvp, root, errmsg);
+    }
+
+    snprintf(errmsg, MAXRBUF, "INDI: <%s> Unable to process tag", tagXMLEle(root));
+    return -1;
+}
+
+/* Set BLOB vector. Process incoming data stream
+ * Return 0 if okay, -1 if error
+*/
+int INDI::BaseDriver::setBLOB(IBLOBVectorProperty *bvp, XMLEle * root, char * errmsg)
+{
+
+    XMLEle *ep;
+    IBLOB *blobEL;
+
+    for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0))
+    {
+        if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
+        {
+            blobEL = IUFindBLOB(bvp, findXMLAttValu (ep, "name"));
+
+            if (blobEL)
+                return processBLOB(blobEL, ep, errmsg);
+            else
+            {
+                snprintf(errmsg, MAXRBUF, "INDI: set %s.%s.%s not found", bvp->device, bvp->name,
+                         findXMLAttValu (ep, "name"));
+                return (-1);
+            }
+        }
+    }
+
+    return -1;
+}
+
+/* Process incoming data stream
+ * Return 0 if okay, -1 if error
+*/
+int INDI::BaseDriver::processBLOB(IBLOB *blobEL, XMLEle *ep, char * errmsg)
+{
+    XMLAtt *ap = NULL;
+    int blobSize=0, r=0;
+    uLongf dataSize=0;
+    char *baseBuffer=NULL, *dataFormat;
+    unsigned char *blobBuffer(NULL), *dataBuffer(NULL);
+    bool iscomp(false);
+
+    ap = findXMLAtt(ep, "size");
+    if (!ap)
+    {
+        snprintf(errmsg, MAXRBUF, "INDI: set %s size not found", blobEL->name);
+        return (-1);
+    }
+
+    dataSize = atoi(valuXMLAtt(ap));
+
+    ap = findXMLAtt(ep, "format");
+    if (!ap)
+    {
+        snprintf(errmsg, MAXRBUF, "INDI: set %s format not found",blobEL->name);
+        return (-1);
+    }
+
+    dataFormat = valuXMLAtt(ap);
+
+    strncpy(blobEL->format, dataFormat, MAXINDIFORMAT);
+
+    baseBuffer = (char *) malloc ( (3*pcdatalenXMLEle(ep)/4) * sizeof (char));
+
+    if (baseBuffer == NULL)
+    {
+        strncpy(errmsg, "Unable to allocate memory for base buffer", MAXRBUF);
+        return (-1);
+    }
+
+    blobSize   = from64tobits (baseBuffer, pcdataXMLEle(ep));
+    blobBuffer = (unsigned char *) baseBuffer;
+
+    /* Blob size = 0 when only state changes */
+    if (dataSize == 0)
+    {
+        free (blobBuffer);
+        return (0);
+    }
+    else if (blobSize < 0)
+    {
+        free (blobBuffer);
+        snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s bad base64", blobEL->bvp->device, blobEL->bvp->name, blobEL->name);
+        return (-1);
+    }
+
+    if (strstr(dataFormat, ".z"))
+    {
+        dataFormat[strlen(dataFormat)-2] = '\0';
+        dataBuffer = (unsigned char *) realloc (dataBuffer,  (dataSize * sizeof(unsigned char)));
+
+        if (baseBuffer == NULL)
+        {
+                free (blobBuffer);
+                strncpy(errmsg, "Unable to allocate memory for data buffer", MAXRBUF);
+                return (-1);
+        }
+
+        r = uncompress(dataBuffer, &dataSize, blobBuffer, (uLong) blobSize);
+        if (r != Z_OK)
+        {
+            snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s compression error: %d", blobEL->bvp->device, blobEL->bvp->name, blobEL->name, r);
+            free (blobBuffer);
+            return -1;
+        }
+        blobEL->size = dataSize;
+    }
+    else
+    {
+        dataBuffer = (unsigned char *) realloc (dataBuffer,  (dataSize * sizeof(unsigned char)));
+        memcpy(dataBuffer, blobBuffer, dataSize);
+        blobEL->size = dataSize;
+    }
+
+    blobEL->blob = dataBuffer;
+
+    if (mediator)
+        mediator->newBLOB(blobEL);
+
+   // newBLOB(dataBuffer, dataSize, dataFormat);
+
+    free (blobBuffer);
+    return (0);
+}
+
+void INDI::BaseDriver::setDeviceName(const char *dev)
+{
+    strncpy(deviceID, dev, MAXINDINAME);
+}
+
+const char * INDI::BaseDriver::deviceName()
+{
+    return deviceID;
+}
+
+void INDI::BaseDriver::addMessage(const char *msg)
+{
+    messageQueue.append(msg);
+}
+
Index: /BAORadio/libindi/libindi/libs/indibase/basedriver.h
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/basedriver.h	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/basedriver.h	(revision 502)
@@ -0,0 +1,162 @@
+#ifndef INDIBASEDRIVER_H
+#define INDIBASEDRIVER_H
+
+#include <vector>
+#include <map>
+#include <string>
+
+#include "indiapi.h"
+#include "indidevapi.h"
+#include "indibase.h"
+
+#define MAXRBUF 2048
+
+/**
+ * \class INDI::BaseDriver
+   \brief Class to provide basic INDI driver functionality.
+
+   INDI::BaseClient contains a vector list of INDI::BaseDrivers. Upon connection with INDI server, the client create a INDI::BaseDriver
+   \e instance for each driver owned by the INDI server. Properties of the driver can be build either by loading an external
+   skeleton file that contains a list of defXXX commands, or by dynamically building properties as they arrive from the server.
+
+   \author Jasem Mutlaq
+ */
+class INDI::BaseDriver
+{
+public:
+    BaseDriver();
+    virtual ~BaseDriver();
+
+    /*! INDI error codes. */
+    enum INDI_ERROR
+    {
+        INDI_DEVICE_NOT_FOUND=-1,       /*!< INDI Device was not found. */
+        INDI_PROPERTY_INVALID=-2,       /*!< Property has an invalid syntax or attribute. */
+        INDI_PROPERTY_DUPLICATED = -3,  /*!< INDI Device was not found. */
+        INDI_DISPATCH_ERROR=-4          /*!< Dispatching command to driver failed. */
+    };
+
+    /*! INDI property type */
+    enum INDI_TYPE
+    {
+        INDI_NUMBER, /*!< INumberVectorProperty. */
+        INDI_SWITCH, /*!< ISwitchVectorProperty. */
+        INDI_TEXT,   /*!< ITextVectorProperty. */
+        INDI_LIGHT,  /*!< ILightVectorProperty. */
+        INDI_BLOB    /*!< IBLOBVectorProperty. */
+    };
+
+    /** \return Return vector number property given its name */
+    INumberVectorProperty * getNumber(const char *name);
+    /** \return Return vector text property given its name */
+    ITextVectorProperty * getText(const char *name);
+    /** \return Return vector switch property given its name */
+    ISwitchVectorProperty * getSwitch(const char *name);
+    /** \return Return vector light property given its name */
+    ILightVectorProperty * getLight(const char *name);
+    /** \return Return vector BLOB property given its name */
+    IBLOBVectorProperty * getBLOB(const char *name);
+
+    /** \brief Remove a property
+        \param name name of property to be removed
+        \return 0 if successul, -1 otherwise.
+    */
+    int removeProperty(const char *name);
+
+    /** \brief Return a property and its type given its name.
+        \param name of property to be found.
+        \param type of property found.
+        \return If property is found, it is returned. To be used you must use static_cast with given the type of property
+        returned.
+
+        \note This is a low-level function and should not be called directly unless necessary. Use getXXX instead where XXX
+        is the property type (Number, Text, Switch..etc).
+
+    */
+    void * getProperty(const char *name, INDI_TYPE & type);
+
+    /** \brief Build driver properties from a skeleton file.
+        \param filename full path name of the file.
+
+    A skeloton file defines the properties supported by this driver. It is a list of defXXX elements enclosed by @<INDIDriver>@
+ and @</INDIDriver>@ opening and closing tags. After the properties are created, they can be rerieved, manipulated, and defined
+ to other clients.
+
+ \see An example skeleton file can be found under examples/tutorial_four_sk.xml
+
+    */
+    void buildSkeleton(const char *filename);
+
+    /** \return True if the device is connected (CONNECT=ON), False otherwise */
+    bool isConnected();
+    /** \brief Connect or Disconnect a device.
+      \param status If true, the driver will attempt to connect to the device (CONNECT=ON). If false, it will attempt
+to disconnect the device.
+    */
+    virtual void setConnected(bool status);
+
+    /** \brief Set the device name
+      \param dev new device name
+      */
+    void setDeviceName(const char *dev);
+    /** \return Returns the device name */
+    const char *deviceName();
+
+    /** \brief Add message to the driver's message queue.
+        \param msg Message to add.
+    */
+    void addMessage(const char *msg);
+    //** \returns Returns the contents of the driver's message queue. *;
+    const char *message() { return messageQueue.c_str(); }
+
+    /** \brief Set the driver's mediator to receive notification of news devices and updated property values. */
+    void setMediator(INDI::BaseMediator *med) { mediator = med; }
+    /** \returns Get the meditator assigned to this driver */
+    INDI::BaseMediator * getMediator() { return mediator; }
+
+protected:
+
+    /** \brief Build a property given the supplied XML element (defXXX)
+      \param root XML element to parse and build.
+      \param errmsg buffer to store error message in parsing fails.
+
+      \return 0 if parsing is successful, -1 otherwise and errmsg is set */
+    int buildProp(XMLEle *root, char *errmsg);
+
+    /** \brief handle SetXXX commands from client */
+    int setValue (XMLEle *root, char * errmsg);
+    /** \brief handle SetBLOB command from client */
+    int processBLOB(IBLOB *blobEL, XMLEle *ep, char * errmsg);
+    /** \brief Parse and store BLOB in the respective vector */
+    int setBLOB(IBLOBVectorProperty *pp, XMLEle * root, char * errmsg);
+
+    char deviceID[MAXINDINAME];
+
+private:
+
+    typedef struct
+    {
+        INDI_TYPE type;
+        void *p;
+    } pOrder;
+
+    std::vector<INumberVectorProperty *> pNumbers;
+    std::vector<ITextVectorProperty *> pTexts;
+    std::vector<ISwitchVectorProperty *> pSwitches;
+    std::vector<ILightVectorProperty *> pLights;
+    std::vector<IBLOBVectorProperty *> pBlobs;
+
+    LilXML *lp;
+
+    std::vector<pOrder> pAll;
+
+    std::string messageQueue;
+
+    INDI::BaseMediator *mediator;
+
+    friend class INDI::BaseClient;
+    friend class INDI::DefaultDriver;
+
+};
+
+#endif // INDIBASEDRIVER_H
Index: /BAORadio/libindi/libindi/libs/indibase/defaultdriver.cpp
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/defaultdriver.cpp	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/defaultdriver.cpp	(revision 502)
@@ -0,0 +1,389 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+
+#include "defaultdriver.h"
+#include "indicom.h"
+#include "base64.h"
+
+
+INDI::DefaultDriver::DefaultDriver()
+{
+    pDebug = false;
+    pSimulation = false;
+}
+
+bool INDI::DefaultDriver::loadConfig()
+{
+    char errmsg[MAXRBUF];
+    bool pResult = false;
+
+    pResult = IUReadConfig(NULL, deviceID, errmsg) == 0 ? true : false;
+
+   if (pResult)
+       IDMessage(deviceID, "Configuration successfully loaded.");
+
+   IUSaveDefaultConfig(NULL, NULL, deviceID);
+
+   return pResult;
+}
+
+bool INDI::DefaultDriver::saveConfig()
+{
+    std::vector<pOrder>::const_iterator orderi;
+    ISwitchVectorProperty *svp=NULL;
+    char errmsg[MAXRBUF];
+    FILE *fp = NULL;
+
+    fp = IUGetConfigFP(NULL, deviceID, errmsg);
+
+    if (fp == NULL)
+    {
+        IDMessage(deviceID, "Error saving configuration. %s", errmsg);
+        return false;
+    }
+
+    IUSaveConfigTag(fp, 0);
+
+    for (orderi = pAll.begin(); orderi != pAll.end(); orderi++)
+    {
+        switch ( (*orderi).type)
+        {
+        case INDI_NUMBER:
+             IUSaveConfigNumber(fp, static_cast<INumberVectorProperty *> ((*orderi).p));
+             break;
+        case INDI_TEXT:
+             IUSaveConfigText(fp, static_cast<ITextVectorProperty *> ((*orderi).p));
+             break;
+        case INDI_SWITCH:
+             svp = static_cast<ISwitchVectorProperty *> ((*orderi).p);
+             /* Never save CONNECTION property. Don't save switches with no switches on if the rule is one of many */
+             if (!strcmp(svp->name, "CONNECTION") || (svp->r == ISR_1OFMANY && !IUFindOnSwitch(svp)))
+                 continue;
+             IUSaveConfigSwitch(fp, svp);
+             break;
+        case INDI_BLOB:
+             IUSaveConfigBLOB(fp, static_cast<IBLOBVectorProperty *> ((*orderi).p));
+             break;
+        }
+    }
+
+    IUSaveConfigTag(fp, 1);
+
+    fclose(fp);
+
+    IUSaveDefaultConfig(NULL, NULL, deviceID);
+
+    IDMessage(deviceID, "Configuration successfully saved.");
+
+    return true;
+}
+
+bool INDI::DefaultDriver::loadDefaultConfig()
+{
+    char configDefaultFileName[MAXRBUF];
+    char errmsg[MAXRBUF];
+    bool pResult = false;
+
+    if (getenv("INDICONFIG"))
+        snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG"));
+    else
+        snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), deviceID);
+
+    if (pDebug)
+        IDLog("Requesting to load default config with: %s\n", configDefaultFileName);
+
+    pResult = IUReadConfig(configDefaultFileName, deviceID, errmsg) == 0 ? true : false;
+
+    if (pResult)
+        IDMessage(deviceID, "Default configuration loaded.");
+    else
+        IDMessage(deviceID, "Error loading default configuraiton. %s", errmsg);
+
+    return pResult;
+}
+
+bool INDI::DefaultDriver::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+
+    // ignore if not ours //
+    if (strcmp (dev, deviceID))
+        return false;
+
+    ISwitchVectorProperty *svp = getSwitch(name);
+
+    if (!svp)
+        return false;
+
+    if (!strcmp(svp->name, "DEBUG"))
+    {
+        IUUpdateSwitch(svp, states, names, n);
+        ISwitch *sp = IUFindOnSwitch(svp);
+        if (!sp)
+            return false;
+
+        if (!strcmp(sp->name, "ENABLE"))
+            setDebug(true);
+        else
+            setDebug(false);
+        return true;
+    }
+
+    if (!strcmp(svp->name, "SIMULATION"))
+    {
+        IUUpdateSwitch(svp, states, names, n);
+        ISwitch *sp = IUFindOnSwitch(svp);
+        if (!sp)
+            return false;
+
+        if (!strcmp(sp->name, "ENABLE"))
+            setSimulation(true);
+        else
+            setSimulation(false);
+        return true;
+    }
+
+    if (!strcmp(svp->name, "CONFIG_PROCESS"))
+    {
+        IUUpdateSwitch(svp, states, names, n);
+        ISwitch *sp = IUFindOnSwitch(svp);
+        IUResetSwitch(svp);
+        bool pResult = false;
+        if (!sp)
+            return false;
+
+        if (!strcmp(sp->name, "CONFIG_LOAD"))
+            pResult = loadConfig();
+        else if (!strcmp(sp->name, "CONFIG_SAVE"))
+            pResult = saveConfig();
+        else if (!strcmp(sp->name, "CONFIG_DEFAULT"))
+            pResult = loadDefaultConfig();
+
+        if (pResult)
+            svp->s = IPS_OK;
+        else
+            svp->s = IPS_ALERT;
+
+        IDSetSwitch(svp, NULL);
+        return true;
+    }
+
+    return false;
+
+}
+
+void INDI::DefaultDriver::addAuxControls()
+{
+    /**************************************************************************/
+    DebugSP = getSwitch("DEBUG");
+    if (!DebugSP)
+    {
+        DebugSP = new ISwitchVectorProperty;
+        IUFillSwitch(&DebugS[0], "ENABLE", "Enable", ISS_OFF);
+        IUFillSwitch(&DebugS[1], "DISABLE", "Disable", ISS_ON);
+        IUFillSwitchVector(DebugSP, DebugS, NARRAY(DebugS), deviceID, "DEBUG", "Debug", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+        pSwitches.push_back(DebugSP);
+        pOrder debo = {INDI_SWITCH, DebugSP};
+        pAll.push_back(debo);
+    }
+    else
+    {
+        ISwitch *sp = IUFindSwitch(DebugSP, "ENABLE");
+        if (sp)
+            if (sp->s == ISS_ON)
+                pDebug = true;
+    }
+    /**************************************************************************/
+
+    /**************************************************************************/
+    SimulationSP = getSwitch("SIMULATION");
+    if (!SimulationSP)
+    {
+        SimulationSP = new ISwitchVectorProperty;
+        IUFillSwitch(&SimulationS[0], "ENABLE", "Enable", ISS_OFF);
+        IUFillSwitch(&SimulationS[1], "DISABLE", "Disable", ISS_ON);
+        IUFillSwitchVector(SimulationSP, SimulationS, NARRAY(SimulationS), deviceID, "SIMULATION", "Simulation", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+        pSwitches.push_back(SimulationSP);
+        pOrder simo = {INDI_SWITCH, SimulationSP};
+        pAll.push_back(simo);
+    }
+    else
+    {
+        ISwitch *sp = IUFindSwitch(SimulationSP, "ENABLE");
+        if (sp)
+            if (sp->s == ISS_ON)
+                pSimulation = true;
+    }
+
+    /**************************************************************************/
+    ConfigProcessSP = getSwitch("CONFIG_PROCESS");
+    if (!ConfigProcessSP)
+    {
+        ConfigProcessSP = new ISwitchVectorProperty;
+        IUFillSwitch(&ConfigProcessS[0], "CONFIG_LOAD", "Load", ISS_OFF);
+        IUFillSwitch(&ConfigProcessS[1], "CONFIG_SAVE", "Save", ISS_OFF);
+        IUFillSwitch(&ConfigProcessS[2], "CONFIG_DEFAULT", "Default", ISS_OFF);
+        IUFillSwitchVector(ConfigProcessSP, ConfigProcessS, NARRAY(ConfigProcessS), deviceID, "CONFIG_PROCESS", "Configuration", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
+        pSwitches.push_back(ConfigProcessSP);
+        pOrder cpono = {INDI_SWITCH, ConfigProcessSP};
+        pAll.push_back(cpono);
+    }
+    /**************************************************************************/
+
+}
+
+void INDI::DefaultDriver::setDebug(bool enable)
+{
+    if (pDebug == enable)
+    {
+        DebugSP->s = IPS_OK;
+        IDSetSwitch(DebugSP, NULL);
+        return;
+    }
+
+    if (!DebugSP)
+        return;
+
+    IUResetSwitch(DebugSP);
+
+    if (enable)
+    {
+        ISwitch *sp = IUFindSwitch(DebugSP, "ENABLE");
+        if (sp)
+        {
+            sp->s = ISS_ON;
+            IDMessage(deviceID, "Debug is enabled.");
+        }
+    }
+    else
+    {
+        ISwitch *sp = IUFindSwitch(DebugSP, "DISABLE");
+        if (sp)
+        {
+            sp->s = ISS_ON;
+            IDMessage(deviceID, "Debug is disabled.");
+        }
+    }
+
+    pDebug = enable;
+    DebugSP->s = IPS_OK;
+    IDSetSwitch(DebugSP, NULL);
+
+}
+
+void INDI::DefaultDriver::setSimulation(bool enable)
+{
+   if (pSimulation == enable)
+   {
+       SimulationSP->s = IPS_OK;
+       IDSetSwitch(SimulationSP, NULL);
+       return;
+   }
+
+   if (!SimulationSP)
+       return;
+
+   IUResetSwitch(SimulationSP);
+
+   if (enable)
+   {
+       ISwitch *sp = IUFindSwitch(SimulationSP, "ENABLE");
+       if (sp)
+       {
+           IDMessage(deviceID, "Simulation is enabled.");
+           sp->s = ISS_ON;
+       }
+   }
+   else
+   {
+       ISwitch *sp = IUFindSwitch(SimulationSP, "DISABLE");
+       if (sp)
+       {
+           sp->s = ISS_ON;
+           IDMessage(deviceID, "Simulation is disabled.");
+       }
+   }
+
+   pSimulation = enable;
+   SimulationSP->s = IPS_OK;
+   IDSetSwitch(SimulationSP, NULL);
+
+}
+
+bool INDI::DefaultDriver::isDebug()
+{
+  return pDebug;
+}
+
+bool INDI::DefaultDriver::isSimulation()
+{
+ return pSimulation;
+}
+
+void INDI::DefaultDriver::ISGetProperties (const char *dev)
+{
+    std::vector<pOrder>::const_iterator orderi;
+
+    for (orderi = pAll.begin(); orderi != pAll.end(); orderi++)
+    {
+        switch ( (*orderi).type)
+        {
+        case INDI_NUMBER:
+             IDDefNumber(static_cast<INumberVectorProperty *>((*orderi).p) , NULL);
+             break;
+        case INDI_TEXT:
+             IDDefText(static_cast<ITextVectorProperty *>((*orderi).p) , NULL);
+             break;
+        case INDI_SWITCH:
+             IDDefSwitch(static_cast<ISwitchVectorProperty *>((*orderi).p) , NULL);
+             break;
+        case INDI_LIGHT:
+             IDDefLight(static_cast<ILightVectorProperty *>((*orderi).p) , NULL);
+             break;
+        case INDI_BLOB:
+             IDDefBLOB(static_cast<IBLOBVectorProperty *>((*orderi).p) , NULL);
+             break;
+        }
+    }
+
+}
+
+void INDI::DefaultDriver::resetProperties()
+{
+    std::vector<INumberVectorProperty *>::const_iterator numi;
+    std::vector<ISwitchVectorProperty *>::const_iterator switchi;
+    std::vector<ITextVectorProperty *>::const_iterator texti;
+    std::vector<ILightVectorProperty *>::const_iterator lighti;
+    std::vector<IBLOBVectorProperty *>::const_iterator blobi;
+
+    for ( numi = pNumbers.begin(); numi != pNumbers.end(); numi++)
+    {
+        (*numi)->s = IPS_IDLE;
+        IDSetNumber( (*numi), NULL);
+    }
+
+   for ( switchi = pSwitches.begin(); switchi != pSwitches.end(); switchi++)
+   {
+       (*switchi)->s = IPS_IDLE;
+       IDSetSwitch( (*switchi), NULL);
+   }
+
+   for ( texti = pTexts.begin(); texti != pTexts.end(); texti++)
+   {
+      (*texti)->s = IPS_IDLE;
+      IDSetText( (*texti), NULL);
+   }
+
+   for ( lighti = pLights.begin(); lighti != pLights.end(); lighti++)
+   {
+       (*lighti)->s = IPS_IDLE;
+       IDSetLight( (*lighti), NULL);
+   }
+
+   for ( blobi = pBlobs.begin(); blobi != pBlobs.end(); blobi++)
+   {
+       (*blobi)->s = IPS_IDLE;
+       IDSetBLOB( (*blobi), NULL);
+   }
+}
Index: /BAORadio/libindi/libindi/libs/indibase/defaultdriver.h
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/defaultdriver.h	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/defaultdriver.h	(revision 502)
@@ -0,0 +1,114 @@
+#ifndef INDIDEFAULTDRIVER_H
+#define INDIDEFAULTDRIVER_H
+
+#include "basedriver.h"
+#include "indidriver.h"
+
+/**
+ * \class INDI::DefaultDriver
+   \brief Class to provide extended functionary for drivers in addition
+to the functionality provided by INDI::BaseDriver. This class should \e only be subclassed by
+drivers directly as it is linked with main(). Virtual drivers cannot employ INDI::DefaultDriver.
+
+   INDI::DefaultDriver provides capability to add Debug, Simulation, and Configuration controls. These controls (switches) are
+   defined to the client. Configuration options permit saving and loading of AS-IS property values.
+
+\see <a href='tutorial__four_8h_source.html'>Tutorial Four</a>
+\author Jasem Mutlaq
+ */
+class INDI::DefaultDriver : public INDI::BaseDriver
+{
+public:
+    DefaultDriver();
+    virtual ~DefaultDriver() {}
+
+    /** \brief Add Debug, Simulation, and Configuration options to the driver */
+    void addAuxControls();
+
+    /** \brief Set all properties to IDLE state */
+    void resetProperties();
+
+protected:
+
+    /** \brief define the driver's properties to the client.
+      \param dev name of the device
+      \note This function is called by the INDI framework, do not call it directly.
+    */
+    virtual void ISGetProperties (const char *dev);
+
+    /** \brief Process the client newSwitch command
+      \note This function is called by the INDI framework, do not call it directly.
+      \returns True if any property was successfully processed, false otherwise.
+    */
+    virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n);
+
+    /** \brief Process the client newNumber command
+      \note This function is called by the INDI framework, do not call it directly.
+      \returns True if any property was successfully processed, false otherwise.
+    */
+    virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {return false;}
+
+    /** \brief Process the client newSwitch command
+      \note This function is called by the INDI framework, do not call it directly.
+      \returns True if any property was successfully processed, false otherwise.
+    */
+    virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {return false;}
+
+    // Configuration
+
+    /** \brief Load the last saved configuration file
+        \return True if successful, false otherwise.
+    */
+    bool loadConfig();
+
+    /** \brief Save the current properties in a configuration file
+        \return True if successful, false otherwise.
+    */
+    bool saveConfig();
+
+    /** \brief Load the default configuration file
+        \return True if successful, false otherwise.
+    */
+    bool loadDefaultConfig();
+
+    // Simulatin & Debug
+
+    /** \brief Toggle driver debug status
+
+      A driver can be more verbose if Debug option is enabled by the client.
+
+      \param enable If true, the Debug option is set to ON.
+    */
+    void setDebug(bool enable);
+
+    /** \brief Toggle driver simulation status
+
+      A driver can run in simulation mode if Simulation option is enabled by the client.
+
+      \param enable If true, the Simulation option is set to ON.
+    */
+    void setSimulation(bool enable);
+
+    /** \return True if Debug is on, False otherwise. */
+    bool isDebug();
+
+    /** \return True if Simulation is on, False otherwise. */
+    bool isSimulation();
+
+private:
+
+    bool pDebug;
+    bool pSimulation;
+
+    ISwitch DebugS[2];
+    ISwitch SimulationS[2];
+    ISwitch ConfigProcessS[3];
+
+    ISwitchVectorProperty *DebugSP;
+    ISwitchVectorProperty *SimulationSP;
+    ISwitchVectorProperty *ConfigProcessSP;
+
+
+};
+
+#endif // INDIDEFAULTDRIVER_H
Index: /BAORadio/libindi/libindi/libs/indibase/indibase.h
===================================================================
--- /BAORadio/libindi/libindi/libs/indibase/indibase.h	(revision 502)
+++ /BAORadio/libindi/libindi/libs/indibase/indibase.h	(revision 502)
@@ -0,0 +1,73 @@
+#ifndef INDIBASE_H
+#define INDIBASE_H
+
+#include "indiapi.h"
+#include "indidevapi.h"
+
+#define MAXRBUF 2048
+
+/**
+ * \namespace INDI
+   \brief Namespace to encapsulate INDI client, device, and mediator classes
+
+   <ul>
+   <li>BaseClient: Base class for INDI clients. By subclassing BaseClient, client can easily connect to INDI server
+   and handle device communication, command, and notifcation.</li>
+   <li>BaseMediator: Abstract class to provide interface for event notifications in INDI::BaseClient.</li>
+   <li>BaseDriver: Base class for all INDI virtual driver as handled and stored in INDI::BaseClient.</li>
+   <li>DefaultDriver: INDI::BaseDriver with extended functionality such as debug, simulation, and configuration support.
+       It is \e only used by drivers directly, it cannot be used by clients.</li>
+   </ul>
+ */
+namespace INDI
+{
+    class BaseMediator;
+    class BaseClient;
+    class BaseDriver;
+    class DefaultDriver;
+}
+
+
+/**
+ * \class INDI::BaseMediator
+   \brief Meditates event notification as generated by devices and passed to clients.
+*/
+class INDI::BaseMediator
+{
+public:
+
+    /** \brief Emmited when a new device is created from INDI server.
+    */
+    virtual void newDevice()  =0;
+
+    /** \brief Emmited when a new BLOB value arrives from INDI server.
+        \param bp Pointer to filled and process BLOB.
+    */
+    virtual void newBLOB(IBLOB *bp) =0;
+
+    /** \brief Emmited when a new switch value arrives from INDI server.
+        \param svp Pointer to a switch vector property.
+    */
+    virtual void newSwitch(ISwitchVectorProperty *svp) =0;
+
+    /** \brief Emmited when a new number value arrives from INDI server.
+        \param nvp Pointer to a number vector property.
+    */
+    virtual void newNumber(INumberVectorProperty *nvp) =0;
+
+    /** \brief Emmited when a new text value arrives from INDI server.
+        \param tvp Pointer to a text vector property.
+    */
+    virtual void newText(ITextVectorProperty *tvp) =0;
+
+    /** \brief Emmited when a new light value arrives from INDI server.
+        \param lvp Pointer to a light vector property.
+    */
+    virtual void newLight(ILightVectorProperty *lvp) =0;
+
+    /** \brief Emmited when the server gets disconnected.
+    */
+    virtual void serverDisconnected() =0;
+};
+
+#endif // INDIBASE_H
