source: BAORadio/libindi/libindi/examples/tutorial_three.c @ 623

Last change on this file since 623 was 504, checked in by frichard, 13 years ago

-Version 0.8 de libini
-Formule de Marc
-Nouvelles fonctionnalités (goto nom-de l'objet etc...)

File size: 9.0 KB
RevLine 
[490]1/*
2   INDI Developers Manual
3   Tutorial #3
4   
5   "Simple CCD Simulator"
6   
7   In this tutorial, we employ a BLOB property to send a sample FITS file to the client.
8   
9   Refer to README, which contains instruction on how to build this driver, and use it
10   with an INDI-compatible client.
11
12*/
13
14/** \file tutorial_three.c
15    \brief Simulate a CCD camera by using INDI BLOBs to send FITS data to the client.
16    \author Jasem Mutlaq
17*/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <stdarg.h>
23#include <math.h>
24#include <unistd.h>
25#include <time.h>
26#include <fcntl.h>
27#include <signal.h>
28#include <errno.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <netdb.h>
34#include <zlib.h>
35
36/* INDI Core headers */
37#include "indidevapi.h"
38#include "indicom.h"
39#include "eventloop.h"
40#include "base64.h"
41
42#define mydev           "CCD Simulator"
43#define COMM_GROUP      "Main Control"
44
45/* Handy macro */
46#define currentTemp     TemperatureN[0].value
47
48void uploadFile(const char* filename);
49void ISPoll(void * p);
50
51static double targetTemp        = 0;
52
53/*INDI controls */
54
55/* Connect/Disconnect */
56static ISwitch PowerS[]                 = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}};
57static ISwitchVectorProperty PowerSP    = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0};
58
59/* Exposure time */
60static INumber ExposeTimeN[]    = {{ "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., .5, 1., 0, 0, 0}};
61static INumberVectorProperty ExposeTimeNP = { mydev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE, ExposeTimeN, NARRAY(ExposeTimeN), "", 0};
62 
63/* Temperature control */
64 static INumber TemperatureN[]    = { {"CCD_TEMPERATURE_VALUE", "Temperature", "%+06.2f", -30., 40., 1., 0., 0, 0, 0}};
65 static INumberVectorProperty TemperatureNP = { mydev, "CCD_TEMPERATURE", "Temperature (C)", COMM_GROUP, IP_RW, 60, IPS_IDLE, TemperatureN, NARRAY(TemperatureN), "", 0};
66
67/* BLOB for sending image */
[504]68static IBLOB imagePrimaryB = {"CCD1", "Primary", "", 0, 0, 0, 0, 0, 0, 0};
69static IBLOBVectorProperty imagePrimaryBP = {mydev, "CCD1", "", COMM_GROUP,
70  IP_RO, 0, IPS_IDLE, &imagePrimaryB, 1, "", 0};
[490]71
[504]72static IBLOB imageGuideB = {"CCD2", "Guide", "", 0, 0, 0, 0, 0, 0, 0};
73static IBLOBVectorProperty imageGuideBP = {mydev, "CCD2", "", COMM_GROUP,
74  IP_RO, 0, IPS_IDLE, &imageGuideB, 1, "", 0};
75
[490]76void ISGetProperties (const char *dev)
77{ 
78
79  if (dev && strcmp (mydev, dev))
80    return;
81
82  /* COMM_GROUP */
83  IDDefSwitch(&PowerSP, NULL);
84  IDDefNumber(&ExposeTimeNP, NULL);
85  IDDefNumber(&TemperatureNP, NULL);
[504]86  IDDefBLOB(&imagePrimaryBP, NULL);
87  IDDefBLOB(&imageGuideBP, NULL);
[490]88
89  IEAddTimer(1000, ISPoll, NULL);
90 
91}
92
93/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
94void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
95void ISSnoopDevice (XMLEle *root) {}
96
97 
98void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
99{
100        /* ignore if not ours */
101        if (dev && strcmp (dev, mydev))
102            return;
103           
104        /* Connection */
105        if (!strcmp (name, PowerSP.name))
106        {
107          IUUpdateSwitch(&PowerSP, states, names, n);
108          PowerSP.s = IPS_OK;
109          if (PowerS[0].s == ISS_ON)
110                IDSetSwitch(&PowerSP, "CCD Simulator is online.");
111          else
112                IDSetSwitch(&PowerSP, "CCD Simulator is offline.");
113          return;
114        }
115       
116}
117
118void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
119{
120       /* ignore if not ours */ 
121       if (dev && strcmp (mydev, dev))
122         return;
123
124        /* suppress warning */
125        n=n; dev=dev; name=name; names=names; texts=texts;
126       
127}
128
129
130void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
131{
132
133    /* Exposure time */
134    if (!strcmp (ExposeTimeNP.name, name))
135    {
136
137     /* Let's make sure that our simulator is online */
138     if (PowerS[0].s != ISS_ON)
139     {
140       ExposeTimeNP.s = IPS_IDLE;
141       IDSetNumber(&ExposeTimeNP, "CCD Simulator is offline.");
142       return;
143     }
144
145      IDLog("Sending BLOB FITS...\n");
146
147      ExposeTimeNP.s = IPS_BUSY;
148      ExposeTimeN[0].value = values[0];
149 
150      return;
151    } 
152
153    /* Temperature */
154    if (!strcmp (TemperatureNP.name, name))
155    {
156
157     /* Let's make sure that our simulator is online */
158     if (PowerS[0].s != ISS_ON)
159     {
160       TemperatureNP.s = IPS_IDLE;
161       IDSetNumber(&TemperatureNP, "CCD Simulator is offline");
162       return;
163     }
164
165      targetTemp = values[0];
166
167      /* If the requested temperature is the current CCD chip temperature, then return */
168      if (targetTemp == TemperatureN[0].value)
169      {
170        TemperatureNP.s = IPS_OK;
171        IDSetNumber(&TemperatureNP, NULL);
172        return;
173      }
174     
175      /* Otherwise, set property state to busy */
176      TemperatureNP.s = IPS_BUSY;
177      IDSetNumber(&TemperatureNP, "Setting CCD temperature to %g", targetTemp);
178
179      return;
180    }
181
182}
183
184/* Open a data file, compress its content, and send it via our BLOB property */
185void uploadFile(const char* filename)
186{
187   FILE * fitsFile;
188   unsigned char *fitsData, *compressedData;
189   int r=0;
190   unsigned int i =0, nr = 0;
191   uLongf compressedBytes=0;
192   uLong  totalBytes;
193   struct stat stat_p; 
194 
195   /* #1 Let's get the file size */
196   if ( -1 ==  stat (filename, &stat_p))
197   { 
198     IDLog(" Error occoured attempting to stat file.\n"); 
199     return; 
200   }
201   
202   /* #2 Allocate memory for raw and compressed data */
203   totalBytes     = stat_p.st_size;
204   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
205   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
206   
207   if (fitsData == NULL || compressedData == NULL)
208   {
209     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
210     return;
211   }
212   
213   /* #3 Open the FITS file */
214   fitsFile = fopen(filename, "r");
215   
216   if (fitsFile == NULL)
217    return;
218   
219   /* #4 Read file from disk */ 
220   for (i=0; i < totalBytes; i+= nr)
221   {
222      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
223     
224     if (nr <= 0)
225     {
226        IDLog("Error reading temporary FITS file.\n");
227        return;
228     }
229   }
230   
231   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
232   
233   /* #5 Compress raw data */ 
234   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
235   if (r != Z_OK)
236   {
237        /* this should NEVER happen */
238        IDLog("internal error - compression failed: %d\n", r);
239        return;
240   }
241   
242   /* #6 Send it */
243
[504]244   if (!strcmp(filename, "ngc1316o.fits"))
245   {
246   imagePrimaryB.blob = compressedData;
247   imagePrimaryB.bloblen = compressedBytes;
248   imagePrimaryB.size = totalBytes;
249   strcpy(imagePrimaryB.format, ".fits.z");
250
[490]251   /* #7 Set BLOB state to Ok */
[504]252   imagePrimaryBP.s = IPS_OK;
253   IDSetBLOB (&imagePrimaryBP, NULL);
254   }
255   else
256   {
257       imageGuideB.blob = compressedData;
258       imageGuideB.bloblen = compressedBytes;
259       imageGuideB.size = totalBytes;
260       strcpy(imageGuideB.format, ".fits.z");
[490]261
[504]262       /* #7 Set BLOB state to Ok */
263       imageGuideBP.s = IPS_OK;
264       IDSetBLOB (&imageGuideBP, NULL);
265   }
266
[490]267   /* #8 Set Exposure status to Ok */
268   ExposeTimeNP.s = IPS_OK;
269   IDSetNumber(&ExposeTimeNP, "Sending FITS...");
270   
271   /* #9 Let's never forget to free our memory */
272   free (fitsData);   
273   free (compressedData);
274   
275}
276
277/* Poll device status and update accordingly */
278void ISPoll(void * p)
279{
280
281   /* We need to check the status of properties that we want to watch. */
282
283   /* #1 CCD Exposure */
284   switch (ExposeTimeNP.s)
285   {
286     case IPS_IDLE:
287     case IPS_OK:
288     case IPS_ALERT:
289        break;
290
291     /* If an exposure state is busy, decrement the exposure value until it's zero (done exposing). */
292     case IPS_BUSY:
293        ExposeTimeN[0].value--;
294
295        /* Are we done yet? */
[504]296        if (ExposeTimeN[0].value <= 0)
[490]297        {
[504]298          ExposeTimeN[0].value = 0;
299
[490]300          /* Let's set the state of OK and report that to the client */
301          ExposeTimeNP.s = IPS_OK;
302 
303          /* Upload a sample FITS file */
304          uploadFile("ngc1316o.fits");
[504]305          uploadFile("x0cj010ct_d0h.fit");
[490]306
307          IDSetNumber(&ExposeTimeNP, NULL);
308          break;
309        }
310
311        IDSetNumber(&ExposeTimeNP, NULL);
312        break;
313   } 
314
315   /* #2 CCD Temperature */
316   switch (TemperatureNP.s)
317   {
318     case IPS_IDLE:
319     case IPS_OK:
320     case IPS_ALERT:
321        break;
322
323     case IPS_BUSY:
324     /* If target temperature is higher, then increase current CCD temperature */ 
325     if (currentTemp < targetTemp)
326        currentTemp++;
327     /* If target temperature is lower, then decrese current CCD temperature */
328     else if (currentTemp > targetTemp)
329       currentTemp--;
330     /* If they're equal, stop updating */
331     else
332     {
333       TemperatureNP.s = IPS_OK;
334       IDSetNumber(&TemperatureNP, "Target temperature reached.");
335
336       break;
337     }
338
339     IDSetNumber(&TemperatureNP, NULL);
340     break;
341   }
342
343   /* Keep polling alive */
344   IEAddTimer (1000, ISPoll, NULL);
345
346}
Note: See TracBrowser for help on using the repository browser.