source: BAORadio/libindi/libindi/drivers/telescope/BAO.cpp @ 651

Last change on this file since 651 was 651, checked in by frichard, 12 years ago
File size: 85.4 KB
Line 
1/*
2#############################
3##
4## BAORadio Indi driver
5## Franck RICHARD
6## franckrichard033@gmail.com
7## Décembre 2011
8##
9#############################
10*/
11
12#include "BAO.h"
13#include "../communs/alt2motor.h"
14
15
16auto_ptr<BAO> telescope(0);
17
18const int  POLLMS = 1;                                  // Period of update, 1 ms.
19
20const char *mydev = "BAO";                              // Name of our device.
21
22const char *BASIC_GROUP    = "Main Control";            // Main Group
23const char *OPTIONS_GROUP  = "Options";                 // Options Group
24
25
26#define targetRA    EquatorialCoordsWN[0].value
27#define targetDEC   EquatorialCoordsWN[1].value
28
29
30static void ISPoll(void *);
31
32void* LancementThread(BAO * appli);
33
34
35
36/**************************************************************************************
37** Initialisation de la classe BAO
38**
39***************************************************************************************/
40
41BAO::BAO()
42{
43    init_properties();
44
45    // Le bouton connect de la boîte de dialogue d'indi_BAO
46    // est dans l'état IDLE au démarrage
47
48    ConnectSP.s           = IPS_IDLE;
49
50    // derniÚre actualisation
51
52    lastRA                = 0.0;
53    lastDEC               = 0.0;
54
55    // Jour julien de la derniÚre actualisation
56
57    JJAnc                 = 0.0;
58
59    // Variables d'état
60
61    currentSet            =  0;
62
63    // Nombre d'antennes connectées
64
65    SocketsNumber         =  1;
66
67    // Le mode tracking est activé par défaut
68
69    TrackingMode          =  BAO_TRACKING;
70
71    // Méthode d'alignement par défaut
72
73    MethodeAlignement     = SIMPLE;
74
75    // délais en sec entre deux actualisations
76    // dans les modes transit et tracking
77
78    ActualisationTMTransit  = 15.0 * 60.0;    // Délai entre 2 actualisations dans le mode transit (en sec)
79
80    ActualisationTMTracking = 5.0;            //                "                 "        tracking
81
82    // cette variable vaut "true" lorsque le thread de l'aplication a été initialisé
83
84    InitThreadOK          = false;
85
86    // UpdatedGoto = true lorsque le dernier goto a bien été réalisé jusqu'au bout
87
88    UpdatedGoto           = true;
89
90    // RealisationGoto = true lorsque les étapes nécessaires à la réalisation d'un goto
91    // sont en cours d'execution
92
93    RealisationGoto       = false;
94
95    // = true si l'utilisateur demande l'annulation du mouvement en cours
96
97    Abort                 = false;
98
99    // = true si l'utilisateur demande de mettre les antennes en mode park
100
101    Park                  = false;
102
103    // = true si un objet est actuellement suivi par les antennes
104
105    Suivi                 = false;
106
107    // = true si l'utilisateur sort de l'application -> permet de fermer le thread
108
109    Exit                  = false;
110
111    // Initialisation des paramÚtres atmosphériques par défaut
112
113    Pression              = 1013.0;
114
115    Temp                  = 10.0;
116
117
118    // initialisation des sockets (Antennes)
119
120    for (int i=0; i<MAXHOSTNAME; i++)
121    {
122        Sockets[i].Connected         = false;
123        Sockets[i].IP                = "";
124        Sockets[i].TargetPosition.= 0.0;
125        Sockets[i].TargetPosition.= 0.0;
126        Sockets[i].AlignementAntenne = new Alignement();
127
128        if (Sockets[i].AlignementAntenne) Sockets[i].AlignementAntenne->InitAlignement();
129    }
130
131    // initialisations supplémentaires
132
133    InitAntennes();
134
135    // Numéro de version
136
137    AfficherLog("Indi server BAORadio...\n");
138    AfficherLog("Driver Version: 0.51 (02-04-2012)\n");
139
140    //connect_telescope();
141}
142
143
144
145/**************************************************************************************
146** Destructeur
147**
148***************************************************************************************/
149
150BAO::~BAO()
151{
152    // On informe le thread que nous allons sortir
153
154    Exit = true;
155
156    // On lui laisse une seconde pour qu'il se termine
157
158    sleep(1);
159
160    // destruction du thread
161
162    pthread_join(th1, NULL);
163
164    // destruction des objets AlignementAntennes
165
166    for (int i=0; i<MAXHOSTNAME; i++)
167    {
168        delete Sockets[i].AlignementAntenne;
169    }
170
171    // Petit message à l'attention de l'utilisateur
172    // permet de savoir si le destructeur a bien été atteint
173
174    AfficherLog("Sortie de indi_BAO\n");
175}
176
177
178
179/**************************************************************************************
180** Affiche le message à l'écran puis sauvegarde le message dans le fichierBAO_indi.log
181**
182***************************************************************************************/
183
184void BAO::AfficherLog(const char* fmt,...)
185{
186    static bool avertissement = false;
187
188    va_list ap;
189
190    FILE *pFile = NULL;
191
192    string fichier;
193
194    va_start (ap, fmt);
195
196    vfprintf (stderr, fmt, ap);
197
198    va_end (ap);
199
200    fichier = "/home/" + (string)getenv("USER") + "/BAO_indi.log";
201
202    //Si le fichier log a une taille > 3M -> on efface le fichier
203
204    //if ( Taille(fichier) > TAILLEMAXLOGS ) remove(fichier.c_str());
205
206    if ( (pFile = fopen(fichier.c_str(), "a")) != NULL)
207    {
208        time_t rawtime;
209        struct tm * timeinfo;
210
211        char buffer[80];
212
213        // On sauvegarde la date et l'heure
214
215        time ( &rawtime );
216        timeinfo = localtime ( &rawtime );
217        strftime (buffer,80,"%c    ",timeinfo);
218        fprintf(pFile, buffer);
219
220        // On sauvegarde le message dans le fichier log
221        va_start (ap, fmt);
222
223        vfprintf(pFile, fmt, ap);
224
225        va_end (ap);
226
227        fclose(pFile);
228    }
229    else
230    {
231        if (!avertissement)
232        {
233            string chaine = "Impossible d'écrire dans le fichier " + fichier +"\nMerci de vérifier les permissions\n";
234            chaine += "ou exécutez le programme en mode superutilisateur.\n\n";
235
236            va_start (ap, fmt);
237
238            vfprintf (stderr, chaine.c_str(), ap);
239
240            va_end (ap);
241
242            avertissement = true;
243        }
244    }
245}
246
247
248
249/************************************************************************************
250** Initialisation des paramÚtres des antennes
251**
252************************************************************************************/
253
254void BAO::InitAntennes()
255{
256    for (int i=0; i<MAXHOSTNAME; i++)
257    {
258        Sockets[i].status             = 0;
259        Sockets[i].sendalertes        = 0;
260        Sockets[i].AttenteExecution   = 0;
261        Sockets[i].AnomaliesExecution = 0;
262        Sockets[i].etape              = 0;
263
264        Sockets[i].ack_status         = false;
265        Sockets[i].ack_pos            = false;
266        Sockets[i].ack_park           = false;
267        Sockets[i].ack_abort          = false;
268        Sockets[i].ack_goto           = false;
269
270        Sockets[i].PosValides         = false;
271        Sockets[i].GotoOk             = false;
272    }
273}
274
275
276
277/**************************************************************************************
278** Initialisation des boutons et des zones d'affichage dans la boîte de dialogue INDI
279** se référer à la documentation d'INDI
280**
281***************************************************************************************/
282
283void BAO::init_properties()
284{
285    // Connection
286    IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF);
287    IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON);
288    IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
289
290    // Coord Set
291    IUFillSwitch(&OnCoordSetS[0], "TRANSIT", "Transit", ISS_ON);
292    IUFillSwitch(&OnCoordSetS[1], "TRACKING", "Tracking", ISS_OFF);
293    IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
294
295    // Alignment Set
296    IUFillSwitch(&AlignmentS[0], "SIMPLE", "Simple", ISS_ON);
297    IUFillSwitch(&AlignmentS[1], "AFFINE", "Affine", ISS_OFF);
298    IUFillSwitch(&AlignmentS[2], "TAKI", "Taki", ISS_OFF);
299    IUFillSwitchVector(&AlignmentSP, AlignmentS, NARRAY(AlignmentS), mydev, "ALIGNMENT_SET", "Alignment", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
300
301    // Abort
302    IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF);
303    IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
304
305    // Park
306    IUFillSwitch(&ParkS[0], "PARK", "Park", ISS_OFF);
307    IUFillSwitchVector(&ParkSP, ParkS, NARRAY(ParkS), mydev, "", "Park", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
308
309    // Object Name
310    IUFillText(&ObjectT[0], "OBJECT_NAME", "Name", "--");
311    IUFillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE);
312
313    // Equatorial Coords - SET
314    IUFillNumber(&EquatorialCoordsWN[0], "RA", "RA  H:M:S", "%10.6m",  0., 24., 0., 0.);
315    IUFillNumber(&EquatorialCoordsWN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.);
316    IUFillNumberVector(&EquatorialCoordsWNP, EquatorialCoordsWN, NARRAY(EquatorialCoordsWN), mydev, "EQUATORIAL_EOD_COORD_REQUEST" , "Equatorial JNow", BASIC_GROUP, IP_WO, 0, IPS_IDLE);
317
318    //Command
319    IUFillText(&CommandT[0], "COMMAND", "Command", "");
320    IUFillTextVector(&CommandTP, CommandT, NARRAY(CommandT), mydev, "COMMAND_SET", "Command", BASIC_GROUP, IP_WO, 0, IPS_IDLE);
321
322    // Geographic coord - SET
323    IUFillNumber(&GeographicCoordsWN[0], "LAT", "Lat  D", "%10.6m",  -90., 90., 0., 0.);
324    IUFillNumber(&GeographicCoordsWN[1], "LONG", "Long D", "%10.6m", 0., 360., 0., 0.);
325    IUFillNumberVector(&GeographicCoordsWNP, GeographicCoordsWN, NARRAY(GeographicCoordsWN), mydev, "GEOGRAPHIC_COORD" , "Geographic coords", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
326
327    // Pression température - SET
328    IUFillNumber(&PressionTempWN[0], "Pression", "Pression mb", "%10.6m",  0., 1500., 0., 0.);
329    IUFillNumber(&PressionTempWN[1], "Temperature", "Temperature °c", "%10.6m", -50., +50., 0., 0.);
330    IUFillNumberVector(&PressionTempWNP, PressionTempWN, NARRAY(PressionTempWN), mydev, "PRESSION_DATA" , "Pression, Temperature", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
331
332    // Actualisation - SET
333    IUFillNumber(&ActualisationN1[0], "DELAY", "Transit delay (s)", "%10.6m",  0., 3600., 0., 0.);
334    IUFillNumberVector(&ActualisationNP1, ActualisationN1, NARRAY(ActualisationN1), mydev, "DELAY1" , "", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
335
336    IUFillNumber(&ActualisationN2[0], "DELAY", "Tracking delay (s)", "%10.6m",  0., 3600., 0., 0.);
337    IUFillNumberVector(&ActualisationNP2, ActualisationN2, NARRAY(ActualisationN2), mydev, "DELAY2" , "", OPTIONS_GROUP, IP_WO, 0, IPS_IDLE);
338}
339
340
341/**************************************************************************************
342** Définition de tous les vecteurs de la boîte de dialogue INDI
343** Cette procédure doit être obligatoirement présente dans tous pilotes Indi
344**
345***************************************************************************************/
346
347void BAO::ISGetProperties(const char *dev)
348{
349
350    if (dev && strcmp (mydev, dev))
351        return;
352
353    // Main Control
354    IDDefSwitch(&ConnectSP, NULL);
355    IDDefText(&ObjectTP, NULL);
356    IDDefNumber(&EquatorialCoordsWNP, NULL);
357    IDDefText(&CommandTP, NULL);
358    IDDefSwitch(&OnCoordSetSP, NULL);
359    IDDefSwitch(&AlignmentSP, NULL);
360    IDDefSwitch(&AbortSlewSP, NULL);
361    IDDefSwitch(&ParkSP, NULL);
362
363    // Options
364    IDDefNumber(&ActualisationNP1, NULL);
365    IDDefNumber(&ActualisationNP2, NULL);
366    IDDefNumber(&PressionTempWNP, NULL);
367    IDDefNumber(&GeographicCoordsWNP, NULL);
368}
369
370
371/**************************************************************************************
372** Initialisation des vecteurs de la boîte Indi
373** Cette procédure doit être obligatoirement présente dans tous pilotes Indi
374**
375***************************************************************************************/
376
377void BAO::reset_all_properties()
378{
379    ConnectSP.s                 = IPS_IDLE;
380    OnCoordSetSP.s              = IPS_IDLE;
381    AlignmentSP.s               = IPS_IDLE;
382    AbortSlewSP.s               = IPS_IDLE;
383    ParkSP.s                    = IPS_IDLE;
384    ObjectTP.s                  = IPS_IDLE;
385    EquatorialCoordsWNP.s       = IPS_IDLE;
386    CommandTP.s                 = IPS_IDLE;
387    PressionTempWNP.s           = IPS_IDLE;
388    GeographicCoordsWNP.s       = IPS_IDLE;
389    ActualisationNP1.s          = IPS_IDLE;
390    ActualisationNP2.s          = IPS_IDLE;
391
392    IUResetSwitch(&OnCoordSetSP);
393    IUResetSwitch(&AlignmentSP);
394    IUResetSwitch(&AbortSlewSP);
395    IUResetSwitch(&ParkSP);
396
397    OnCoordSetS[0].s = ISS_ON;
398    AlignmentS[0].s = ISS_ON;
399    ConnectS[0].s = ISS_OFF;
400    ConnectS[1].s = ISS_ON;
401
402    IDSetSwitch(&ConnectSP, NULL);
403    IDSetSwitch(&OnCoordSetSP, NULL);
404    IDSetSwitch(&AlignmentSP, NULL);
405    IDSetSwitch(&AbortSlewSP, NULL);
406    IDSetSwitch(&ParkSP, NULL);
407    IDSetText(&ObjectTP, NULL);
408    IDSetText(&CommandTP, NULL);
409    IDSetNumber(&EquatorialCoordsWNP, NULL);
410    IDSetNumber(&PressionTempWNP, NULL);
411    IDSetNumber(&GeographicCoordsWNP, NULL);
412    IDSetNumber(&ActualisationNP1, NULL);
413    IDSetNumber(&ActualisationNP2, NULL);
414}
415
416
417
418/**************************************************************************************
419** En cas de changement de texte dans la boîte de dialogue (par exemple : changement du
420** nom de l'objet) alors suivre l'objet...
421** Cette fonction n'est pas utilisée
422** TODO: faut-il proposer cette fonction depuis la boîte alors qu'il est déjà
423** possible de le faire depuis  Kstars et BAOcontrol ?
424**
425**
426***************************************************************************************/
427
428void BAO::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
429{
430    // Ignore if not ours
431    if (strcmp (dev, mydev))
432        return;
433
434    if (is_connected() == false)
435    {
436        IDMessage(mydev, "Error ! Please connect before issuing any commands.");
437        reset_all_properties();
438        return;
439    }
440
441    // ===================================
442    // Object Name
443    // ===================================
444    if (!strcmp (name, ObjectTP.name))
445    {
446        if (IUUpdateText(&ObjectTP, texts, names, n) < 0)
447            return;
448
449        ObjectTP.s = IPS_OK;
450        IDSetText(&ObjectTP, NULL);
451        return;
452    }
453
454
455    // ===================================
456    // Commands
457    // ===================================
458    if (!strcmp (name, CommandTP.name))
459    {
460        if (IUUpdateText(&CommandTP, texts, names, n) < 0)
461            return;
462
463        IText *eqp = IUFindText (&CommandTP, names[0]);
464
465
466        if (eqp == &CommandT[0])
467        {
468            char chaine[100];
469
470            bool result = false;
471
472            strcpy(chaine, texts[0]);
473
474            if (chaine[0] == 'G')
475            {
476                for (int i = 1; i<=strlen(chaine); i++) chaine[i-1]=chaine[i];
477               
478                IDLog(chaine);
479
480                for (int i = 1; i<SocketsNumber; i++ )
481                {
482                    if (Sockets[i].Connected)
483                    {
484                        result = COMMANDE(i, (char*)"G", chaine);
485                    }
486                }
487            }
488            else
489            {
490                for (int i = 1; i<SocketsNumber; i++ )
491                {
492                    if (Sockets[i].Connected)
493                    {
494                        result = COMMANDE(i, chaine, (char*)"");
495                    }
496                }
497            }
498
499            (result) ? CommandTP.s = IPS_OK : CommandTP.s = IPS_ALERT;
500
501            IDSetText(&CommandTP, NULL);
502        }
503        return;
504    }
505}
506
507
508
509/**************************************************************************************
510** En cas de changement d'une valeur numérique dans la boîte de dialogue Indi
511** Exemple : longitude, latitude, ar, dec etc...) -> prendre en compte les modifications
512**
513** const char *dev  contient le nom du dispositif recevant le message (ici indi_BAO)
514** const char *name reçoit  le nom de la rubrique modifiée par l'utilisateur
515** (ex : les coordonnées géographiques, les coordonnées horaires de l'objet etc...)
516** double names[] contient la liste de tous les champs modifiables dans chaque rubrique
517** (ex : longitude et latitude dans la rubrique coordonnées géographiques
518** char *values[] contient toutes les valeurs (numériques ou non) mais toujours exprimées
519** sous la forme d'une chaîne de caractÚres
520**
521***************************************************************************************/
522
523void BAO::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
524{
525
526    // Ignore if not ours
527
528    if (strcmp (dev, mydev))
529        return;
530
531    // Si pas de connexion -> on sort
532
533    if (is_connected() == false)
534    {
535        IDMessage(mydev, "Error ! BAO is offline. Please connect before issuing any commands.");
536
537        reset_all_properties();
538
539        return;
540    }
541
542
543    // ===================================
544    // Geographic  Coords
545    // ===================================
546
547    if (!strcmp (name, GeographicCoordsWNP.name))
548    {
549        // l'utilisateur a modifié une des coordonnées géographiques de la boite indi
550
551        int i = 0, nset = 0;
552
553        // En cas d'erreur, on doit pouvoir sortir avec des paramÚtres par défaut
554        // ici la latitude et la longitude valent 0.0
555
556        Latitude  = 0.0;
557        Longitude = 0.0;
558
559        // pour ce vecteur, on sait qu'il y a n éléments possibles
560        // Exemple pour la rubrique coordonnées géographique de la boîte indi
561        // il y a deux éléments : la longitude et la latitude
562        // pour la rubrique alignement, il y a en a trois : simple, affine et taki
563
564        for (i = 0; i < n; i++)
565        {
566            // pour chacun d'entre eux, on regarde si le nom passé en argument de la fonction (*name)
567            // correspond bien à l'un des éléments du vecteur GeographicCoordsWNP
568
569            INumber *eqp = IUFindNumber (&GeographicCoordsWNP, names[i]);
570
571            if (eqp == &GeographicCoordsWN[0])
572            {
573                // ici on a identifié la zone latitude de la boîte de dialogue
574                // Value[i] contient la chaîne de caractÚre correspondante dans la boîte
575                // C'est la valeur saisie par l'utilisateur
576
577                Latitude = values[i];
578
579                // On doit vérifier que la latitude est dans un intervalle correct
580
581                nset += Latitude >= -90.0 && Latitude <= 90.0;
582
583                // on convertit en radians
584
585                Latitude *= Pidiv180;
586            }
587            else if (eqp == &GeographicCoordsWN[1])
588            {
589                // ici on a identifié une modification dans la rubrique longitude
590
591                Longitude = values[i];
592
593                // dans l'intervalle ?
594
595                nset += Longitude >= 0.0 && Longitude <= 360.0;
596
597                // en radians
598
599                Longitude *= -Pidiv180;
600            }
601        }
602
603        // Si la longitude et la latitude sont correctes
604        // on envoie les coordonnées à la classe Astro
605        if (nset == 2)
606        {
607            // Vérification
608            // AfficherLog("Geographic : RA %5.2f - DEC %5.2f\n", Latitude, Longitude);
609
610            // nset vaut 2, nous sommes donc sûrs qu'il n'y a pas de problÚme dans les valeurs
611            // saisies par l'utilisateur
612            // voir le code plus haut pour comprendre...
613
614            // On change la couleur de la "diode" de la rubrique coordonnées
615            // géographiques de la boîte en vert
616
617            GeographicCoordsWNP.s = IPS_OK;
618
619            // pas de message d'erreur dans la boîte
620
621            IDSetNumber(&GeographicCoordsWNP, NULL);
622        }
623        else
624        {
625            // quelque chose cloche
626            // peut-être l'une des valeurs saisies par l'utilisateur n'est-elle pas dans
627            // le bon intervalle ? ex : lat = 150°
628
629            // on change la couleur de la diode
630
631            GeographicCoordsWNP.s = IPS_ALERT;
632
633            // on affiche un message d'erreur
634
635            IDSetNumber(&GeographicCoordsWNP, "Latitude or Longitude missing or invalid");
636
637            // on fixe arbitrairement les valeurs à 0
638
639            Latitude  = 0.0;
640            Longitude = 0.0;
641        }
642
643        // c'est bon. On peut donc transmettre les nouvelles valeurs à la classe astro
644        // qui utilisera ces informations pur calculer l'azimut des objets et le temps sidéral local en particulier...
645
646        DefinirLongitudeLatitude(Longitude, Latitude);
647
648        return;
649    }
650
651
652    // ===================================
653    // Equatorial Coords
654    // ===================================
655    if (!strcmp (name, EquatorialCoordsWNP.name))
656    {
657        int i = 0, nset = 0;
658
659        double newRA =0.0, newDEC =0.0;
660
661        // nous avons le même principe de fonctionnement que pour les coordonnées géographiques
662
663        for (i = 0; i < n; i++)
664        {
665            INumber *eqp = IUFindNumber (&EquatorialCoordsWNP, names[i]);
666
667            if (eqp == &EquatorialCoordsWN[0])
668            {
669                // on a compris que l'utilisateur avait changé l'ascension droite de l'objet
670
671                // on affecte la nouvelle valeur à newRA
672
673                newRA = values[i];
674
675                // Est-ce que cette valeur est dans le bon intervalle ?
676
677                nset += newRA >= 0 && newRA <= 24.0;
678            }
679            else if (eqp == &EquatorialCoordsWN[1])
680            {
681                // même chose pour la déclinaison
682                newDEC = values[i];
683
684                nset += newDEC >= -90.0 && newDEC <= 90.0;
685            }
686        }
687
688
689        // si les coordonnées de l'objet sont correctes
690
691        if (nset == 2)
692        {
693            char RAStr[32], DecStr[32];
694            double targetAZ, targetAlt;
695
696            // On garde une trace des nouvelles coordonnées saisies par l'utilisateur
697
698            targetRA  = newRA;
699            targetDEC = newDEC;
700
701            // on les affiche dans les logs
702
703            fs_sexa(RAStr, newRA, 2, 3600);
704            fs_sexa(DecStr, newDEC, 2, 3600);
705
706            AfficherLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr);
707
708            // on convertit les coordonnées équatoriales de la zone du ciel observée
709            // en unités de codeurs des moteurs
710
711            ADDEC2Motor(newRA, newDEC);
712
713            // on déclenche le goto
714
715            if (process_coords() == false)
716            {
717                EquatorialCoordsWNP.s = IPS_ALERT;
718
719                IDSetNumber(&EquatorialCoordsWNP, NULL);
720            }
721        }
722        else
723        {
724            EquatorialCoordsWNP.s = IPS_ALERT;
725
726            IDSetNumber(&EquatorialCoordsWNP, "Error ! RA or Dec missing or invalid");
727        }
728
729        return;
730    }
731
732
733    // ===================================
734    // Pression, Temperature
735    // ===================================
736    if (!strcmp (name, PressionTempWNP.name))
737    {
738        int i = 0, nset = 0;
739
740        double newPression =0.0, newTemperature =0.0;
741
742        // nous avons le même principe de fonctionnement que pour les coordonnées géographiques
743
744        for (i = 0; i < n; i++)
745        {
746            INumber *eqp = IUFindNumber (&PressionTempWNP, names[i]);
747
748            if (eqp == &PressionTempWN[0])
749            {
750                // on a compris que l'utilisateur a changé l'ascension droite de l'objet
751
752                // on affecte la nouvelle valeur à newRA
753
754                newPression = values[i];
755
756                // Est-ce que cette valeur est dans le bon intervalle ?
757
758                nset += newPression >= 0.0 && newPression <= 1500.0;
759            }
760            else if (eqp == &PressionTempWN[1])
761            {
762                //même chose pour la déclinaison
763                newTemperature = values[i];
764
765                nset += newTemperature >= -50.0 && newTemperature <= 50.0;
766            }
767        }
768
769
770        // si les coordonnées de l'objet sont correctes
771
772        if (nset == 2)
773        {
774            PressionTempWNP.s = IPS_OK;
775
776            IDSetNumber(&PressionTempWNP, NULL);
777
778            Pression = newPression;
779            Temp = newTemperature;
780        }
781        else
782        {
783            PressionTempWNP.s = IPS_ALERT;
784
785            IDSetNumber(&PressionTempWNP, "Error ! Bad values for pression or temperature");
786        }
787
788        return;
789    }
790
791
792    // ===================================
793    // Actualisation
794    // ===================================
795    if (!strcmp (name, ActualisationNP1.name))
796    {
797        // on a ici exactement le même fonctionnement que précédemment
798        // on rÚgle ici les valeurs des délais entre deux actualisations
799        // de la position en mode transit et tracking
800        // Retourne un message d'erreur si les durées ne sont pas exprimées
801        // dans un intervalle > 0 et < 3600
802
803        double newAct1 = 1.0;
804
805        for (int i = 0; i < n; i++)
806        {
807            INumber *eqp = IUFindNumber (&ActualisationNP1, names[i]);
808
809            if (eqp == &ActualisationN1[0])
810            {
811                newAct1 = values[i];
812
813                if ( newAct1 >= 0.0 && newAct1 <= 3600.0 )
814                {
815                    ActualisationTMTransit = newAct1;
816
817                    ActualisationNP1.s = IPS_OK;
818
819                    IDSetNumber(&ActualisationNP1, NULL);
820                }
821                else
822                {
823                    ActualisationNP1.s = IPS_ALERT;
824
825                    IDSetNumber(&ActualisationNP1, "Error ! Delay invalid");
826                }
827            }
828        }
829    }
830
831    if (!strcmp (name, ActualisationNP2.name))
832    {
833        double newAct2 = 1.0;
834
835        for (int i = 0; i < n; i++)
836        {
837            INumber *eqp = IUFindNumber (&ActualisationNP2, names[i]);
838
839            if (eqp == &ActualisationN2[0])
840            {
841                newAct2 = values[i];
842
843                if ( newAct2 >= 0.0 && newAct2 <= 3600.0 )
844                {
845                    ActualisationTMTracking = newAct2;
846
847                    ActualisationNP2.s = IPS_OK;
848
849                    IDSetNumber(&ActualisationNP2, NULL);
850                }
851                else
852                {
853                    ActualisationNP2.s = IPS_ALERT;
854                    IDSetNumber(&ActualisationNP2, "Error ! Delay invalid");
855                }
856            }
857        }
858    }
859}
860
861
862
863/**************************************************************************************
864** L'utilisateur clique sur l'un des boutons de la boîte Indi
865** Même observation que pour la procédure précédente
866**
867***************************************************************************************/
868
869void BAO::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
870{
871    // ignore if not ours //
872    if (strcmp (mydev, dev))
873        return;
874
875    // ===================================
876    // Connect Switch
877    // ===================================
878    if (!strcmp (name, ConnectSP.name))
879    {
880        if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0)
881            return;
882
883        connect_telescope();
884
885        return;
886    }
887
888    if (is_connected() == false)
889    {
890        IDMessage(mydev, "Error ! BAORadio is offline. Please connect before issuing any commands.");
891        reset_all_properties();
892        return;
893    }
894
895    // ===================================
896    // Coordinate Set
897    // ===================================
898    if (!strcmp(name, OnCoordSetSP.name))
899    {
900        if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0)
901            return;
902
903        currentSet = get_switch_index(&OnCoordSetSP);
904        OnCoordSetSP.s = IPS_OK;
905        IDSetSwitch(&OnCoordSetSP, NULL);
906    }
907
908    // ===================================
909    // Alignment Set
910    // ===================================
911    if (!strcmp(name, AlignmentSP.name))
912    {
913        if (IUUpdateSwitch(&AlignmentSP, states, names, n) < 0)
914            return;
915
916        MethodeAlignement = get_switch_index(&AlignmentSP) + 1 ;
917
918        /*char chaine[100];
919        sprintf(chaine, "****************************************** %i\n", MethodeAlignement);
920        AfficherLog(chaine);*/
921
922        AlignmentSP.s = IPS_OK;
923        IDSetSwitch(&AlignmentSP, NULL);
924
925        for (int i=0; i<MAXHOSTNAME; i++)
926        {
927            switch (MethodeAlignement)
928            {
929            case 1 :
930                Sockets[i].AlignementAntenne->MethodeAlignement = SIMPLE;
931                break;
932            case 2 :
933                Sockets[i].AlignementAntenne->MethodeAlignement = AFFINE;
934                break;
935            case 3 :
936                Sockets[i].AlignementAntenne->MethodeAlignement = TAKI;
937                break;
938            }
939        }
940
941        return;
942    }
943
944    // ===================================
945    // Abort slew
946    // ===================================
947    if (!strcmp (name, AbortSlewSP.name))
948    {
949        Abort = true;
950
951        IUResetSwitch(&AbortSlewSP);
952
953        if (EquatorialCoordsWNP.s == IPS_OK)
954        {
955            AbortSlewSP.s = IPS_OK;
956            EquatorialCoordsWNP.s = IPS_IDLE;
957            ObjectTP.s = IPS_IDLE;
958            CommandTP.s = IPS_IDLE;
959
960            IDSetSwitch(&ConnectSP, "Envoi de la commande Abort\n");
961            IDSetNumber(&EquatorialCoordsWNP, NULL);
962            IDSetText(&ObjectTP, NULL);
963            IDSetText(&CommandTP, NULL);
964        }
965
966        return;
967    }
968
969
970    // ===================================
971    // Park
972    // ===================================
973    if (!strcmp (name, ParkSP.name))
974    {
975        Park=true;
976
977        IUResetSwitch(&ParkSP);
978
979        if (EquatorialCoordsWNP.s == IPS_OK)
980        {
981            AbortSlewSP.s = IPS_OK;
982            EquatorialCoordsWNP.s = IPS_IDLE;
983            ObjectTP.s = IPS_IDLE;
984            CommandTP.s = IPS_IDLE;
985
986            IDSetSwitch(&ConnectSP, "Envoi de la commande Park\n");
987            IDSetNumber(&EquatorialCoordsWNP, NULL);
988            IDSetText(&ObjectTP, NULL);
989            IDSetText(&CommandTP, NULL);
990        }
991
992        return;
993    }
994}
995
996
997
998/**************************************************************************************
999** Gestion du thread
1000** permet de suivre la connexion/déconnexion des antennes toutes les secondes
1001**
1002** l'utilisation d'un thread permet de contourner le problÚme de la fonction accept
1003** qui est bloquante.
1004** L'adresse IP de l'antenne qui a effectué la connexion est consignée dans la variable IP
1005** de la structure Sockets. L'état de l'antenne (connected) est placée à true
1006**
1007***************************************************************************************/
1008
1009void *BAO::pThreadSocket ()
1010{
1011    do
1012    {
1013        try
1014        {
1015            server.accept( Sockets[SocketsNumber].new_sock );
1016
1017            Sockets[SocketsNumber].IP = server.recupip(Sockets[SocketsNumber].new_sock);
1018
1019            Sockets[SocketsNumber].AlignementAntenne->MethodeAlignement = MethodeAlignement;
1020
1021            Sockets[SocketsNumber++].Connected = true;
1022
1023            InitThreadOK = true;
1024        }
1025        catch ( SocketException& e )
1026        {
1027            /*AfficherLog("Indi_BAO, pThreadSocket exception : ");
1028            AfficherLog(e.description().c_str());
1029            AfficherLog("\n");*/
1030        }
1031
1032        sleep(1); // faire une pause pour éviter de consommer trop de temps CPU -> à vérifier
1033    }
1034    while (!Exit);
1035
1036    pthread_exit (0);
1037}
1038
1039
1040
1041/**************************************************************************************
1042** Astuce pour lancer le thread depuis la classe BAO
1043**
1044***************************************************************************************/
1045
1046void* LancementThread(BAO * appli)
1047{
1048    appli->pThreadSocket();
1049
1050    return 0;
1051}
1052
1053
1054/**************************************************************************************
1055** Extraction de la position de l'antenne aprÚs l'envoi de la commande P
1056** Le retour de la commande P est POSITION/valeur_az/valeur_alt/
1057** Ce retour est envoyé dans la chaîne str
1058** ExtractPosition retourne une structure Position contenant Valeur_az et Valeur_alt
1059** Ex: ExtractPosition("POSITION/0100/0001/", result)  retourne result.x=100 et result.y=1
1060**
1061***************************************************************************************/
1062
1063bool BAO::ExtractPosition(string str, Position *result)
1064{
1065    string str2;
1066
1067    int pos = str.find("/");
1068
1069    if (pos != string::npos)
1070    {
1071        str2 = str.substr(pos + 1);
1072
1073        pos = str2.find("/");
1074
1075        if (pos != string::npos)
1076        {
1077            result->x = atol( str2.substr(0, pos).c_str() );
1078
1079            result->y = atol( str2.substr(pos + 1).c_str() );
1080
1081            return true;
1082        }
1083    }
1084
1085    AfficherLog((str +" failed !\n").c_str());
1086
1087    return false;
1088}
1089
1090
1091
1092/************************************************************************************
1093** Cette procédure, aprÚs avoir appliqué la matrice de rotation aux coordonnées de l'objet
1094** visées par l'utilisateur, effectue les conversions en unités codeurs des paraboles
1095** (càd en nb de tours des deux axes moteurs depuis la position PARK)
1096**
1097************************************************************************************/
1098
1099void BAO::ADDEC2Motor(double newRA, double newDEC)
1100{
1101    double targetAz;
1102    double targetAlt;
1103    double newRA2  = newRA * 15.0 * Pidiv180;
1104    double newDEC2 = newDEC * Pidiv180;
1105    char AzStr[32];
1106    char AltStr[32];
1107    Coord result, vect;
1108
1109    // Pour toutes les antennes connectées
1110
1111    for (int i=0; i<SocketsNumber; i++)
1112    {
1113        // On vérifie qu'elles sont encore connectées
1114
1115        if (Sockets[i].Connected)
1116        {
1117            newRA  = newRA2;
1118            newDEC = newDEC2;
1119
1120            // Dans les modes d'alignement AFFINE et TAKI, on applique la matrice de correction
1121            // sur les coordonnées horaires de l'objet visé
1122
1123            // il faut vérifier auparavant que la matrice de rotation est disponible
1124            // pour l'antenne i
1125
1126            if  (Sockets[i].AlignementAntenne->Matrice_ok)
1127            {
1128                // On est bien dans le cas de l'alignement AFFINE ou Taki
1129
1130                if (Sockets[i].AlignementAntenne->MethodeAlignement ==  AFFINE ||
1131                        Sockets[i].AlignementAntenne->MethodeAlignement ==  TAKI)
1132                {
1133                    // On crée un vecteur avec pour coordonnées
1134                    // x = Angle horaire de l'objet visé
1135                    // y = déclinaison de l'objet
1136                    // z = 1.0
1137                    // Voir la documentation pour plus d'explications sur le calcul affine/taki
1138
1139                    vect.x = VerifAngle( newRA2 - GetTSL() );
1140                    vect.y = newDEC2;
1141                    vect.z = 1.0;
1142
1143                    // Message pour l'utilisateur et les logs
1144
1145                    AfficherLog("Application de la matrice AFFINE/TAKI\nCoordonnees initiales: AD = %s  Dec = %s\n", DHMS(newRA2*N180divPi, true ).c_str(),
1146                                DHMS(newDEC2*N180divPi, false ).c_str());
1147
1148                    // On applique la matrice de transformation
1149
1150                    switch (Sockets[i].AlignementAntenne->MethodeAlignement)
1151                    {
1152                    case AFFINE :
1153                        Sockets[i].AlignementAntenne->AppliquerMatriceCorrectionAffine(&result, vect);
1154                        break;
1155                    case TAKI   :
1156                        Sockets[i].AlignementAntenne->AppliquerMatriceCorrectionTaki( &result, vect);
1157                        break;
1158                    }
1159
1160                    // On récupÚre les nouvelles coordonnées. z ne nous intéresse pas
1161
1162                    newRA  = VerifAngle(result.x + GetTSL());
1163                    newDEC = result.y;
1164
1165                    AfficherLog("Coordonnees finales: AD = %s  Dec = %s\n", DHMS(newRA*N180divPi, true ).c_str(),
1166                                DHMS(newDEC*N180divPi, false ).c_str());
1167                }
1168            }
1169            else
1170            {
1171                if (Sockets[i].AlignementAntenne->AlignementEnCours)
1172                {
1173                    // Si la matrice n'est pas prête, c'est que la procédure d'alignement de l'antenne i n'est pas encore achevée.
1174                    // On se contente ici d'appliquer des deltas en ascension droite et en déclinaison. Ces deltas sont envoyés de BAOcontrol
1175                    // au driver indi_BAO par l'intermédiaire du fichier AlignementAntennes.cfg
1176                    // Consultez la documentation pour comprendre le principe de fonctionnement de l'alignement et de la communication
1177                    // entre les deux programmes
1178
1179                    newRA  = VerifAngle(newRA2  + Sockets[i].AlignementAntenne->delta_ad[Sockets[i].AlignementAntenne->nbrcorrections] * PasDeltaAD);
1180                    newDEC = newDEC2 + Sockets[i].AlignementAntenne->delta_de[Sockets[i].AlignementAntenne->nbrcorrections] * PasDeltaDe;
1181
1182                    AfficherLog("Alignement en cours.\nDelta RA=%i  delta Dec=%i\n", Sockets[i].AlignementAntenne->delta_ad[Sockets[i].AlignementAntenne->nbrcorrections], Sockets[i].AlignementAntenne->delta_de[Sockets[i].AlignementAntenne->nbrcorrections]);
1183                    AfficherLog("Nouvelles Coordonnées AD =%s  Dec = %s\n", DHMS(newRA*N180divPi, true).c_str(), DHMS(newDEC*N180divPi, false).c_str());
1184                }
1185            }
1186
1187            // Calcule la hauteur et l'azimut de la zone du ciel pointée (en fonction de la date et du lieu d'observation)
1188
1189            Azimut( newRA, newDEC, &targetAz, &targetAlt);
1190
1191            // Si la méthode d'alignement est la méthode SIMPLE, alors on doit cette fois-ci appliquer la matrice
1192            // de correction au coordonnées horizontales et non aux coordonnées horaires comme ce que nous
1193            // avons vu plus haut
1194
1195            if  (Sockets[i].AlignementAntenne->Matrice_ok && Sockets[i].AlignementAntenne->MethodeAlignement == SIMPLE)
1196            {
1197                // AprÚs s'être assurer que nous utilisons la méthode SIMPLE et que la matrice de rotation est ok
1198
1199                AfficherLog("Application de la matrice SIMPLE\nCoordonnees initiales: Azi = %s  Haut = %s\n", DHMS(targetAz*N180divPi, false ).c_str(),
1200                            DHMS(targetAlt*N180divPi, false ).c_str());
1201
1202                // On constitue un vecteur vect
1203                // Les coordonnées du vecteur correspondent à la position
1204                // d'un point défini par une latitude targetAlt et une longitude targetAz
1205                // sur une sphÚre de rayon 1.
1206                // On reconnaît les formules de passage des coordonnées
1207                // sphériques aux coordonnées rectangulaires
1208
1209
1210                vect.x = cos(targetAz) * cos(targetAlt);
1211                vect.y = sin(targetAz) * cos(targetAlt);
1212                vect.z = sin(targetAlt);
1213
1214
1215                // Application de la matrice SIMPLE
1216
1217                Sockets[i].AlignementAntenne->AppliquerMatriceCorrectionSimple(&result, vect);
1218
1219
1220                // Là on doit repasser des coordonnées rectangulaires
1221                // aux coordonnées sphériques
1222
1223                if (result.x != 0.0)
1224                {
1225                    targetAz = atan( result.y / result.x );
1226
1227                    if (result.x < 0) targetAz += Pi;
1228                }
1229                else targetAz = Pidiv2;
1230
1231                targetAz  = VerifAngle(targetAz);
1232
1233                targetAlt = asin(result.z);
1234
1235
1236                AfficherLog("Coordonnees finales: Azi = %s  Haut = %s\n", DHMS(targetAz*N180divPi, false ).c_str(),
1237                            DHMS(targetAlt*N180divPi, false ).c_str());
1238            }
1239
1240            // Application du delta en azimut (préalablement réglé sur la polaire)
1241            // Correspond à la variable AlignementAntenne->delta_az_polar
1242            // Ne s'applique que pour les alignements AFFINE et TAKI
1243
1244            if (Sockets[i].AlignementAntenne->MethodeAlignement != SIMPLE) targetAz += Sockets[i].AlignementAntenne->delta_az_polar * PasDeltaAD;
1245
1246            // Correction de la réfraction atmosphérique
1247
1248            targetAlt = RefractionAtmospherique(targetAlt);
1249
1250            // On ajoute Pi pour que le sud soit à 0° d'azimut
1251
1252            targetAz = VerifAngle( targetAz + Pi );
1253
1254            // On convertit les angles précédents en degrés
1255
1256            targetAlt *= N180divPi;
1257            targetAz  *= N180divPi;
1258
1259            // Affichage dans les logs
1260
1261            fs_sexa(AzStr, targetAz, 2, 3600);
1262            fs_sexa(AltStr, targetAlt, 2, 3600);
1263
1264            AfficherLog("Coordonnees horizontales finales: Azi = %s  Haut= %s\n", AzStr, AltStr);
1265
1266
1267            // Conversion des deux angles en pas codeurs
1268
1269            /*  if ( targetAlt < HAUTMIN )
1270              {
1271                  // L'objet est trop bas ( < 30°). On annule le suivi...
1272
1273                  IDSetSwitch(&OnCoordSetSP, "Erreur ! L objet suivi est situe a moins de 30 deg au-dessus de l horizon. Goto annule.");
1274
1275                  Suivi = false;
1276
1277                  RealisationGoto = false;
1278
1279                  InitAntennes();
1280
1281                  return;
1282              }
1283              else*/
1284            {
1285                // Si la hauteur est supérieure à 90°, on doit ajouter 180° à l'azimut et corriger
1286                // la hauteur en appliquant hauteur=180°-hauteur
1287
1288                if (targetAlt > 90.0)
1289                {
1290                    targetAlt = 180.0 - targetAlt;
1291                    targetAz += 180.0;
1292                }
1293
1294                if ( targetAlt < HAUTMIN ) targetAlt = HAUTMIN;
1295
1296                // On applique la formule de Marc pour convertir la hauteur en nombre de pas codeur alt
1297
1298                Sockets[i].TargetPosition.y = (int) Arrondi( Alt2Motor( targetAlt ) );
1299
1300                //4000 pas pour 360° sur l'axe az
1301
1302                Sockets[i].TargetPosition.x = (int) Arrondi( targetAz * (double)NBREPASCODEURSAZ / 360.0);
1303
1304                // Message de debug
1305
1306                AfficherLog("Nbre de pas codeurs Az = %i  Alt = %i\n", Sockets[i].TargetPosition.x, Sockets[i].TargetPosition.y);
1307            }
1308        }
1309    }
1310}
1311
1312
1313
1314/************************************************************************************
1315** Retourne le nombre d'antennes actuellement connectées
1316**
1317************************************************************************************/
1318
1319int BAO::AntennesConnectees()
1320{
1321    int num = 0;
1322
1323    for (int i=1; i<SocketsNumber; i++) if (Sockets[i].Connected) num++;
1324
1325    return num;
1326}
1327
1328
1329
1330/**************************************************************************************
1331** En cas de problÚme
1332** Déconnecter l'antenne utilisant le socket num
1333***************************************************************************************/
1334
1335void BAO::DeconnecterSocket(int num)
1336{
1337    if (Sockets[num].Connected) AfficherLog("Deconnexion de l antenne : %s\n", Sockets[num].IP.c_str());
1338    Sockets[num].new_sock.shutdown();
1339    Sockets[num].Connected = false;
1340    Sockets[num].IP = "";
1341}
1342
1343
1344
1345
1346/**************************************************************************************
1347** Procédure principale
1348** Elle est appelée toutes les ms
1349**
1350***************************************************************************************/
1351
1352void BAO::ISPoll()
1353{
1354    static int memSocketsNumber = -1;      // Combien y avait-il d'antennes connectées lors de l'appel précédent d'ISPoll ?
1355    static unsigned int compt   =  0;      // Compteur de la fonction ISPoll
1356
1357    struct tm date;
1358    time_t t;
1359    struct timeval tv;
1360    struct timezone tz;
1361
1362    //si pas de connexion avec le serveur d'indi -> on sort
1363
1364    if (!is_connected()) return;
1365
1366
1367    // toutes les 100 millisec, on actualise le jour julien
1368    // le temps sidéral local etc...
1369
1370    if ( compt%100 == 0 )
1371    {
1372        //Récupération de la date et de l'heure
1373
1374        time(&t);
1375        date=*gmtime(&t);
1376        gettimeofday(&tv, &tz);
1377
1378        double Annee = (double)(date.tm_year + 1900);
1379        double Mois  = (double)(date.tm_mon + 1);
1380        double Jour  = (double)date.tm_mday;
1381        double Heu   = (double)date.tm_hour;
1382        double Min   = (double)date.tm_min;
1383        double Sec   = (double)date.tm_sec+tv.tv_usec/1.0E6;
1384        double UTCP  = 0.0;//(double)date.tm_isdst;
1385
1386        // On transmet la date et l'heure à la classe Astro
1387
1388        DefinirDateHeure(Annee, Mois, Jour, Heu, Min, Sec);
1389
1390        // Puis on calcule le temps sidéral local, le JJ etc.
1391
1392        CalculTSL();
1393
1394
1395        // On charge les paramÚtres de correction des antennes toutes les demi-secondes
1396
1397        if ( compt%500 == 0  && tv.tv_usec/1.0E6 > 0.5 )
1398        {
1399            for (int i=1; i<SocketsNumber; i++)
1400            {
1401                if (Sockets[i].Connected)
1402                {
1403                    // Si l'antenne i est connectée, on charge les paramÚtres
1404                    Sockets[i].AlignementAntenne->TransmettreParametresClasseAstro(Annee, Mois, Jour, Heu, Min, Sec, Longitude, Latitude, Pression, Temp);
1405
1406                    if (Sockets[i].AlignementAntenne->MethodeAlignement == SIMPLE )
1407                    {
1408                        //AfficherLog("chargement simple\n");
1409                        Sockets[i].AlignementAntenne->ChargementParametresAlignement(Sockets[i].IP, "/home/" + (string)getenv("USER") + "/AlignementAntennesSIMPLE.cfg", targetRA * 15 * Pidiv180, targetDEC * Pidiv180);
1410                    }
1411                    else
1412                    {
1413                        // AfficherLog("chargement taki\n");
1414                        Sockets[i].AlignementAntenne->ChargementParametresAlignement(Sockets[i].IP, "/home/" + (string)getenv("USER") + "/AlignementAntennesTAKI.cfg", targetRA * 15 * Pidiv180, targetDEC * Pidiv180);
1415                    }
1416                }
1417            }
1418        }
1419    }
1420
1421
1422
1423    // Il faut que le thread soit actif
1424
1425    if (InitThreadOK)
1426    {
1427
1428        // Nouvelle connexion sur le socket ?
1429
1430        if (SocketsNumber > memSocketsNumber)
1431        {
1432            memSocketsNumber = SocketsNumber;
1433
1434            IDSetSwitch(&ConnectSP, "Connexion de l antenne %s (Antennes connectees : %i)",
1435                        Sockets[SocketsNumber-1].IP.c_str(), AntennesConnectees());
1436        }
1437
1438
1439        /////////////////////////////////////////////////
1440        // Début des échanges avec les micro-contrÃŽleurs
1441
1442        // Analyse des réponses des micro-contrÃŽleurs
1443
1444        for (int i=1; i<SocketsNumber; i++)
1445        {
1446            if (Sockets[i].Connected)
1447            {
1448                try
1449                {
1450                    string reponse, buffereponse;
1451
1452                    // on récupÚre la réponse du micro-contrÃŽleur
1453
1454                    Sockets[i].new_sock >> reponse;
1455
1456                    // Dans le cas où plusieurs trames seraient arrivées entre deux appels de POLLMS
1457                    // les traiter successivement
1458
1459                    // d'où l'intérêt de mettre un '\n' à la fin des trames
1460                    // pour différencier une trame de la précédente
1461
1462                    int pos = reponse.find("\n");
1463
1464                    // S'il y a une réponse
1465
1466                    while ((pos != string::npos) && (reponse.length() > 1))
1467                    {
1468                        // on garde en stock la deuxiÚme partie de la trame
1469                        // pour un traitement ultérieur
1470
1471                        buffereponse = reponse.substr(pos + 1);
1472
1473                        // Partie traitée
1474
1475                        reponse = reponse.substr(0, pos);
1476
1477                        // on l'affiche dans le log
1478
1479                        AfficherLog("Reponse recue de %s : %s\n", Sockets[i].IP.c_str(), reponse.c_str());
1480
1481                        // On vérifie ici les acknowledges
1482
1483                        if ((reponse.find("ACK") != string::npos) && (reponse.find("NACK") == string::npos))
1484                        {
1485                            if (reponse.find("POSITION")  != string::npos)
1486                            {
1487                                Sockets[i].ack_pos   = true;
1488                            }
1489                            else if (reponse.find("GOTO") != string::npos)
1490                            {
1491                                Sockets[i].ack_goto  = true;
1492                            }
1493                            else if (reponse.find("PARK") != string::npos)
1494                            {
1495                                Sockets[i].ack_park  = true;
1496                            }
1497                            else if (reponse.find("ABORT")!= string::npos)
1498                            {
1499                                Sockets[i].ack_abort = true;
1500                            }
1501                        }
1502                        else
1503                        {
1504                            // Réponse à la requête POSITION
1505
1506                            if (reponse.find("POSITION") != string::npos)
1507                            {
1508                                // Il y a une erreur signalée par le micro-contrÃŽleur
1509
1510                                if (reponse.find("NACK") != string::npos)
1511                                {
1512                                    // ProblÚme concernant la commande P
1513                                    // On affiche dans la boîte indi un voyant de couleur rouge
1514                                    // et on affiche un message d'erreur
1515
1516                                    OnCoordSetSP.s = IPS_ALERT;
1517
1518                                    IDSetSwitch(&OnCoordSetSP, "ALERTE antenne %s : position de l antenne inconnue !\n",
1519                                                Sockets[i].IP.c_str());
1520                                    AfficherLog("ALERTE antenne %s : position de l antenne inconnue !\n",
1521                                                Sockets[i].IP.c_str());
1522
1523                                    // La position de l'antenne st donc inconnue
1524
1525                                    Sockets[i].PosValides = false;
1526
1527                                    // On déconnecte l'antenne
1528
1529                                    Sockets[i].Connected  = false;
1530                                }
1531                                else if (Sockets[i].ack_pos)
1532                                {
1533                                    // La position devrait être valide si on arrive ici...
1534
1535                                    if ( Sockets[i].PosValides = (ExtractPosition(reponse, &Sockets[i].Pos) == true) )
1536                                    {
1537                                        // La fonction extractPositon confirme que les positions transmises
1538                                        // par le micro-contrÃŽleur sont valides
1539
1540                                        OnCoordSetSP.s = IPS_OK;
1541
1542                                        // message dans les logs
1543
1544                                        IDSetSwitch(&OnCoordSetSP, "Antenne %s : POSITION OK  (x=%i, y=%i)\n",
1545                                                    Sockets[i].IP.c_str(), Sockets[i].Pos.x, Sockets[i].Pos.y);
1546                                    }
1547                                    else
1548                                    {
1549                                        // Erreur repérée par la fonction ExtractPosition
1550
1551                                        OnCoordSetSP.s = IPS_ALERT;
1552
1553                                        // On en informe l'utilisateur
1554
1555                                        IDSetSwitch(&OnCoordSetSP, "Antenne %s : La position n est pas valide !\n",
1556                                                    Sockets[i].IP.c_str());
1557                                    }
1558                                }
1559                            }
1560
1561                            //réponse à la requête PARK
1562
1563                            if (reponse.find("PARK") != string::npos)
1564                            {
1565                                if (reponse.find("NACK") != string::npos)
1566                                {
1567                                    // Une erreur  est retournée par le micro-contrÃŽleur concernant la commande Park
1568                                    // On affiche le voyant Park en rouge dans la boîte indi...
1569
1570                                    ParkSP.s = IPS_ALERT;
1571
1572                                    // ... et on affiche un message d'erreur
1573
1574                                    IDSetSwitch(&ParkSP, "ALERTE antenne %s : erreur PARK !\n", Sockets[i].IP.c_str());
1575                                    AfficherLog("ALERTE antenne %s : erreur ABORT !\n",  Sockets[i].IP.c_str());
1576                                }
1577                                else if (Sockets[i].ack_park && reponse.find("OK")!=string::npos)
1578                                {
1579                                    // PARK ok !
1580
1581                                    ParkSP.s = IPS_OK;
1582
1583                                    IDSetSwitch(&ParkSP, "Antenne %s : PARK OK\n",  Sockets[i].IP.c_str());
1584                                }
1585                            }
1586
1587                            //réponse à la requête ABORT
1588
1589                            if (reponse.find("ABORT") != string::npos)
1590                            {
1591                                if (reponse.find("NACK") != string::npos)
1592                                {
1593                                    // Une erreur  est retournée par le micro-contrÃŽleur concernant la commande Abort
1594                                    // On affiche le voyant Park en rouge dans la boîte indi...
1595
1596                                    AbortSlewSP.s = IPS_ALERT;
1597
1598                                    // ... et on affiche un message d'erreur
1599
1600                                    IDSetSwitch(&AbortSlewSP, "ALERTE antenne %s : erreur ABORT !\n",  Sockets[i].IP.c_str());
1601                                    AfficherLog("ALERTE antenne %s : erreur ABORT !\n",  Sockets[i].IP.c_str());
1602                                }
1603                                else if (Sockets[i].ack_abort && reponse.find("OK")!=string::npos)
1604                                {
1605                                    // OK !
1606
1607                                    AbortSlewSP.s = IPS_OK;
1608
1609                                    IDSetSwitch(&AbortSlewSP, "Antenne %s : ABORT OK\n",  Sockets[i].IP.c_str());
1610                                }
1611                            }
1612
1613                            //réponse à la requête GOTO
1614
1615                            if (reponse.find("GOTO") != string::npos)
1616                            {
1617                                if (reponse.find("NACK") != string::npos)
1618                                {
1619                                    // Une erreur  est retournée par le micro-contrÃŽleur concernant la commande Goto
1620                                    // On affiche le voyant Park en rouge dans la boîte indi...
1621
1622                                    OnCoordSetSP.s = IPS_ALERT;
1623
1624                                    // Message d'erreur
1625
1626                                    IDSetSwitch(&OnCoordSetSP, "ALERTE antenne %s : Erreur NACK GOTO !\nRetour : %s\n",  Sockets[i].IP.c_str(), reponse.c_str());
1627                                    AfficherLog("ALERTE antenne %s : Erreur NACK GOTO !\nRetour : %s\n",  Sockets[i].IP.c_str(), reponse.c_str());
1628                                    // On déconnecte l'antenne. Elle ne semble pas en mesure d'exécuter les ordres goto
1629
1630                                    // 02/04/2012 Le fait de recevoir un nack/eos ne nécessite pas de devoir déconnecter l'antenne
1631                                    // DeconnecterSocket(i);
1632                                }
1633                                else if (Sockets[i].ack_goto)
1634                                {
1635                                    if (reponse.find("OK") != string::npos)
1636                                    {
1637                                        // On a ici la confirmation que l'antenne 'i' a bien réalisé le goto
1638
1639                                        // On prend note
1640
1641                                        Sockets[i].GotoOk = true;
1642
1643                                        // Voyant en vert dans la boîte Indi
1644
1645                                        OnCoordSetSP.s = IPS_OK;
1646
1647                                        // Message pour l'utilisateur
1648
1649                                        IDSetSwitch(&OnCoordSetSP, "Antenne %s : GOTO OK.\n",  Sockets[i].IP.c_str());
1650
1651                                        // Fin du Goto pour toutes les antennes ?
1652                                        // On compte les antennes connectées qui ont réalisé le dernier ordre goto
1653
1654                                        int num = 0;
1655
1656                                        for (int j=1; j<SocketsNumber; j++)
1657                                        {
1658                                            if (Sockets[j].Connected)
1659                                            {
1660                                                if (Sockets[j].GotoOk) num++;
1661                                            }
1662                                        }
1663
1664                                        // Si le nombre d'antennes connectées est > 0
1665                                        // et que toutes les antennes connectées ont
1666                                        // réalisé le goto alors...
1667
1668                                        if ((num == AntennesConnectees()) && (num>0))
1669                                        {
1670                                            // C'est bon ! Tout marche bien...
1671                                            // On actualise l'AD et la Dec dans la boîte de dialogue
1672
1673                                            lastRA  = targetRA;
1674                                            lastDEC = targetDEC;
1675
1676                                            // On a fini le mouvement. Il n'y a donc plus d'étape à faire
1677                                            // dans le processus de réalisation d'un goto
1678                                            // RealisationGoto vaut donc false
1679
1680                                            RealisationGoto = false;
1681
1682                                            // Réinitialisation des paramÚtres des antennes en vue d'un prochain goto
1683
1684                                            InitAntennes();
1685
1686                                            // On dessine les voyants de la boîte de dialogue en vert
1687
1688                                            OnCoordSetSP.s = IPS_OK;
1689                                            EquatorialCoordsWNP.s = IPS_OK;
1690                                            IDSetNumber (&EquatorialCoordsWNP, NULL);
1691
1692                                            // Confirmation dans la boîte de dialogue que toutes
1693                                            // les antennes sont OK
1694
1695                                            IDSetSwitch(&OnCoordSetSP, "GOTO OK !");
1696
1697                                            UpdatedGoto = true;
1698                                        }
1699                                    }
1700                                }
1701                            }
1702                        }
1703
1704                        // On passe à la trame suivante si memreponse n'est pas vide
1705
1706                        reponse = buffereponse;
1707                        pos     = reponse.find("\n");
1708                    }
1709                }
1710                catch (SocketException& e) //Aïe
1711                {
1712                    // Une exception concerne le socket i
1713
1714                    // On déconnecte l'antenne pour plus de sécurité
1715
1716                    DeconnecterSocket(i);
1717
1718                    AfficherLog("Indi_BAO, SocketException IsPoll : ");
1719                    AfficherLog(e.description().c_str());
1720                    AfficherLog("\n");
1721                }
1722            }
1723        }
1724
1725
1726        ///////////////////////////////////////
1727        // L'utilisateur a demandé l'annulation du mouvement en cours
1728
1729        if (Abort)
1730        {
1731            // On arrête le suivi d'un objet
1732
1733            Suivi = false;
1734
1735            // On arrête l'enchaînement des actions nécessaires à la réalisation d'un goto
1736
1737            RealisationGoto = false;
1738
1739            // On envoie l'ordre ABORT à toutes les antennes
1740
1741            for (int i=1; i<SocketsNumber; i++)
1742            {
1743                if (Sockets[i].Connected)
1744                {
1745                    if (!ABORT(i)) Sockets[i].sendalertes++;
1746                }
1747            }
1748
1749            // Message à destination de l'utilisateur et des logs
1750
1751            IDSetSwitch(&OnCoordSetSP, "ABORT OK !");
1752
1753            // Réinititialisation des paramÚtres des antennes
1754
1755            InitAntennes();
1756
1757            //Pour permettre de refaire un abort
1758
1759            Abort = false;
1760        }
1761
1762        ///////////////////////////////////////
1763        // L'utilisateur a demandé de mettre les antennes au repos
1764
1765        if (Park)
1766        {
1767            // On arrête le suivi d'un objet
1768
1769            Suivi = false;
1770
1771            // On arrête l'enchaînement des actions
1772            // pour réaliser un goto
1773
1774            RealisationGoto = false;
1775
1776            // On envoie l'ordre PARK à toutes les antennes
1777
1778            for (int i=1; i<SocketsNumber; i++)
1779            {
1780                if (Sockets[i].Connected)
1781                {
1782                    if (!PARK(i)) Sockets[i].sendalertes++;
1783                }
1784            }
1785
1786            IDSetSwitch(&OnCoordSetSP, "PARK OK !");
1787
1788            // Réinititialisation des paramÚtres des antennes
1789
1790            InitAntennes();
1791
1792            // Pour permettre de refaire un park
1793
1794            Park = false;
1795        }
1796
1797
1798        ///////////////////////////////////////
1799        // Gestion du suivi
1800
1801        if ((Suivi) && (UpdatedGoto))
1802        {
1803            // Délais entre deux actualisations
1804
1805            // Actualisation toutes les 15 minutes en mode transit (par défaut)
1806
1807            double delai = ActualisationTMTransit / 3600.0 / 24.0;
1808
1809            // et 5 secs en mode tracking (par défaut)
1810
1811            if (TrackingMode == BAO_TRACKING) delai = ActualisationTMTracking / 3600.0 / 24.0;
1812
1813
1814            // On actualise la position si le délai est dépassé
1815
1816            if (GetJJ() - JJAnc > delai)
1817            {
1818                // Cette variable vaut true lorsque le goto a été réalisé
1819
1820                UpdatedGoto = false;
1821
1822                // Conversion des coordonnées en pas moteur
1823
1824                ADDEC2Motor(targetRA, targetDEC);
1825
1826                // On réinitialise les antennes en vue du goto
1827
1828                InitAntennes();
1829
1830                // On lance le processus d'actualisation du goto
1831
1832                RealisationGoto = true;
1833
1834                // On sauvegarde la date
1835
1836                JJAnc = GetJJ();
1837            }
1838
1839            //Plus d'antenne ! On arrête le suivi
1840
1841            if (AntennesConnectees() == 0)
1842            {
1843                if ( compt % 1000 == 0)
1844                {
1845                    IDSetSwitch(&OnCoordSetSP, "Erreur ! Plus d antennes connectees !");
1846
1847                    if (Suivi) AfficherLog("Arrêt du suivi !");
1848
1849                    RealisationGoto=false;
1850
1851                    Suivi=false;
1852
1853                    InitAntennes();
1854                }
1855            }
1856        }
1857
1858
1859
1860        // Exécution de la procédure complÚte d'un goto :
1861        // 1Úre étape : envoi de la commande POSITION à toutes les antennes
1862        // 2Úme étape : Vérification de l'acknowledge de la commande POSITION pour chaque antenne
1863        // 3Úme étape : Les positions retournées par les antennes sont-elles valides ?
1864        // 4Úme étape : Si oui, envoie de la commande goto à toutes les antennes
1865        // 5Úme étape : est-ce que toutes les antennes ont envoyé l'acknowledge de la commande goto ?
1866        // 6Úme étape : les antennes ont toutes répondu GOTO OK !
1867
1868        if (RealisationGoto)
1869        {
1870            for (int i=1; i<SocketsNumber; i++)
1871            {
1872                // On ne parle qu'aux antennes connectées
1873
1874                if (Sockets[i].Connected)
1875                {
1876                    // En fonction de l'étage de la réalisation d'un goto par l'antenne i
1877
1878                    switch (Sockets[i].etape)
1879                    {
1880
1881                        // Envoi de la commande POS
1882
1883                    case 0 :
1884                    {
1885                        // On doit initialiser l'acknowledge à false
1886
1887                        Sockets[i].ack_pos    = false;
1888
1889                        // et considérer que la position de l'antenne n'est pas valide
1890
1891                        Sockets[i].PosValides = false;
1892
1893                        // avant d'envoyer l'ordre POSITION
1894
1895                        if (!POSITION(i)) Sockets[i].sendalertes++;
1896
1897                        // On passe à l'étage suivante
1898
1899                        Sockets[i].etape++;
1900                    }
1901                    break;
1902
1903
1904                    // A-ton bien reçu l'ack POS ?
1905
1906                    case 1 :
1907                    {
1908                        if (Sockets[i].ack_pos)
1909                        {
1910                            // tout marche bien. On a bien reçu l'acknowledge de l'antenne i
1911
1912                            // Il n'y a donc aucune attente supplémentaire pour recevoir la réponse
1913                            Sockets[i].AttenteExecution = 0;
1914
1915                            // Pas d'anomalie à consigner
1916                            Sockets[i].AnomaliesExecution = 0;
1917
1918                            // On passe à l'étape suivante
1919                            Sockets[i].etape++;
1920
1921                            //permet de rester sur le même socket malgré la boucle -> plus rapide
1922                            i--;
1923                        }
1924                        else
1925                        {
1926                            // On réitÚre l'ordre précédent si rien ne se passe
1927
1928                            // On garde une trace de l'anomalie
1929
1930                            Sockets[i].AttenteExecution++;
1931
1932                            if (Sockets[i].AttenteExecution > MAXATTENTE)
1933                            {
1934                                // on recommence depuis le début.
1935                                // Peut-être que l'antenne n'a pas reçu l'ordre ?
1936                                Sockets[i].etape = 0;
1937                                Sockets[i].AttenteExecution = 0;
1938
1939                                // Pas de réponse. On consigne une erreur grave
1940                                Sockets[i].AnomaliesExecution++;
1941                            }
1942
1943                            // Les erreurs graves s'accumulent. Pas de réponse aprÚs plusieurs minutes
1944                            // -> Il faut déconnecter l'antenne
1945                            if (Sockets[i].AnomaliesExecution > MAXANOMALIES)
1946                            {
1947                                //Voyant en rouge dans la boîte Indi
1948
1949                                OnCoordSetSP.s = IPS_ALERT;
1950
1951                                //Message à l'attention de l'utilisateur
1952
1953                                IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s : pas d acknowledge recu apres l ordre POSITION. \
1954Deconnexion de l antenne.", Sockets[i].IP.c_str());
1955                                AfficherLog("Erreur sur l antenne %s : pas d acknowledge recu apres l ordre POSITION. \
1956Deconnexion de l antenne.", Sockets[i].IP.c_str());
1957
1958                                // On déconnecte l'antenne
1959
1960                                // DeconnecterSocket(i);
1961                            }
1962                        }
1963                    }
1964                    break;
1965
1966
1967                    //Les valeurs retournées pas la commande POSITION sont-elles valides ?
1968
1969                    case 2 :
1970                    {
1971                        if (Sockets[i].PosValides)
1972                        {
1973                            // Tout vas bien
1974                            // On ne consigne aucune anomalie
1975
1976                            Sockets[i].AttenteExecution = 0;
1977                            Sockets[i].AnomaliesExecution = 0;
1978
1979                            //On passe à l'étape suivante
1980
1981                            Sockets[i].etape++;
1982                        }
1983                        else
1984                        {
1985                            // on réitÚre l'ordre précédent si rien ne se passe
1986
1987                            Sockets[i].AttenteExecution++;
1988
1989                            if (Sockets[i].AttenteExecution > MAXATTENTE)
1990                            {
1991                                // on attend encore la réponse posvalides
1992
1993                                Sockets[i].etape = 2;
1994                                Sockets[i].AttenteExecution = 0;
1995
1996                                // On consigne une erreur grave. L'antenne tarde à répondre
1997
1998                                Sockets[i].AnomaliesExecution++;
1999                            }
2000
2001                            // Aucune réponse de l'antenne depuis plusieurs minutes
2002                            // On la déconnecte
2003
2004                            if (Sockets[i].AnomaliesExecution > MAXANOMALIES)
2005                            {
2006                                // Voyant en rouge
2007
2008                                OnCoordSetSP.s = IPS_ALERT;
2009
2010                                //Message d'erreur
2011
2012                                IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s : la position retournee n est pas valide. \
2013Deconnexion de l antenne.", Sockets[i].IP.c_str());
2014                                AfficherLog("Erreur sur l antenne %s : la position retournee n est pas valide. \
2015Deconnexion de l antenne.", Sockets[i].IP.c_str());
2016
2017                                //Déconnexion de l'antenne
2018
2019                                // DeconnecterSocket(i);
2020                            }
2021                        }
2022                    }
2023                    break;
2024
2025
2026
2027                    // On peut remarquer qu'il n'y a pas de case 3 ici...
2028                    // L'envoie de la commande goto se fait portant pendant l'étape 3 en dehors du switch
2029                    // Voir le code plus loin...
2030
2031
2032                    // A-ton reçu l'acknowledge de la commande goto ?
2033
2034                    case 4 :
2035                    {
2036                        if (Sockets[i].ack_goto)
2037                        {
2038                            Sockets[i].AttenteExecution = 0;
2039                            Sockets[i].AnomaliesExecution = 0;
2040                            Sockets[i].etape++; // on passe à l'étape suivante
2041                        }
2042                        else
2043                        {
2044                            // on réitÚre l'ordre précédent si rien ne se passe
2045                            Sockets[i].AttenteExecution++;
2046
2047                            if (Sockets[i].AttenteExecution > MAXATTENTE)
2048                            {
2049                                // On prolonge l'attente pour recevoir l'acknowledge du goto
2050                                Sockets[i].etape = 4;
2051                                Sockets[i].AttenteExecution = 0;
2052                                Sockets[i].AnomaliesExecution++;
2053                            }
2054
2055                            if (Sockets[i].AnomaliesExecution > MAXANOMALIES)
2056                            {
2057                                OnCoordSetSP.s = IPS_ALERT;
2058
2059                                IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s : pas d acknowledge recu apres l ordre GOTO. Deconnexion de l antenne.", Sockets[i].IP.c_str());
2060                                AfficherLog("Erreur sur l antenne %s : pas d acknowledge recu apres l ordre GOTO. Deconnexion de l antenne.", Sockets[i].IP.c_str());
2061
2062                                // DeconnecterSocket(i);
2063                            }
2064                        }
2065                    }
2066                    break;
2067
2068
2069                    //  Confirmation goto ok ?
2070
2071                    case 5 :
2072                    {
2073                        if (Sockets[i].GotoOk)
2074                        {
2075                            // On a bien reçu Goto Ok pour l'antenne i !
2076
2077                            Sockets[i].AttenteExecution = 0;
2078                            Sockets[i].AnomaliesExecution = 0;
2079
2080                            //On passe à l'étape suivante
2081                            Sockets[i].etape++;
2082                        }
2083                        else
2084                        {
2085                            // on réitÚre l'ordre précédent si rien ne se passe
2086                            Sockets[i].AttenteExecution++;
2087
2088                            if (Sockets[i].AttenteExecution > MAXATTENTE)
2089                            {
2090                                // On prolonge l'attente afin de recevoir un GOTO OK
2091
2092                                Sockets[i].etape = 5;
2093                                Sockets[i].AttenteExecution = 0;
2094                                Sockets[i].AnomaliesExecution++;
2095                            }
2096
2097                            // On déconnecte l'antenne s'il n'y a pas de confirmation du goto au bout de 2 minutes
2098                            if (Sockets[i].AnomaliesExecution > MAXANOMALIESGOTO)
2099                            {
2100                                // Alerte sur une antenne
2101                                OnCoordSetSP.s = IPS_ALERT;
2102
2103                                // Message d'erreur
2104                                IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s : l antenne n a pas renvoye GOTO/OK. Deconnexion de l antenne.", Sockets[i].IP.c_str());
2105                                AfficherLog("Erreur sur l antenne %s : l antenne n a pas renvoye GOTO/OK. Deconnexion de l antenne.", Sockets[i].IP.c_str());
2106
2107
2108                                //Déconnexion de l'antenne
2109                                // DeconnecterSocket(i);
2110                            }
2111                        }
2112                    }
2113                    break;
2114                    }
2115                }
2116            }
2117        }
2118
2119
2120        ///////////////////////////////////////
2121        // Réalisation d'un goto - traitement de l'étape 3
2122        // On place cette partie du traitement en dehors du switch et de la boucle
2123        // pour pouvoir envoyer les gotos à toutes les antennes lorsque l'on a la confirmation
2124        // qu'elles sont toutes prêtes à exécuter cet ordre (être à l'étape 3 pour un socket)
2125        // -> meilleure synchronisation
2126
2127        // On compte les antennes rendues à l'étape 3 et qui attendent
2128
2129        int num = 0;
2130
2131        for (int i=1; i<SocketsNumber; i++)
2132        {
2133            // Uniquement les antennes connectées
2134
2135            if (Sockets[i].Connected)
2136            {
2137                if (Sockets[i].etape == 3) num++; // num antennes sont prêtes à recevoir l'ordre GOTO
2138            }
2139        }
2140
2141        // Toutes les antennes connectées sont prêtes à recevoir l'ordre goto
2142
2143        if ((num == AntennesConnectees()) && (num>0))
2144        {
2145            for (int i=1; i<SocketsNumber; i++ )
2146            {
2147                if (Sockets[i].Connected)
2148                {
2149                    // On envoie l'ordre
2150
2151                    Sockets[i].ack_goto = false;
2152                    Sockets[i].AttenteExecution = 0;
2153                    Sockets[i].AnomaliesExecution = 0;
2154
2155                    if (!GOTO(i, Sockets[i].TargetPosition.x - Sockets[i].Pos.x, Sockets[i].TargetPosition.y - Sockets[i].Pos.y )) Sockets[i].sendalertes++;
2156
2157                    Sockets[i].etape++;
2158                }
2159            }
2160        }
2161
2162        ///////////////////////////////////////
2163        // Opération garbage
2164        // Détection d'anomalies sur le socket i.
2165        // Ce n'est pas normal ici. Il faut déconnecte l'antenne
2166
2167        for (int i=1; i<SocketsNumber; i++)
2168        {
2169            if (Sockets[i].Connected)
2170            {
2171                if (Sockets[i].sendalertes > 0)
2172                {
2173                    // Alarme dans la boîte Indi
2174
2175                    OnCoordSetSP.s = IPS_ALERT;
2176
2177                    // Erreur dans les logs
2178
2179                    IDSetSwitch(&OnCoordSetSP, "Erreur sur l antenne %s : deconnexion de l antenne.", Sockets[i].IP.c_str());
2180                    AfficherLog("Erreur sur l antenne %s : deconnexion de l antenne.", Sockets[i].IP.c_str());
2181
2182                    // Déconnexion antenne
2183
2184                    // DeconnecterSocket(i);
2185                }
2186            }
2187        }
2188    }
2189
2190    //incrémentation du compteur
2191
2192    compt++;
2193}
2194
2195
2196
2197/**************************************************************************************
2198** Mode transit ou tracking
2199**
2200***************************************************************************************/
2201
2202bool BAO::process_coords()
2203{
2204    switch (currentSet)
2205    {
2206        // Transit
2207
2208    case BAO_TRANSIT:
2209
2210        // Éteindre les voyants dans la boîte de dialogue Indi
2211        EquatorialCoordsWNP.s = IPS_BUSY;
2212        AbortSlewSP.s = IPS_IDLE;
2213        ParkSP.s = IPS_IDLE;
2214
2215        IDSetNumber (&EquatorialCoordsWNP, NULL);
2216        IDSetSwitch (&AbortSlewSP, NULL);
2217        IDSetSwitch (&ParkSP, NULL);
2218
2219        // On prépare les antennes pour le prochain goto
2220
2221        InitAntennes();
2222
2223        // On garde la trace du début du Goto pour enchaîner les actualisations
2224
2225        JJAnc = GetJJ();
2226
2227        // Conversion des coordonnées horaires en pas moteur
2228
2229        ADDEC2Motor(targetRA, targetDEC);
2230
2231        // Mode transit activé
2232
2233        TrackingMode = BAO_TRANSIT;
2234
2235        // On suit un objet
2236
2237        Suivi = true;
2238
2239        // Aucun goto n'a été encore réalisé
2240
2241        UpdatedGoto = false;
2242
2243        // Mais on se lance dans la réalisation d'un goto
2244
2245        RealisationGoto = true;
2246
2247        break;
2248
2249        // Tracking
2250
2251    case BAO_TRACKING:
2252
2253        // Éteindre les voyants dans la boîte de dialogue Indi
2254
2255        EquatorialCoordsWNP.s = IPS_BUSY;
2256        AbortSlewSP.s = IPS_IDLE;
2257        ParkSP.s = IPS_IDLE;
2258
2259        IDSetNumber (&EquatorialCoordsWNP, NULL);
2260        IDSetSwitch (&AbortSlewSP, NULL);
2261        IDSetSwitch (&ParkSP, NULL);
2262
2263        InitAntennes();
2264
2265        JJAnc = GetJJ();
2266
2267        ADDEC2Motor(targetRA, targetDEC);
2268
2269        TrackingMode = BAO_TRACKING;
2270
2271        Suivi = true;
2272
2273        UpdatedGoto = false;
2274
2275        RealisationGoto = true;
2276
2277        break;
2278    }
2279
2280    return true;
2281}
2282
2283
2284
2285/**************************************************************************************
2286** Connexion / Déconnexion avec le télescope
2287**
2288***************************************************************************************/
2289
2290void BAO::connect_telescope()
2291{
2292    switch (ConnectSP.sp[0].s)
2293    {
2294    case ISS_ON:
2295
2296        // Etats des voyants
2297
2298        ConnectS[0].s = ISS_ON;
2299        ConnectS[1].s = ISS_OFF;
2300        ConnectSP.s = IPS_OK;
2301        IDSetSwitch (&ConnectSP, "BAORadio is online. Retrieving basic data...");
2302
2303        // Petit message
2304
2305        AfficherLog("\nHello BAORadio !\n");
2306
2307        // On lance le thread !
2308        // Exit ne faudra true que lorsque sera venu le moment de sortir !
2309
2310        Exit = false;
2311
2312        // Création du thread
2313
2314        if (pthread_create (&th1, NULL, (void*(*)(void*))LancementThread, this) < 0)
2315        {
2316            AfficherLog("pthread_create error for threadSocket\n");
2317        }
2318
2319        break;
2320
2321    case ISS_OFF:
2322
2323        // Etat des voyants
2324
2325        ConnectS[0].s = ISS_OFF;
2326        ConnectS[1].s = ISS_ON;
2327        ConnectSP.s = IPS_IDLE;
2328        IDSetSwitch (&ConnectSP, "BAORadio is offline.");
2329        AfficherLog("Telescope is offline.");
2330
2331        // On déconnecte tous les sockets
2332
2333        for (int i=0; i<MAXHOSTNAME; i++)
2334        {
2335            DeconnecterSocket(i);
2336        }
2337
2338        // init
2339
2340        InitAntennes();
2341
2342        SocketsNumber = 1;
2343
2344        // On sort du thread
2345
2346        // On dit au thread de sortir de la boucle
2347
2348        Exit = true;
2349
2350        // Désactiver la boucle de traitement des messages des ISPOLL
2351
2352        InitThreadOK = false;
2353
2354        // On laisse 1 s au thread pour sortir de la boucle
2355
2356        sleep(1);
2357
2358        // On détruit le thread
2359
2360        pthread_join (th1, NULL);
2361
2362        // on sort du programme
2363
2364        exit(EXIT_SUCCESS);
2365
2366        break;
2367    }
2368}
2369
2370
2371
2372
2373/**************************************************************************************
2374**  Envoie une commande sur le socket numsocket
2375**
2376***************************************************************************************/
2377
2378bool BAO::COMMANDE(int numsocket, char* Commande, char* Params)
2379{
2380    char chaine[MAXCARACTERES];
2381
2382    try
2383    {
2384        sprintf(chaine, "%s%s\n", Commande, Params);
2385
2386        Sockets[numsocket].new_sock << chaine;
2387
2388        AfficherLog("Commande envoyee a %s: %s", Sockets[numsocket].IP.c_str(), chaine);
2389    }
2390    catch (SocketException& e)
2391    {
2392        // Consignation d'une anomalie sur le socket
2393
2394        DeconnecterSocket(numsocket);
2395
2396        AfficherLog("Indi_BAO, COMMANDE exception : ");
2397        AfficherLog(e.description().c_str());
2398        AfficherLog("\n");
2399
2400        return false;
2401    }
2402
2403    return true;
2404}
2405
2406
2407/**************************************************************************************
2408** Commande POSITION
2409**
2410***************************************************************************************/
2411
2412bool BAO::POSITION(int numsocket)
2413{
2414    return COMMANDE(numsocket, (char*)"P", (char*)"");
2415}
2416
2417/**************************************************************************************
2418** Commande PARK
2419**
2420***************************************************************************************/
2421
2422bool BAO::PARK(int numsocket)
2423{
2424    return COMMANDE(numsocket, (char*)"Z", (char*)"");
2425}
2426
2427/**************************************************************************************
2428** Commande ABORT
2429**
2430***************************************************************************************/
2431
2432bool BAO::ABORT(int numsocket)
2433{
2434    return COMMANDE(numsocket, (char*)"A", (char*)"");
2435}
2436
2437
2438/**************************************************************************************
2439** Commande GOTO
2440**
2441***************************************************************************************/
2442
2443bool BAO::GOTO(int numsocket, int deltaAz, int deltaAlt)
2444{
2445    char Params[MAXCARACTERES];
2446    char sensAz;
2447    char sensAlt;
2448
2449    sensAlt = 1;
2450    sensAz  = 1;
2451
2452    // gestion des signes des deltas
2453
2454    if ( deltaAz < 0 )
2455    {
2456        deltaAz = -deltaAz;
2457        sensAz  = 0;
2458    }
2459
2460    if ( deltaAlt < 0 )
2461    {
2462        deltaAlt = -deltaAlt;
2463        sensAlt  = 0;
2464    }
2465
2466    // Vérification du nombre de pas à faire au niveau de l'axe azimut
2467    // Rappel : un tour complet autour de l'axe az fait 4000 pas codeur (voir #define NBREPASCODEURSAZ dans BAO.h)
2468
2469    // problÚme 1 : si deltaAz > à un demi-tours - soit 2000 pas codeur alors
2470    // on fait le trajet en sens inverse pour aller plus vite
2471
2472    // problÚme 2 : Passage au méridien
2473    // on se situe à quelques secondes de degrés avant le sud par exemple (nb de pas 3995 par exemple)
2474    // et on franchit le méridien (nb de pas codeur = 5 par exemple)
2475    // On risque alors de faire un tour complet en sens inverse pour rattraper l'objet -> à éviter
2476
2477    // ne pas faire des tours complets en Az pour rien...
2478
2479    while (deltaAz > NBREPASCODEURSAZ) deltaAz -= NBREPASCODEURSAZ;
2480
2481    // Doit résoudre tous les problÚmes concernant l'azimut...
2482
2483    if (deltaAz > NBREPASCODEURSAZ / 2 )
2484    {
2485        deltaAz = NBREPASCODEURSAZ - deltaAz;
2486
2487        sensAz = 1 - sensAz;
2488    }
2489
2490    //on envoie les coordonnées au driver
2491
2492    (sensAz == 1 ) ? sensAz='f' : sensAz='b';
2493
2494    (sensAlt == 1 ) ? sensAlt='f': sensAlt='b';
2495
2496    sprintf(Params, "%c%04i%c%04i", sensAz, deltaAz, sensAlt, deltaAlt);
2497
2498    return COMMANDE(numsocket, (char*)"G", Params);
2499}
2500
2501
2502
2503/**************************************************************************************
2504** Les fonctions qui suivent sont nécessaires pour construire le pilote Indi_BAO
2505** Elles sont appelées par le noyau d'Indi
2506***************************************************************************************/
2507
2508/**************************************************************************************
2509** Initialisation du pilote BAO
2510***************************************************************************************/
2511
2512void ISInit()
2513{
2514    //Il ne faut exécuter la fonction qu'une seule fois
2515
2516    static int isInit = 0;
2517
2518    if (isInit) return;
2519
2520    if (telescope.get() == 0) telescope.reset(new BAO());
2521
2522    isInit = 1;
2523
2524    //initialisation du timer
2525
2526    IEAddTimer (POLLMS, ISPoll, NULL);
2527}
2528
2529
2530void ISGetProperties (const char *dev)
2531{
2532    ISInit();
2533
2534    telescope->ISGetProperties(dev);
2535}
2536
2537void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
2538{
2539    ISInit();
2540    telescope->ISNewSwitch(dev, name, states, names, n);
2541}
2542
2543void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
2544{
2545    ISInit();
2546    telescope->ISNewText(dev, name, texts, names, n);
2547}
2548
2549void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
2550{
2551    ISInit();
2552    telescope->ISNewNumber(dev, name, values, names, n);
2553}
2554
2555void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
2556{
2557    INDI_UNUSED(dev);
2558    INDI_UNUSED(name);
2559    INDI_UNUSED(sizes);
2560    INDI_UNUSED(blobsizes);
2561    INDI_UNUSED(blobs);
2562    INDI_UNUSED(formats);
2563    INDI_UNUSED(names);
2564    INDI_UNUSED(n);
2565}
2566
2567void ISSnoopDevice (XMLEle *root)
2568{
2569    INDI_UNUSED(root);
2570}
2571
2572void ISPoll (void *p)
2573{
2574    INDI_UNUSED(p);
2575
2576    telescope->ISPoll();
2577
2578    IEAddTimer (POLLMS, ISPoll, NULL);
2579}
2580
2581
2582/**************************************************************************************
2583**
2584***************************************************************************************/
2585
2586int BAO::get_switch_index(ISwitchVectorProperty *sp)
2587{
2588    for (int i=0; i < sp->nsp ; i++)
2589        if (sp->sp[i].s == ISS_ON)
2590            return i;
2591
2592    return -1;
2593}
2594
2595
2596
2597/**************************************************************************************
2598**
2599***************************************************************************************/
2600
2601bool BAO::is_connected()
2602{
2603    // return (ConnectSP.sp[0].s == ISS_ON);
2604    return (ConnectSP.s == IPS_OK);
2605}
2606
2607/**************************************************************************************
2608**
2609***************************************************************************************/
2610void BAO::connection_lost()
2611{
2612    ConnectSP.s = IPS_IDLE;
2613    IDSetSwitch(&ConnectSP, "The connection to the telescope is lost.");
2614    AfficherLog("arret");
2615    return;
2616}
2617
2618/**************************************************************************************
2619**
2620***************************************************************************************/
2621void BAO::connection_resumed()
2622{
2623    ConnectS[0].s = ISS_ON;
2624    ConnectS[1].s = ISS_OFF;
2625    ConnectSP.s = IPS_OK;
2626
2627    IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed.");
2628}
2629
2630
2631/**************************************************************************************
2632** GÚre les erreurs de communication avec la boîte Indi
2633***************************************************************************************/
2634/*
2635void BAO::handle_error(INumberVectorProperty *nvp, int err, const char *msg)
2636{
2637    nvp->s = IPS_ALERT;
2638
2639    // If the error is a time out, then the device doesn't support this property
2640    if (err == -2)
2641    {
2642        nvp->s = IPS_ALERT;
2643        IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg);
2644    }
2645    else
2646        // Changing property failed, user should retry.
2647        IDSetNumber( nvp , "%s failed.", msg);
2648
2649    fault = true;
2650}*/
2651
2652
2653/**************************************************************************************
2654**
2655***************************************************************************************/
2656/*
2657void BAO::correct_fault()
2658{
2659    fault = false;
2660    IDMessage(mydev, "Telescope is online.");
2661}*/
2662
2663
2664
2665
Note: See TracBrowser for help on using the repository browser.