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

Last change on this file since 654 was 490, checked in by campagne, 15 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.