source: BAORadio/libindi/v1.0.1/examples/tutorial_three.c @ 503

Last change on this file since 503 was 490, checked in by campagne, 14 years ago

import libindi (JEC)

File size: 8.3 KB
Line 
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 */
68static IBLOB imageB = {"CCD1", "Feed", "", 0, 0, 0, 0, 0, 0, 0};
69static IBLOBVectorProperty imageBP = {mydev, "Video", "Video", COMM_GROUP,
70  IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
71
72void ISGetProperties (const char *dev)
73{ 
74
75  if (dev && strcmp (mydev, dev))
76    return;
77
78  /* COMM_GROUP */
79  IDDefSwitch(&PowerSP, NULL);
80  IDDefNumber(&ExposeTimeNP, NULL);
81  IDDefNumber(&TemperatureNP, NULL);
82  IDDefBLOB(&imageBP, NULL);
83
84  IEAddTimer(1000, ISPoll, NULL);
85 
86}
87
88/* Note that we must define ISNewBLOB and ISSnoopDevice even if we don't use them, otherwise, the driver will NOT compile */
89void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {}
90void ISSnoopDevice (XMLEle *root) {}
91
92 
93void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
94{
95        /* ignore if not ours */
96        if (dev && strcmp (dev, mydev))
97            return;
98           
99        /* Connection */
100        if (!strcmp (name, PowerSP.name))
101        {
102          IUUpdateSwitch(&PowerSP, states, names, n);
103          PowerSP.s = IPS_OK;
104          if (PowerS[0].s == ISS_ON)
105                IDSetSwitch(&PowerSP, "CCD Simulator is online.");
106          else
107                IDSetSwitch(&PowerSP, "CCD Simulator is offline.");
108          return;
109        }
110       
111}
112
113void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
114{
115       /* ignore if not ours */ 
116       if (dev && strcmp (mydev, dev))
117         return;
118
119        /* suppress warning */
120        n=n; dev=dev; name=name; names=names; texts=texts;
121       
122}
123
124
125void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
126{
127
128    /* Exposure time */
129    if (!strcmp (ExposeTimeNP.name, name))
130    {
131
132     /* Let's make sure that our simulator is online */
133     if (PowerS[0].s != ISS_ON)
134     {
135       ExposeTimeNP.s = IPS_IDLE;
136       IDSetNumber(&ExposeTimeNP, "CCD Simulator is offline.");
137       return;
138     }
139
140      IDLog("Sending BLOB FITS...\n");
141
142      ExposeTimeNP.s = IPS_BUSY;
143      ExposeTimeN[0].value = values[0];
144 
145      return;
146    } 
147
148    /* Temperature */
149    if (!strcmp (TemperatureNP.name, name))
150    {
151
152     /* Let's make sure that our simulator is online */
153     if (PowerS[0].s != ISS_ON)
154     {
155       TemperatureNP.s = IPS_IDLE;
156       IDSetNumber(&TemperatureNP, "CCD Simulator is offline");
157       return;
158     }
159
160      targetTemp = values[0];
161
162      /* If the requested temperature is the current CCD chip temperature, then return */
163      if (targetTemp == TemperatureN[0].value)
164      {
165        TemperatureNP.s = IPS_OK;
166        IDSetNumber(&TemperatureNP, NULL);
167        return;
168      }
169     
170      /* Otherwise, set property state to busy */
171      TemperatureNP.s = IPS_BUSY;
172      IDSetNumber(&TemperatureNP, "Setting CCD temperature to %g", targetTemp);
173
174      return;
175    }
176
177}
178
179/* Open a data file, compress its content, and send it via our BLOB property */
180void uploadFile(const char* filename)
181{
182   FILE * fitsFile;
183   unsigned char *fitsData, *compressedData;
184   int r=0;
185   unsigned int i =0, nr = 0;
186   uLongf compressedBytes=0;
187   uLong  totalBytes;
188   struct stat stat_p; 
189 
190   /* #1 Let's get the file size */
191   if ( -1 ==  stat (filename, &stat_p))
192   { 
193     IDLog(" Error occoured attempting to stat file.\n"); 
194     return; 
195   }
196   
197   /* #2 Allocate memory for raw and compressed data */
198   totalBytes     = stat_p.st_size;
199   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
200   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
201   
202   if (fitsData == NULL || compressedData == NULL)
203   {
204     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
205     return;
206   }
207   
208   /* #3 Open the FITS file */
209   fitsFile = fopen(filename, "r");
210   
211   if (fitsFile == NULL)
212    return;
213   
214   /* #4 Read file from disk */ 
215   for (i=0; i < totalBytes; i+= nr)
216   {
217      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
218     
219     if (nr <= 0)
220     {
221        IDLog("Error reading temporary FITS file.\n");
222        return;
223     }
224   }
225   
226   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
227   
228   /* #5 Compress raw data */ 
229   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
230   if (r != Z_OK)
231   {
232        /* this should NEVER happen */
233        IDLog("internal error - compression failed: %d\n", r);
234        return;
235   }
236   
237   /* #6 Send it */
238   imageB.blob = compressedData;
239   imageB.bloblen = compressedBytes;
240   imageB.size = totalBytes;
241   strcpy(imageB.format, ".fits.z");
242
243   /* #7 Set BLOB state to Ok */
244   imageBP.s = IPS_OK;
245   IDSetBLOB (&imageBP, NULL);
246
247   /* #8 Set Exposure status to Ok */
248   ExposeTimeNP.s = IPS_OK;
249   IDSetNumber(&ExposeTimeNP, "Sending FITS...");
250   
251   /* #9 Let's never forget to free our memory */
252   free (fitsData);   
253   free (compressedData);
254   
255}
256
257/* Poll device status and update accordingly */
258void ISPoll(void * p)
259{
260
261   /* We need to check the status of properties that we want to watch. */
262
263   /* #1 CCD Exposure */
264   switch (ExposeTimeNP.s)
265   {
266     case IPS_IDLE:
267     case IPS_OK:
268     case IPS_ALERT:
269        break;
270
271     /* If an exposure state is busy, decrement the exposure value until it's zero (done exposing). */
272     case IPS_BUSY:
273        ExposeTimeN[0].value--;
274
275        /* Are we done yet? */
276        if (ExposeTimeN[0].value == 0)
277        {
278          /* Let's set the state of OK and report that to the client */
279          ExposeTimeNP.s = IPS_OK;
280 
281          /* Upload a sample FITS file */
282          uploadFile("ngc1316o.fits");
283
284          IDSetNumber(&ExposeTimeNP, NULL);
285          break;
286        }
287
288        IDSetNumber(&ExposeTimeNP, NULL);
289        break;
290   } 
291
292   /* #2 CCD Temperature */
293   switch (TemperatureNP.s)
294   {
295     case IPS_IDLE:
296     case IPS_OK:
297     case IPS_ALERT:
298        break;
299
300     case IPS_BUSY:
301     /* If target temperature is higher, then increase current CCD temperature */ 
302     if (currentTemp < targetTemp)
303        currentTemp++;
304     /* If target temperature is lower, then decrese current CCD temperature */
305     else if (currentTemp > targetTemp)
306       currentTemp--;
307     /* If they're equal, stop updating */
308     else
309     {
310       TemperatureNP.s = IPS_OK;
311       IDSetNumber(&TemperatureNP, "Target temperature reached.");
312
313       break;
314     }
315
316     IDSetNumber(&TemperatureNP, NULL);
317     break;
318   }
319
320   /* Keep polling alive */
321   IEAddTimer (1000, ISPoll, NULL);
322
323}
Note: See TracBrowser for help on using the repository browser.