source: BAORadio/libindi/v1/drivers/video/stv.c @ 620

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

import libindi (JEC)

File size: 49.5 KB
Line 
1#if 0
2    STV Driver
3    Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
19#endif
20
21/* Standard headers */
22
23#include <string.h>
24#include <sys/stat.h>
25#include <stdio.h>
26#include <zlib.h>
27#include <unistd.h>
28
29#ifndef _WIN32
30#include <termios.h>
31#endif
32
33/* INDI Core headers */
34
35#include "indidevapi.h"
36
37/* INDI Eventloop mechanism */
38
39#include "eventloop.h"
40
41/* INDI Common Routines/RS232 */
42
43#include "indicom.h"
44
45/* Config parameters */
46#include <config.h>
47
48/* Fits */
49
50#include <fitsio.h>
51
52/* STV's definitions */
53
54#include "stvdriver.h"
55
56/* Definitions */
57
58#define mydev              "STV Guider"     /* Device name */
59#define CONNECTION_GROUP   "Connection"     /* Group name */
60#define SETTINGS_GROUP     "Setings"        /* Group name */
61#define BUTTONS_GROUP      "Buttons and Knobs"        /* Button Pannel */
62#define IMAGE_GROUP        "Download"        /* Button Pannel */
63
64#define currentBuffer             BufferN[0].value
65#define currentX                  WindowingN[0].value
66#define currentY                  WindowingN[1].value
67#define currentLines              WindowingN[2].value
68#define currentLength             WindowingN[3].value
69
70#define currentCompression        CompressionS[0].s
71 
72static int compression= OFF ;
73static int acquiring=   OFF ;
74static int guiding=     OFF ; 
75static int processing=  OFF ;
76
77/* Fits (fli_ccd project) */
78enum STVFrames { LIGHT_FRAME = 0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME };
79#define TEMPFILE_LEN    16
80
81
82/* Image (fli_ccd project)*/
83
84typedef struct {
85int  width;
86int  height;
87int  frameType;
88int  expose;
89unsigned short  *img;
90} img_t;
91
92static img_t *STVImg;
93
94/* Function adapted from fli_ccd project */
95
96void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info) ;
97int  writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[]) ;
98void uploadFile(const char* filename) ;
99
100/* File descriptor and call back id */
101int fd ;
102static int cb= -1 ;
103char tracking_buf[1024] ;
104
105
106/* Function prototypes */
107int ISTerminateTXDisplay(void) ;
108int ISRestoreTXDisplay(void) ;
109int ISMessageImageInfo( int buffer, IMAGE_INFO *image_info) ;
110int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) ;
111
112int STV_LRRotaryDecrease(void) ;
113int STV_LRRotaryIncrease(void) ;
114int STV_UDRotaryDecrease(void) ;
115int STV_UDRotaryIncrease(void) ;
116
117int STV_AKey(void) ;
118int STV_BKey(void) ;
119int STV_Setup(void) ;
120int STV_Interrupt(void) ;
121int STV_Focus(void) ;
122int STV_Image(void) ;
123int STV_Monitor(void) ;
124int STV_Calibrate(void) ;
125int STV_Track(void) ;
126int STV_Display(void) ;
127int STV_FileOps(void) ;
128int STV_RequestImageInfo(int imagebuffer, IMAGE_INFO *image_info) ;
129int STV_BufferStatus(int buffer) ;
130int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) ;
131int STV_Download( void) ;
132int STV_TXDisplay(void) ;
133int STV_TerminateTXDisplay(void) ;
134int STV_RequestAck(void) ;
135unsigned int STV_GetBits( unsigned int x, int p, int n) ;
136int STV_PrintBuffer( unsigned char *cmdbuf, int n ); 
137void handleError(ISwitchVectorProperty *svp, int err, const char *msg) ;
138static void ISInit() ;
139void ISCallBack(void) ;
140
141
142int init_serial(char *device_name, int bit_rate, int word_size, int parity, int stop_bits) ;
143int STV_ReceivePacket( unsigned char *buf, int mode) ;
144int STV_Connect( char *device, int baud) ;
145#ifdef HAVE_NOVA_H
146int STV_SetDateTime( char *times) ;
147#endif
148double STV_SetCCDTemperature(double set_value) ;
149
150
151
152
153static IText StatusT[]= {
154  {"STATUS", "This driver", "is experimental, contact markus.wildi@datacomm.ch", 0, 0, 0},
155};
156
157static ITextVectorProperty StatusTP= { 
158  mydev, "STAUS", "Status", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, StatusT, NARRAY(StatusT), "", 0
159} ;
160
161/* RS 232 Connection */
162
163static ISwitch PowerS[] = { 
164  {"CONNECT", "Connect", ISS_OFF, 0, 0},                         
165  {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0},
166};
167
168static ISwitchVectorProperty PowerSP = { 
169  mydev, "CONNECTION", "Connection", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0
170};     
171
172/* Serial Port */
173
174static IText PortT[]= {
175  {"PORT", "Port", NULL, 0, 0, 0},
176  {"SPEED", "Speed", NULL, 0, 0, 0}
177}; 
178
179static ITextVectorProperty PortTP= { 
180  mydev, "DEVICE_PORT", "Port", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, PortT, NARRAY(PortT), "", 0
181} ;
182
183static ISwitch TXDisplayS[]= {
184
185  {"1", "On",   ISS_ON, 0, 0}, 
186  {"2", "Off",  ISS_OFF, 0, 0}, 
187};
188
189static ISwitchVectorProperty TXDisplaySP= { 
190  mydev, "Update Display",  "Update Display", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TXDisplayS, NARRAY(TXDisplayS), "", 0 
191} ;
192
193static IText DisplayCT[]= {
194
195  {"DISPLAYC1", "Line 1", NULL, 0, 0, 0},
196  {"DISPLAYC2", "Line 2", NULL, 0, 0, 0}
197}; 
198
199static ITextVectorProperty DisplayCTP= { 
200  mydev, "DISPLAYC", "Display", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayCT, NARRAY(DisplayCT), "", 0
201} ;
202
203static IText DisplayBT[]= {
204
205  {"DISPLAYB1", "Line 1", NULL, 0, 0, 0},
206  {"DISPLAYB2", "Line 2", NULL, 0, 0, 0}
207}; 
208
209static ITextVectorProperty DisplayBTP= { 
210  mydev, "DISPLAYB", "Display", BUTTONS_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayBT, NARRAY(DisplayBT), "", 0
211    } ;
212
213static IText DisplayDT[]= {
214
215  {"DISPLAYD1", "Line 1", NULL, 0, 0, 0},
216  {"DISPLAYD2", "Line 2", NULL, 0, 0, 0}
217}; 
218
219static ITextVectorProperty DisplayDTP= { 
220  mydev, "DISPLAYD", "Display", IMAGE_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayDT, NARRAY(DisplayDT), "", 0
221} ;
222
223
224/* Setings */
225
226static IText UTCT[] = {{"UTC", "UTC", NULL, 0, 0, 0}};
227ITextVectorProperty UTCTP = { mydev, "TIME_UTC", "UTC Time", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, UTCT, NARRAY(UTCT), "", 0};
228
229static INumber SetCCDTemperatureN[]= {
230  { "TEMPERATURE", "Cel. -55.1, +25.2", "%6.1f", -55.8, 25.2, 0.,16., 0, 0, 0},
231
232} ;
233
234static INumberVectorProperty SetCCDTemperatureNP= { 
235  mydev, "CCD_TEMPERATURE", "CCD Temperature",  SETTINGS_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, SetCCDTemperatureN, NARRAY(SetCCDTemperatureN), "", 0
236} ;
237
238
239/* Buttons */
240static ISwitch ControlS[]= {
241
242  {"1", "Parameter", ISS_OFF, 0, 0}, 
243  {"2", "Increase",  ISS_OFF, 0, 0}, 
244  {"3", "Decrease",  ISS_OFF, 0, 0},
245 
246};
247
248static ISwitchVectorProperty ControlSP= { 
249  mydev, "ParaButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ControlS, NARRAY(ControlS), "",  0 
250} ;
251
252static ISwitch ValueS[]= {
253
254  {"1", "Value",    ISS_OFF, 0, 0}, 
255  {"2", "Increase", ISS_OFF, 0, 0}, 
256  {"3", "Decrease", ISS_OFF, 0, 0}, 
257};
258
259static ISwitchVectorProperty ValueSP= { 
260  mydev, "ValueButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ValueS, NARRAY(ValueS), "", 0 
261} ;
262
263static ISwitch AuxiliaryS[]= {
264
265  {"1", "Setup",     ISS_OFF, 0, 0}, 
266  {"2", "Interrupt", ISS_OFF, 0, 0}, 
267
268};
269
270static ISwitchVectorProperty AuxiliarySP= { 
271  mydev, "Auxilliary",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AuxiliaryS, NARRAY(AuxiliaryS), "", 0 
272} ;
273
274
275static ISwitch AcquireS[]= {
276
277  {"1", "Focus",   ISS_OFF, 0, 0}, 
278  {"2", "Image",   ISS_OFF, 0, 0}, 
279  {"3", "Monitor", ISS_OFF, 0, 0}, 
280};
281
282static ISwitchVectorProperty AcquireSP= { 
283  mydev, "Acquire",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AcquireS, NARRAY(AcquireS), "", 0 
284} ;
285
286static ISwitch GuideS[]= {
287
288  {"1", "Calibrate", ISS_OFF, 0, 0}, 
289  {"2", "Track",     ISS_OFF, 0, 0}, 
290};
291
292static ISwitchVectorProperty GuideSP= { 
293  mydev, "Guide",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, GuideS, NARRAY(GuideS), "", 0 
294} ;
295
296static ISwitch ProcessS[]= {
297
298  {"1", "Display/Crosshairs", ISS_OFF, 0, 0}, 
299  {"2", "File Ops",           ISS_OFF, 0, 0}, 
300};
301
302static ISwitchVectorProperty ProcessSP= { 
303  mydev, "Process",  "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ProcessS, NARRAY(ProcessS), "", 0 
304} ;
305
306static ISwitch CompressionS[]= {
307
308  {"1", "On",   ISS_OFF, 0, 0}, 
309  {"2", "Off",  ISS_OFF, 0, 0}, 
310};
311
312static ISwitchVectorProperty CompressionSP= { 
313  mydev, "Compression",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, CompressionS, NARRAY(CompressionS), "", 0 
314} ;
315
316static ISwitch BufferStatusS[]= {
317
318  {"1", "Status",   ISS_OFF, 0, 0}, 
319};
320
321static ISwitchVectorProperty BufferStatusSP= { 
322  mydev, "Buffers",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, BufferStatusS, NARRAY(BufferStatusS), "", 0 
323} ;
324
325static INumber BufferN[]= {
326  { "A0", "Number 1 - 32", "%6.0f", 1., 32., 0.,32., 0, 0, 0}, 
327} ;
328
329static INumberVectorProperty BufferNP= { 
330  mydev, "BUFFER_Number", "Buffer", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, BufferN, NARRAY(BufferN), "", 0
331} ;
332
333static INumber WindowingN[]= {
334
335  { "X", "Offset x", "%6.0f", 0., 199., 0., 0., 0, 0, 0}, 
336  { "Y", "Offset y", "%6.0f", 0., 319., 0., 0., 0, 0, 0}, 
337  { "HEIGHT", "Lines",    "%6.0f", 1., 200., 0., 200., 0, 0, 0},
338  { "WIDTH", "Length",   "%6.0f", 1., 320., 0., 320., 0, 0, 0}, 
339} ;
340
341static INumberVectorProperty WindowingNP= { 
342  mydev, "CCD_FRAME", "Windowing", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, WindowingN, NARRAY(WindowingN), "", 0
343} ;
344
345static ISwitch ImageInfoS[]= {
346
347  {"1", "One Image",  ISS_OFF, 0, 0}, 
348  {"2", "All Images", ISS_OFF, 0, 0}, 
349};
350
351static ISwitchVectorProperty ImageInfoSP= { 
352  mydev, "Information",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ImageInfoS, NARRAY(ImageInfoS), "", 0 
353} ;
354
355static ISwitch DownloadS[]= {
356
357  {"1", "One Image",   ISS_OFF, 0, 0}, 
358  {"2", "All Images",  ISS_OFF, 0, 0}, 
359};
360
361static ISwitchVectorProperty DownloadSP= { 
362  mydev, "Download",  "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DownloadS, NARRAY(DownloadS), "", 0 
363} ;
364
365/* BLOB for sending image */
366
367static IBLOB imageB= {"CCD1", "Image", "", 0, 0, 0, 0, 0, 0, 0};
368
369static IBLOBVectorProperty imageBP= {mydev, "Image", "Image", IMAGE_GROUP, IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0};
370
371
372
373/* Initlization routine */
374
375static void ISInit() {
376
377  static int isInit= 0; 
378 
379  if( isInit)  return;
380 
381  IUSaveText( &PortT[0],  "/dev/ttyUSB0"); 
382  IUSaveText( &PortT[1],  "115200"); 
383
384  if((  DisplayCT[0].text= malloc( 1024))== NULL){
385    fprintf(stderr,"3:Memory allocation error");
386    return;
387  }
388  if((DisplayCT[1].text = malloc( 1024))== NULL){
389    fprintf(stderr,"4:Memory allocation error");
390    return;
391  }
392  if(( DisplayBT[0].text= malloc( 1024))== NULL){
393    fprintf(stderr,"5:Memory allocation error");
394    return;
395  }
396  if(( DisplayBT[1].text= malloc( 1024))== NULL){
397    fprintf(stderr,"5:Memory allocation error");
398    return;
399  }
400  if(( DisplayDT[0].text= malloc( 1024))== NULL){
401    fprintf(stderr,"7:Memory allocation error");
402    return;
403  }
404  if(( DisplayDT[1].text= malloc( 1024))== NULL){
405    fprintf(stderr,"8:Memory allocation error");
406    return;
407  }
408
409  if(( STVImg= malloc( sizeof(img_t)))== NULL){
410    fprintf(stderr,"9:Memory allocation error");
411    return;
412  }
413
414  isInit = 1;
415}
416
417void ISResetButtons( char *message) {
418
419  ControlSP.s= IPS_IDLE ;
420  IUResetSwitch(&ControlSP);
421  IDSetSwitch(&ControlSP, NULL);
422 
423  ValueSP.s= IPS_IDLE ;
424  IUResetSwitch(&ValueSP);
425  IDSetSwitch(&ValueSP, NULL);
426
427  AuxiliarySP.s= IPS_IDLE ;
428  IUResetSwitch(&AuxiliarySP);
429  IDSetSwitch(&AuxiliarySP, NULL);
430
431  AcquireSP.s= IPS_IDLE ;
432  IUResetSwitch(&AcquireSP);
433  IDSetSwitch(&AcquireSP, NULL);
434
435  GuideSP.s= IPS_IDLE ;
436  IUResetSwitch(&GuideSP);
437  IDSetSwitch(&GuideSP, NULL);
438
439  ProcessSP.s= IPS_IDLE ;
440  IUResetSwitch(&ProcessSP);
441  IDSetSwitch(&ProcessSP, NULL);
442
443  ImageInfoSP.s= IPS_IDLE ;
444  IUResetSwitch(&ImageInfoSP);
445  IDSetSwitch(&ImageInfoSP, NULL);
446
447  BufferStatusSP.s= IPS_IDLE ;
448  IUResetSwitch(&BufferStatusSP);
449  IDSetSwitch(&BufferStatusSP, NULL);
450
451/*   SP.s= IPS_IDLE ; */
452/*   IUResetSwitch(&SP); */
453/*   IDSetSwitch(&SP, NULL); */
454
455  DownloadSP.s= IPS_IDLE ;
456  IUResetSwitch(&DownloadSP);
457
458  IDSetSwitch(&DownloadSP, "%s", message);
459   
460  return ;
461}
462
463/* This function is called when ever the file handle fd provides data */
464void ISCallBack() {
465
466  int res ;
467  int k,l,m ;
468
469  unsigned char buf[1024] ;
470
471
472  IERmCallback( cb) ;
473  cb = -1 ;
474
475/*   fprintf( stderr, "ISCallBack\n") ; */
476/*   if(( counter++ % 4) ==0){ */
477/*   fprintf( stderr, ".") ; */
478/*   } */
479
480  if( PowerS[0].s == ISS_ON) {
481
482
483    res= STV_ReceivePacket( buf, guiding) ;
484
485 
486/*     res= STV_PrintBuffer(buf,res) ; */
487
488    DisplayCTP.s= IPS_IDLE ;
489    IDSetText( &DisplayCTP, NULL) ;
490    DisplayBTP.s= IPS_IDLE ;
491    IDSetText( &DisplayBTP, NULL) ;
492    DisplayDTP.s= IPS_IDLE ;
493    IDSetText( &DisplayDTP, NULL) ;
494
495    switch ((int) buf[1]) {       /* STV cmd byte */
496 
497    case DISPLAY_ECHO:
498
499      if( res < 0 ) { 
500       
501        DisplayCTP.s= IPS_ALERT ;
502        IDSetText( &DisplayCTP, NULL) ;
503        DisplayBTP.s= IPS_ALERT ;
504        IDSetText( &DisplayBTP, NULL) ;
505        DisplayDTP.s= IPS_ALERT ;
506        IDSetText( &DisplayDTP, NULL) ;
507        IDMessage(mydev, "Error while reading, continuing\n");
508       
509      } else {
510
511        l= 0 ;
512        m= 0 ;
513        /* replace unprintable characters and format the string */
514        for( k= 0; k < 24; k++) {
515 
516          if( buf[k+ 6]== 0x5e) { /* first line */
517           
518            DisplayCT[0].text[l-1]= 0x50 ;   /* P */
519            DisplayCT[0].text[l++]  = 0x6b ; /* k */
520           
521          } else if( buf[k+ 6]== 0xd7) {
522           
523            DisplayCT[0].text[l++]= 0x28 ; /* "(x,y) " */
524            DisplayCT[0].text[l++]= 0x78 ;
525            DisplayCT[0].text[l++]= 0x2c ;
526            DisplayCT[0].text[l++]= 0x79 ;
527            DisplayCT[0].text[l++]= 0x29 ;
528            DisplayCT[0].text[l++]= 0x20 ;
529
530          } else if( buf[k+ 6] >29 &&  buf[k+ 6] < 127) {
531                                           
532            DisplayCT[0].text[l++]= buf[k+ 6] ;
533
534          } else {
535           
536            /* fprintf(stderr, "LINE 1%2x, %2x, %2x, %c %c %c\n", buf[k+ 5], buf[k+ 6], buf[k+ 7], buf[k+ 5], buf[k+ 6], buf[k+ 7]) ; */
537            DisplayCT[0].text[l++]= 0x20 ;
538           
539          }
540          if( buf[k+ 30]== 0xb0){ /* second line */
541
542            DisplayCT[1].text[m++]= 0x43 ; /* Celsius */
543
544          } else if( buf[k+ 30] >29 &&  buf[k +30] < 127) {
545           
546            DisplayCT[1].text[m++]=buf[k + 30] ;
547          } else {
548           
549            /* fprintf(stderr, "LINE 2 %2x, %2x, %2x, %c %c %c\n", buf[k+ 29], buf[k+ 30], buf[k+ 31], buf[k+ 29], buf[k+ 30], buf[k+ 31]) ; */
550            DisplayCT[1].text[m++]= 0x20 ; 
551          }
552        }
553        DisplayCT[0].text[l]= 0 ;
554        DisplayCT[1].text[m]= 0 ;
555
556
557        strcpy(DisplayBT[0].text, DisplayCT[0].text) ;
558        strcpy(DisplayBT[1].text, DisplayCT[1].text) ;
559        strcpy(DisplayDT[0].text, DisplayCT[0].text) ;
560        strcpy(DisplayDT[1].text, DisplayCT[1].text) ;
561     
562        DisplayCTP.s= IPS_OK ;
563        IDSetText( &DisplayCTP, NULL) ;
564        DisplayBTP.s= IPS_OK ;
565        IDSetText( &DisplayBTP, NULL) ;
566        DisplayDTP.s= IPS_OK ;
567        IDSetText( &DisplayDTP, NULL) ;
568      }
569      break ;
570    case REQUEST_DOWNLOAD:
571
572      /* fprintf(stderr, "STV says REQUEST_DOWNLOAD\n") ; */
573
574      if(  TXDisplayS[0].s == ISS_ON) {
575
576        res= STV_Download() ;
577
578        imageB.blob = NULL;
579        imageB.bloblen = 0;
580        imageB.size = 0;
581
582     
583        imageBP.s = IPS_ALERT;
584        IDSetBLOB (&imageBP, NULL);
585       
586        IDMessage( mydev, "Switch off display read out manually first (Update Display: Off\n)") ;
587
588      } else {
589
590        tcflush(fd, TCIOFLUSH);
591        usleep( 100000) ;
592     
593        res= ISRequestImageData( 1, 31, 0, 0, 320, 200) ; /* Download the on screen image (buffer 32 -1) */
594      }
595      /*fprintf(stderr, "STV END REQUEST_DOWNLOAD\n") ;  */
596      break ;   
597    case REQUEST_DOWNLOAD_ALL:
598     
599      IDMessage(mydev,  "REQUEST_DOWNLOAD_ALL initiated at the STV not implemented")  ;
600      break ;   
601    case ACK:
602     
603      if( cb == -1)  {
604                                         
605        strcpy(DisplayCT[0].text, "Key press acknowledged") ;
606        strcpy(DisplayBT[0].text, DisplayCT[0].text) ;
607        strcpy(DisplayDT[0].text, DisplayCT[0].text) ;
608     
609        DisplayCTP.s= IPS_OK ;
610        IDSetText( &DisplayCTP, NULL) ;
611        DisplayBTP.s= IPS_OK ;
612        IDSetText( &DisplayBTP, NULL) ;
613        DisplayDTP.s= IPS_OK ;
614        IDSetText( &DisplayDTP, NULL) ;
615      }
616      break ;
617    case NACK:
618
619      /*fprintf(stderr, "STV says NACK!!") ;   */
620      IDMessage(mydev, "STV says NACK!") ;
621      break ;
622    case REQUEST_BUFFER_STATUS:
623
624      IDMessage(mydev, "Request Buffer status seen, ignoring\n") ;
625      break ;
626    default:
627
628      if( guiding== ON) {/* While STV is tracking, it send time, brightnes, centroid x,y */
629
630        IDMessage( mydev, "Tracking: %s", tracking_buf) ;
631      } else {
632
633        /*fprintf(stderr, "STV ISCallBack: Unknown response 0x%2x\n",  buf[1]) ;  */
634        IDLog("ISCallBack: Unknown response 0x%2x\n",  buf[1]) ;
635      }
636     break ;
637    }
638  }
639  cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
640}
641
642/* Client retrieves properties */
643void ISGetProperties (const char *dev) {
644
645  /* #1 Let's make sure everything has been initialized properly */
646   ISInit();
647  /* #2 Let's make sure that the client is asking for the properties of our device, otherwise ignore */
648  if (dev && strcmp (mydev, dev))
649    return;
650   
651  /* #3 Tell the client to create new properties */
652
653  /* Connection tab */
654
655 
656  IDDefText(&DisplayCTP, NULL) ;
657  IDDefSwitch(&PowerSP, NULL) ;
658  IDDefText(&PortTP, NULL) ;
659  IDDefSwitch(&TXDisplaySP, NULL) ;
660  IDDefText(&StatusTP, NULL) ;
661
662  /* Settings Tab */
663  IDDefText(&UTCTP, NULL) ;
664  IDDefNumber(&SetCCDTemperatureNP, NULL) ;
665
666  /* Buttons tab */
667  IDDefText(&DisplayBTP, NULL) ;
668  IDDefSwitch(&ControlSP, NULL) ;
669  IDDefSwitch(&ValueSP, NULL) ;
670  IDDefSwitch(&AuxiliarySP, NULL) ;
671  IDDefSwitch(&AcquireSP, NULL) ;
672  IDDefSwitch(&GuideSP, NULL) ;
673  IDDefSwitch(&ProcessSP, NULL) ;
674
675  /* Image tab */
676  IDDefText(&DisplayDTP, NULL) ;
677  /* "direct" read out does not work well IDDefSwitch(&BufferStatusSP, NULL) ; */
678  IDDefSwitch(&BufferStatusSP, NULL) ;
679  IDDefSwitch(&ImageInfoSP, NULL);
680  IDDefNumber(&BufferNP, NULL);
681
682  IDDefSwitch(&DownloadSP, NULL) ;
683  IDDefSwitch(&CompressionSP, NULL) ;
684  IDDefNumber(&WindowingNP, NULL);
685  IDDefBLOB(&imageBP, NULL);
686} 
687
688/* Client sets new switch */
689void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) {
690
691  int i, j ;
692  int res = 0;
693  int baud ;
694  IMAGE_INFO image_info ;
695  ISwitch *sp ;
696  int lower_buffer = 0;
697  int upper_buffer = 0 ;
698
699  /*fprintf(stderr, "ISNewSwitch\n") ; */
700
701  /* #1 Let's make sure everything has been initialized properly */
702 
703  ISInit();
704       
705  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
706 
707  if (dev && strcmp (dev, mydev))
708    return;
709           
710  /* #3 Now let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/
711 
712  if( !strcmp (name, PowerSP.name)) {
713         
714    /* A. We reset all switches (in this case CONNECT and DISCONNECT) to ISS_OFF */
715   
716    IUResetSwitch(&PowerSP);
717
718    /* B. We update the switches by sending their names and updated states IUUpdateSwitch function */
719   
720    IUUpdateSwitch(&PowerSP, states, names, n);
721         
722    /* C. We try to establish a connection to our device or terminate it*/
723
724    int res= 0 ;
725    switch (PowerS[0].s) {
726    case ISS_ON:
727       
728      if(( res= strcmp( "9600", PortT[1].text)) ==0) {
729
730        baud= 9600 ;
731      } else if(( res= strcmp( "19200", PortT[1].text)) ==0) {
732        baud= 19200 ;
733      } else if( (res= strcmp( "38400", PortT[1].text)) ==0) {
734        baud= 38400 ;
735      } else if(( res= strcmp( "57600", PortT[1].text)) ==0) {
736        baud= 57600 ;
737      } else if(( res= strcmp( "115200", PortT[1].text)) ==0) {
738        baud= 115200 ;
739      } else {
740
741        IUSaveText(&PortT[1], "9600");
742        IDSetText(&PortTP, "Wrong RS 232 value: %s, defaulting to 9600 baud",  PortT[1].text);
743        return ;
744      }
745                   
746      if(( fd= STV_Connect( PortT[0].text, baud))== -1) {
747
748        PowerSP.s = IPS_ALERT;
749        IUResetSwitch( &PowerSP);
750        IDSetSwitch( &PowerSP, "Error connecting to port %s", PortT[0].text);
751
752        return;
753      } else {
754
755        cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
756       
757        /* The SBIG manual says one can request an ACK, never saw it, even not on a RS 232 tester */
758        if(( res= STV_RequestAck()) != 0) {
759          fprintf( stderr, "COULD not write an ACK\n") ;
760        } 
761        /* Second trial: start reading out the display  */
762        if((res= STV_TXDisplay()) != 0) {
763         
764          fprintf(stderr, "STV: Could not write  %d\n", res) ;
765          return ;
766        }
767      }
768
769      PowerSP.s = IPS_OK ;
770      IDSetSwitch(&PowerSP, "STV is online, port: %s, baud rate: %s", PortT[0].text, PortT[1].text) ;
771     
772      PortTP.s = IPS_OK ;
773      IDSetText(&PortTP, NULL);
774
775      break;   
776
777    case ISS_OFF:
778
779      IERmCallback( cb) ;
780      cb = -1 ;
781
782      /* Close the serial port */
783               
784      tty_disconnect(fd);
785
786      ISResetButtons(NULL) ;
787       
788      GuideSP.s= IPS_IDLE ;
789      IUResetSwitch(&GuideSP);
790      IDSetSwitch(&GuideSP, NULL);
791
792      TXDisplaySP.s= IPS_IDLE ;
793      IUResetSwitch(&TXDisplaySP);
794      IDSetSwitch(&TXDisplaySP, NULL);
795     
796      DisplayCTP.s = IPS_IDLE;
797      IDSetText (&DisplayCTP, NULL);
798
799      DisplayBTP.s = IPS_IDLE;
800      IDSetText (&DisplayBTP, NULL);
801
802      DisplayDTP.s = IPS_IDLE;
803      IDSetText (&DisplayDTP, NULL);
804     
805      PortTP.s = IPS_IDLE ;
806      IDSetText(&PortTP, NULL) ;
807     
808      imageB.blob = NULL;
809      imageB.bloblen = 0;
810      imageB.size = 0;
811
812     
813      imageBP.s = IPS_IDLE;
814      IDSetBLOB (&imageBP, NULL);
815
816      PowerSP.s = IPS_IDLE;
817      IUResetSwitch(&PowerSP);
818      IDSetSwitch(&PowerSP, "STV is offline");
819
820      break;
821    }
822    return ;
823
824  } else if( !strcmp (name, AuxiliarySP.name)) {
825
826    /* Setup und interrupt buttons */
827
828    ISResetButtons(NULL) ;
829    IUResetSwitch(&AuxiliarySP);
830    IUUpdateSwitch(&AuxiliarySP, states, names, n);
831
832    for( i = 0; i < n; i++) {
833     
834      sp = IUFindSwitch (&AuxiliarySP, names[i]) ;
835
836      if( sp == &AuxiliaryS[0]){
837       
838        res= STV_Setup() ;
839       
840      } else if( sp == &AuxiliaryS[1]){
841
842        res= STV_Interrupt() ;
843      }
844    }
845    if( res== 0) {
846
847      AuxiliarySP.s= IPS_OK ;
848      IUResetSwitch(&AuxiliarySP) ;
849      IDSetSwitch(&AuxiliarySP, NULL) ;
850
851    } else {
852
853      AuxiliarySP.s= IPS_ALERT ;
854      IUResetSwitch(&AuxiliarySP) ;
855      IDSetSwitch(&AuxiliarySP, "Check connection") ;
856    }
857
858  } else if( !strcmp (name, ControlSP.name)) {
859
860    /* Parameter, value and the rotary knobs */
861    ISResetButtons(NULL) ;
862    IUResetSwitch(&ControlSP);
863    IUUpdateSwitch(&ControlSP, states, names, n);
864
865    acquiring=   OFF ;
866    guiding=     OFF ; 
867    processing=  OFF ;
868
869    for( i = 0; i < n; i++) {
870     
871      sp = IUFindSwitch (&ControlSP, names[i]) ;
872     
873      /* If the state found is ControlS[0] then process it */
874     
875      if( sp == &ControlS[0]){
876
877        res= STV_AKey() ;
878
879      } else if( sp == &ControlS[1]){
880
881        res= STV_UDRotaryIncrease() ;
882
883      } else if( sp == &ControlS[2]){
884
885        res= STV_UDRotaryDecrease() ;
886      }
887    }
888    if( res== 0) {
889
890      ControlSP.s= IPS_OK ;
891      IUResetSwitch(&ControlSP) ;
892      IDSetSwitch(&ControlSP, NULL) ;
893
894    } else {
895
896      ControlSP.s= IPS_ALERT ;
897      IUResetSwitch(&ControlSP) ;
898      IDSetSwitch(&ControlSP, "Check connection") ;
899    }
900  } else if( !strcmp (name, ValueSP.name)) {
901
902    /* Button Value, left/right knob */
903    ISResetButtons(NULL) ;
904    IUResetSwitch(&ValueSP);
905    IUUpdateSwitch(&ValueSP, states, names, n);
906
907    acquiring=   OFF ;
908    guiding=     OFF ; 
909    processing=  OFF ;
910
911    for( i = 0; i < n; i++) {
912     
913      sp = IUFindSwitch (&ValueSP, names[i]) ;
914 
915      if( sp == &ValueS[0]){
916
917        res= STV_BKey() ;
918
919      } else if( sp == &ValueS[1]){
920
921        res= STV_LRRotaryIncrease() ;
922
923      } else if( sp == &ValueS[2]){
924
925        res= STV_LRRotaryDecrease() ;
926      }
927    }
928
929    if( res== 0) {
930
931      ValueSP.s= IPS_OK ;
932      IUResetSwitch(&ValueSP) ;
933      IDSetSwitch(&ValueSP, NULL) ;
934
935    } else {
936
937      ValueSP.s= IPS_ALERT ;
938      IUResetSwitch(&ValueSP) ;
939      IDSetSwitch(&ValueSP, "Check connection") ;
940    }
941  } else if( !strcmp (name, AcquireSP.name)) {
942
943    /* Focus, Image Monitor buttons */
944    ISResetButtons(NULL) ;
945    IUResetSwitch(&AcquireSP);
946    IUUpdateSwitch(&AcquireSP, states, names, n);
947
948    acquiring=  ON  ;
949    guiding=    OFF ;
950    processing= OFF ;
951
952    for( i = 0; i < n; i++) {
953     
954      sp = IUFindSwitch (&AcquireSP, names[i]) ;
955 
956      if( sp == &AcquireS[0]){
957
958        res= STV_Focus() ;
959
960      } else if( sp == &AcquireS[1]){
961
962        res= STV_Image() ;
963
964      } else if( sp == &AcquireS[2]){
965
966        res= STV_Monitor() ;
967      }
968    }
969    if( res== 0) {
970
971      AcquireSP.s= IPS_OK ;
972      IUResetSwitch(&AcquireSP) ;
973      IDSetSwitch(&AcquireSP, NULL) ;
974
975    } else {
976
977      AcquireSP.s= IPS_ALERT ;
978      IUResetSwitch(&AcquireSP) ;
979      IDSetSwitch(&AcquireSP, "Check connection") ;
980    }
981
982  } else if( !strcmp (name, GuideSP.name)) {
983
984    /* Calibrate, Track buttons */
985    ISResetButtons(NULL) ;
986    IUResetSwitch(&GuideSP);
987    IUUpdateSwitch(&GuideSP, states, names, n);
988
989    acquiring=  OFF  ;
990    guiding=    ON ;
991    processing= OFF ;
992
993    for( i = 0; i < n; i++) {
994     
995      sp = IUFindSwitch (& GuideSP, names[i]) ;
996 
997      if( sp == & GuideS[0]){
998
999        res= STV_Calibrate() ;
1000
1001      } else if( sp == &GuideS[1]){
1002
1003        res= STV_Track() ;
1004      } 
1005    }
1006    if( res== 0) {
1007
1008      GuideSP.s= IPS_OK ;
1009      IUResetSwitch(&GuideSP) ;
1010      IDSetSwitch(&GuideSP, NULL) ;
1011
1012    } else {
1013
1014      GuideSP.s= IPS_ALERT ;
1015      IUResetSwitch(&GuideSP) ;
1016      IDSetSwitch(&GuideSP, "Check connection") ;
1017    }
1018  } else if( !strcmp (name, ProcessSP.name)) {
1019
1020    ISResetButtons(NULL) ;
1021    IUResetSwitch(&ProcessSP);
1022    IUUpdateSwitch(&ProcessSP, states, names, n);
1023
1024    acquiring=  OFF ;
1025    guiding=    OFF ;
1026    processing= ON  ;
1027
1028    for( i = 0; i < n; i++) {
1029     
1030      sp = IUFindSwitch (&ProcessSP, names[i]) ;
1031 
1032      if( sp == &ProcessS[0]){
1033
1034        res= STV_Display() ;
1035
1036      } else if( sp == &ProcessS[1]){
1037
1038        res= STV_FileOps() ;
1039      }
1040    }
1041    if( res== 0) {
1042
1043      ProcessSP.s= IPS_OK ;
1044      IUResetSwitch(&ProcessSP) ;
1045      IDSetSwitch(&ProcessSP, NULL) ;
1046
1047    } else {
1048
1049      ProcessSP.s= IPS_ALERT ;
1050      IUResetSwitch(&ProcessSP) ;
1051      IDSetSwitch(&ProcessSP, "Check connection") ;
1052    }
1053  } else if( !strcmp (name, ImageInfoSP.name)) {
1054
1055    acquiring=   OFF ;
1056    guiding=     OFF ; 
1057    processing=  OFF ;
1058
1059    /* Read out the image buffer and display a short message if it is empty or not */
1060    res= ISTerminateTXDisplay() ;
1061
1062    for( i = 0; i < n; i++) {
1063       
1064      sp = IUFindSwitch( &ImageInfoSP, names[i]) ;
1065 
1066      if( sp == &ImageInfoS[0]){
1067
1068        if(( res= STV_RequestImageInfo( currentBuffer- 1, &image_info))== 0 ) {
1069         
1070          ISMessageImageInfo( (int)currentBuffer- 1, &image_info) ;
1071        } else {
1072          IDMessage( mydev, "Buffer %2d is empty", (int)currentBuffer) ;
1073
1074        }
1075        break ;
1076      } else if( sp == &ImageInfoS[1]){
1077
1078        for( i= 0; i < 32 ; i++) {
1079
1080          if(( res= STV_RequestImageInfo( i, &image_info))== 0 ) {
1081            ISMessageImageInfo( i, &image_info) ;
1082          } else {
1083            IDMessage( mydev, "Buffer %2d is empty", i+ 1) ;
1084          }
1085        }
1086        break ;
1087      } 
1088    }
1089    if( res== 0) {
1090
1091      ImageInfoSP.s= IPS_OK ;
1092      IUResetSwitch( &ImageInfoSP) ;
1093      IDSetSwitch( &ImageInfoSP, NULL) ;
1094
1095    } else {
1096
1097      ImageInfoSP.s= IPS_ALERT ;
1098      IUResetSwitch( &ImageInfoSP) ;
1099      /*IDSetSwitch( &ImageInfoSP, "Check connection") ; */
1100      IDSetSwitch( &ImageInfoSP, NULL) ;
1101    }
1102    res= STV_Interrupt() ; /* STV initiates a download that we do not want */
1103    res= ISRestoreTXDisplay() ;
1104
1105  } else if( !strcmp (name, CompressionSP.name)) {
1106
1107
1108    acquiring=   OFF ;
1109    guiding=     OFF ; 
1110    processing=  OFF ;
1111
1112    /* Enable or disable compression for image download */
1113    ISResetButtons(NULL) ;
1114    IUResetSwitch(&CompressionSP);
1115    IUUpdateSwitch(&CompressionSP, states, names, n);
1116
1117    for( i = 0; i < n; i++) {
1118     
1119      sp = IUFindSwitch (&CompressionSP, names[i]) ;
1120 
1121      if( sp == &CompressionS[0]){
1122
1123        CompressionS[0].s= ISS_ON ;
1124      } else if( sp == &CompressionS[1]){
1125
1126        CompressionS[1].s= ISS_ON ;
1127      }
1128    }
1129
1130    CompressionSP.s= IPS_OK ;
1131    IDSetSwitch(&CompressionSP, NULL) ;
1132
1133  } else if( !strcmp (name, BufferStatusSP.name)) {
1134
1135
1136    ISResetButtons(NULL) ;
1137
1138    BufferStatusSP.s= IPS_ALERT ;
1139    IUResetSwitch(&BufferStatusSP) ;
1140    IDSetSwitch(&BufferStatusSP, "Wait...") ;
1141     
1142    if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) {
1143   
1144      acquiring=  OFF ;
1145      guiding=    OFF ;
1146      processing= OFF ;
1147
1148      ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ;
1149
1150      AcquireSP.s= IPS_IDLE ;
1151      IUResetSwitch(&AcquireSP);
1152      IDSetSwitch(&AcquireSP, NULL);
1153
1154      GuideSP.s= IPS_IDLE ;
1155      IUResetSwitch(&GuideSP);
1156      IDSetSwitch(&GuideSP, NULL);
1157
1158      ProcessSP.s= IPS_IDLE ;
1159      IUResetSwitch(&ProcessSP);
1160      IDSetSwitch(&ProcessSP, NULL);
1161
1162      ImageInfoSP.s= IPS_IDLE ;
1163      IUResetSwitch(&ImageInfoSP);
1164      IDSetSwitch(&ImageInfoSP, NULL);
1165
1166      res= STV_Interrupt() ;
1167      usleep(100000) ;
1168      res= STV_Interrupt() ;
1169    }
1170    acquiring=  OFF ;
1171    guiding=    OFF ;
1172    processing= OFF ;
1173
1174    sp = IUFindSwitch (&BufferStatusSP, names[0]) ;
1175 
1176    if((res= ISTerminateTXDisplay()) != 0) {
1177
1178      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
1179    }
1180
1181    if( sp == &BufferStatusS[0]) {
1182
1183      for( i= 31; i > -1; i--) {
1184   
1185        usleep( 50000) ;
1186        if(( res= STV_BufferStatus( i))== 0) {
1187          IDMessage( mydev, "Buffer %2d: image present", i+ 1) ;
1188        } else {
1189          IDMessage( mydev, "Buffer %2d: empty", i+ 1) ;
1190        }
1191      }
1192    }
1193
1194    BufferStatusS[0].s= ISS_OFF ;
1195
1196    if( 0 <= res) { 
1197
1198      BufferStatusSP.s= IPS_OK ;
1199      IUResetSwitch(&BufferStatusSP) ;
1200      IDSetSwitch(&BufferStatusSP, NULL) ;
1201    } else {
1202
1203      BufferStatusSP.s= IPS_ALERT ;
1204      IUResetSwitch(&BufferStatusSP) ;
1205      IDSetSwitch(&BufferStatusSP, "Check connection") ;
1206    }
1207 
1208    res= ISRestoreTXDisplay() ;
1209    res= STV_Interrupt() ;
1210
1211  } else if( !strcmp (name, DownloadSP.name)) {
1212
1213    /* Download images */
1214    /* Downloading while the STV is occupied is not working */
1215    if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) {
1216   
1217
1218      ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ;
1219
1220      AcquireSP.s= IPS_IDLE ;
1221      IUResetSwitch(&AcquireSP);
1222      IDSetSwitch(&AcquireSP, NULL);
1223
1224      GuideSP.s= IPS_IDLE ;
1225      IUResetSwitch(&GuideSP);
1226      IDSetSwitch(&GuideSP, NULL);
1227
1228      ProcessSP.s= IPS_IDLE ;
1229      IUResetSwitch(&ProcessSP);
1230      IDSetSwitch(&ProcessSP, NULL);
1231
1232      ImageInfoSP.s= IPS_IDLE ;
1233      IUResetSwitch(&ImageInfoSP);
1234      IDSetSwitch(&ImageInfoSP, NULL);
1235
1236      res= STV_Interrupt() ;
1237      usleep(100000) ;
1238      res= STV_Interrupt() ;
1239    }
1240    acquiring=  OFF ;
1241    guiding=    OFF ;
1242    processing= OFF  ;
1243   
1244    if((res= ISTerminateTXDisplay()) != 0) {
1245
1246      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
1247    }
1248
1249    DownloadSP.s= IPS_ALERT ;
1250    IUResetSwitch(&DownloadSP) ;
1251    IDSetSwitch(&DownloadSP, NULL) ;
1252
1253    compression= OFF ;
1254    if( CompressionS[0].s ==  ISS_ON) {
1255
1256      compression= ON ;
1257    } 
1258    for( i = 0; i < n; i++) {
1259     
1260      sp = IUFindSwitch (&DownloadSP, names[i]) ;
1261 
1262      if( sp == &DownloadS[0]){
1263
1264        lower_buffer=  currentBuffer- 2 ;
1265        upper_buffer=  currentBuffer- 1 ;
1266
1267      } else if( sp == &DownloadS[1]){
1268
1269        lower_buffer=  -1 ;
1270        upper_buffer=  31 ;
1271      }
1272    }
1273    for( j= upper_buffer ; j> lower_buffer ; j--) {
1274         
1275      if((res= ISRequestImageData( compression, j, currentX, currentY, currentLength, currentLines)) != 0) {
1276        if( res== 1) {
1277
1278          IDMessage( mydev, "Buffer %2.0f: empty", (double)(j+ 1)) ;
1279        } else {
1280          break ;
1281        }
1282      }
1283    }
1284    if( res== 0) {
1285 
1286      IDMessage( mydev, "STV waits for SYNC TIME Do it! Setting time, PLEASE WAIT!") ;
1287
1288      #ifdef HAVE_NOVA_H
1289      if((res= STV_SetDateTime(NULL)) == 0) {
1290     
1291        UTCTP.s= IPS_OK ;
1292        IDSetText( &UTCTP, "Time set to UTC now") ;
1293      } else {
1294 
1295        UTCTP.s= IPS_ALERT ;
1296        IDSetText( &UTCTP, "Error setting time, check connection") ;
1297      }
1298      #endif
1299
1300      DownloadSP.s= IPS_OK ;
1301      IUResetSwitch(&DownloadSP) ;
1302      IDSetSwitch(&DownloadSP, NULL) ;
1303
1304    } else { /* res could be -1 (STV_RequestImageData) */
1305
1306      DownloadSP.s= IPS_ALERT ;
1307      IUResetSwitch(&DownloadSP) ;
1308      IDSetSwitch(&DownloadSP, "Check connection") ;
1309      IDSetSwitch(&DownloadSP, NULL) ;
1310    }
1311
1312    res= ISRestoreTXDisplay() ;
1313    res= STV_Interrupt() ;
1314    IDMessage( mydev, "You may continue NOW") ;
1315
1316  } else if( !strcmp (name, TXDisplaySP.name)) {
1317
1318    acquiring=  OFF ;
1319    guiding=    OFF ;
1320    processing= OFF  ;
1321
1322    ISResetButtons(NULL) ;
1323    IUResetSwitch(&TXDisplaySP);
1324    IUUpdateSwitch(&TXDisplaySP, states, names, n);
1325
1326    for( i = 0; i < n; i++) {
1327     
1328      sp= IUFindSwitch (&TXDisplaySP, names[i]) ;
1329     
1330      if( sp == &TXDisplayS[0]){
1331
1332        if((res= STV_TXDisplay()) == 0) {
1333         
1334          TXDisplaySP.s= IPS_OK ;
1335          IDSetSwitch( &TXDisplaySP, "Reading out display") ;
1336
1337          DisplayCTP.s = IPS_OK ;
1338          IDSetText( &DisplayCTP, NULL);
1339
1340          DisplayBTP.s = IPS_OK ;
1341          IDSetText( &DisplayBTP, NULL);
1342
1343          DisplayDTP.s = IPS_OK ;
1344          IDSetText( &DisplayDTP, NULL);
1345        }
1346       
1347      } else if( sp== &TXDisplayS[1]){
1348
1349        DisplayCTP.s = IPS_IDLE ;
1350        DisplayBTP.s = IPS_IDLE ;
1351        DisplayDTP.s = IPS_IDLE ;
1352       
1353        if((res= STV_TerminateTXDisplay()) == 0) {
1354          TXDisplaySP.s = IPS_OK ;
1355          IDSetSwitch( &TXDisplaySP, "Stopping display read out") ;
1356
1357          DisplayCTP.s = IPS_IDLE ;
1358          IUSaveText(&DisplayCT[0], "                        "); /* reset client's display */
1359          IUSaveText(&DisplayCT[1], "                        ");
1360          IDSetText( &DisplayCTP, NULL);
1361         
1362          DisplayBTP.s = IPS_IDLE ;
1363          IUSaveText(&DisplayBT[0], "                        "); /* reset client's display */
1364          IUSaveText(&DisplayBT[1], "                        ");
1365          IDSetText( &DisplayBTP, NULL); 
1366
1367          DisplayDTP.s = IPS_IDLE ;
1368          IUSaveText(&DisplayDT[0], "                        "); /* reset client's display */
1369          IUSaveText(&DisplayDT[1], "                        ");
1370          IDSetText( &DisplayDTP, NULL); 
1371        }
1372      }
1373    }
1374    if( res != 0) {
1375
1376      TXDisplaySP.s= IPS_ALERT ;
1377      IUResetSwitch(&TXDisplaySP) ;
1378      IDSetSwitch(&TXDisplaySP, "Check connection") ;
1379    }
1380
1381  }
1382}
1383
1384void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {
1385
1386  int res ;
1387  IText *tp ;
1388
1389  /*fprintf(stderr, "ISNewText\n") ; */
1390
1391  /* #1 Let's make sure everything has been initialized properly */
1392  ISInit();
1393       
1394  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
1395  if ( dev && strcmp( dev, mydev))
1396    return;
1397
1398  if( !strcmp (name, PortTP.name)) {
1399
1400    if (IUUpdateText(&PortTP, texts, names, n) < 0)
1401        return;
1402
1403    PortTP.s = IPS_OK;
1404
1405    if (PowerS[0].s == ISS_ON){
1406     
1407      PortTP.s = IPS_ALERT;
1408      IDSetText(&PortTP, "STV is already online");
1409    }
1410
1411    /* JM: Don't forget to send acknowledgment */
1412    IDSetText(&PortTP, NULL);
1413
1414  } else if( !strcmp (name, UTCTP.name)) {
1415
1416    ISResetButtons(NULL) ;
1417   
1418    tp= IUFindText (&UTCTP, names[0]) ;
1419 
1420    if((res= ISTerminateTXDisplay()) != 0) {
1421
1422      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
1423    }
1424     
1425    if( tp == &UTCT[0]) {   
1426
1427      #ifdef HAVE_NOVA_H
1428      if((res= STV_SetDateTime(NULL)) == 0) {
1429         
1430        UTCTP.s= IPS_OK ;
1431        IDSetText( &UTCTP, "Time set to UTC") ;
1432      } else {
1433
1434        UTCTP.s= IPS_ALERT ;
1435        IDSetText( &UTCTP, "Error setting time, check connection") ;
1436      }
1437      #endif
1438    }
1439    res= ISRestoreTXDisplay() ;
1440  } 
1441}
1442/* Client sets new number */
1443void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {
1444
1445  int res ; 
1446  double ccd_temperature ;
1447  /*fprintf(stderr, "ISNewNumber\n") ; */
1448
1449  /* #1 Let's make sure everything has been initialized properly */
1450  ISInit();
1451       
1452  /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */
1453  if ( dev && strcmp( dev, mydev))
1454    return;
1455
1456  if (PowerS[0].s != ISS_ON){
1457     
1458    PowerSP.s = IPS_ALERT;
1459    IDSetSwitch( &PowerSP, NULL) ;
1460    IDMessage("STV is offline", NULL);
1461    return ;
1462  }
1463
1464  if( !strcmp (name, BufferNP.name)) {
1465
1466    INumber *buffer = IUFindNumber( &BufferNP, names[0]) ;
1467
1468    if( buffer == &BufferN[0]) {
1469     
1470      currentBuffer=  values[0] ;
1471   
1472      /* Check the boundaries, this is incomplete at the moment */
1473      BufferNP.s = IPS_OK ;
1474      IDSetNumber(&BufferNP, NULL) ; 
1475    } 
1476  } else  if( !strcmp (name, WindowingNP.name)) {
1477
1478    INumber *buffer = IUFindNumber( &WindowingNP, names[0]) ;
1479
1480    if( buffer == &WindowingN[0]) {
1481     
1482      currentX     =  values[0] ;
1483      currentY     =  values[1] ;
1484      currentLines =  values[2] ;
1485      currentLength=  values[3] ;
1486
1487      WindowingNP.s = IPS_OK ;
1488      IDSetNumber(&WindowingNP, NULL) ; 
1489    }
1490  } else if( !strcmp (name, SetCCDTemperatureNP.name)) {
1491
1492    if((res= ISTerminateTXDisplay()) != 0) {
1493
1494      fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ;
1495    }
1496
1497    INumber *np= IUFindNumber (&SetCCDTemperatureNP, names[0]) ;
1498     
1499    if( np == &SetCCDTemperatureN[0]) {
1500
1501      if((ccd_temperature= STV_SetCCDTemperature(values[0])) != 0) { /* STV has no 0 C setting */
1502       
1503        SetCCDTemperatureNP.s= IPS_OK ;
1504        SetCCDTemperatureN[0].value=  ccd_temperature;
1505        IDSetNumber( &SetCCDTemperatureNP, "CCD Temperature set to %g", SetCCDTemperatureN[0].value) ;
1506
1507      } else {
1508        SetCCDTemperatureNP.s= IPS_ALERT ;
1509        IDSetNumber( &SetCCDTemperatureNP, "Error setting CCD temperature, check connection") ;
1510      } 
1511    } 
1512    res= ISRestoreTXDisplay() ;
1513  }
1514}
1515
1516void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) 
1517{
1518  INDI_UNUSED(dev);
1519  INDI_UNUSED(name);
1520  INDI_UNUSED(sizes);
1521  INDI_UNUSED(blobsizes);
1522  INDI_UNUSED(blobs);
1523  INDI_UNUSED(formats);
1524  INDI_UNUSED(names);
1525  INDI_UNUSED(n);
1526}
1527void ISSnoopDevice (XMLEle *root) 
1528{
1529  INDI_UNUSED(root);
1530}
1531
1532int writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[])
1533{
1534
1535  fitsfile *fptr;       /* pointer to the FITS file; defined in fitsio.h */
1536  int status;
1537  long  fpixel = 1, naxis = 2, nelements;
1538  long  naxes[2];
1539  char filename_rw[TEMPFILE_LEN+1];
1540
1541  naxes[0] = STVImg->width;
1542  naxes[1] = STVImg->height;
1543
1544  /* Append ! to file name to over write it.*/
1545  snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename);
1546
1547  status = 0;         /* initialize status before calling fitsio routines */
1548  fits_create_file(&fptr, filename_rw, &status);   /* create new file */
1549
1550  /* Create the primary array image (16-bit short integer pixels */
1551  fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
1552
1553  addFITSKeywords(fptr, image_info);
1554
1555  nelements = naxes[0] * naxes[1];          /* number of pixels to write */
1556
1557  /* Write the array of integers to the image */
1558  fits_write_img(fptr, TUSHORT, fpixel, nelements, STVImg->img, &status);
1559
1560  fits_close_file(fptr, &status);            /* close the file */
1561
1562  fits_report_error(stderr, status);  /* print out any error messages */
1563
1564  /* Success */
1565  /*ExposeTimeNP.s = IPS_OK; */
1566  /*IDSetNumber(&ExposeTimeNP, NULL); */
1567  uploadFile(filename);
1568 
1569  return status;
1570}
1571
1572void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info)
1573{
1574  int status=0; 
1575  char binning_s[32];
1576  char frame_s[32];
1577  char date_obs_s[64] ;
1578  char tmp[32] ;
1579 
1580
1581  image_info->pixelSize= 7.4 ; /* microns */
1582
1583  if( image_info->binning== 1) {
1584    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 1., 1.);
1585  } else if( image_info->binning== 2) {
1586    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 2., 2.);
1587  } else if( image_info->binning== 3) {
1588    snprintf(binning_s, 32, "(%1.0f x %1.0f)", 3., 3.);
1589  } else {
1590    fprintf( stderr, "Error in binning information: %d\n", image_info->binning) ; 
1591  }
1592 
1593
1594  strcpy(frame_s, "Light");
1595
1596  /* ToDo: assign the frame type */
1597/*   switch (STVImg->frameType) */
1598/*   { */
1599/*     case LIGHT_FRAME: */
1600/*              strcpy(frame_s, "Light"); */
1601/*      break; */
1602/*     case BIAS_FRAME: */
1603/*         strcpy(frame_s, "Bias"); */
1604/*      break; */
1605/*     case FLAT_FRAME: */
1606/*         strcpy(frame_s, "Flat Field"); */
1607/*      break; */
1608/*     case DARK_FRAME: */
1609/*         strcpy(frame_s, "Dark"); */
1610/*      break; */
1611/*   } */
1612
1613 
1614  fits_update_key(fptr, TDOUBLE, "CCD-TEMP", &(image_info->ccdTemp), "CCD Temperature (Celcius)", &status);
1615  fits_update_key(fptr, TDOUBLE, "EXPOSURE", &(image_info->exposure ), "Total Exposure Time (ms)", &status); 
1616  fits_update_key(fptr, TDOUBLE, "PIX-SIZ",  &(image_info->pixelSize), "Pixel Size (microns)", &status);
1617  fits_update_key(fptr, TSTRING, "BINNING",  binning_s, "Binning HOR x VER", &status);
1618  fits_update_key(fptr, TSTRING, "FRAME",    frame_s, "Frame Type", &status);
1619  fits_update_key(fptr, TDOUBLE, "DATAMIN",  &(image_info->minValue), "Minimum value", &status);
1620  fits_update_key(fptr, TDOUBLE, "DATAMAX",  &(image_info->maxValue), "Maximum value", &status);
1621  fits_update_key(fptr, TSTRING, "INSTRUME", "SBIG STV", "CCD Name", &status);
1622
1623  sprintf( tmp, "%4d-",image_info->year) ; 
1624  strcpy( date_obs_s,tmp ) ;
1625
1626  if( image_info->month< 10) {
1627    sprintf( tmp, "0%1d-", image_info->month) ; 
1628  } else {
1629    sprintf( tmp, "%2d-",  image_info->month) ; 
1630  }
1631  strcat( date_obs_s, tmp) ;
1632
1633  if( image_info->day< 10) {
1634    sprintf( tmp, "0%1dT", image_info->day) ; 
1635  } else {
1636    sprintf( tmp, "%2dT",  image_info->day) ; 
1637  } 
1638  strcat( date_obs_s, tmp) ;
1639
1640  if( image_info->hours< 10) {
1641    sprintf( tmp, "0%1d:", image_info->hours) ; 
1642  } else {
1643    sprintf( tmp, "%2d:",  image_info->hours) ; 
1644  } 
1645  strcat( date_obs_s, tmp) ;
1646
1647  if( image_info->minutes< 10) {
1648    sprintf( tmp, "0%1d:",image_info->minutes) ; 
1649  } else {
1650    sprintf( tmp, "%2d:", image_info->minutes) ; 
1651  } 
1652  strcat( date_obs_s, tmp) ;
1653
1654  if( image_info->seconds< 10) {
1655    sprintf( tmp, "0%1d:", image_info->seconds) ; 
1656  } else {
1657    sprintf( tmp, "%2d:",  image_info->seconds) ; 
1658  } 
1659  strcat( date_obs_s, tmp) ;
1660
1661  fits_update_key(fptr, TSTRING, "DATE-OBS", date_obs_s, "Observing date (YYYY-MM-DDThh:mm:ss UT", &status);
1662 
1663  fits_write_date(fptr, &status);
1664
1665}
1666
1667void uploadFile(const char* filename)
1668{
1669   FILE * fitsFile;
1670   unsigned char *fitsData, *compressedData;
1671   int r=0;
1672   unsigned int i =0, nr = 0;
1673   uLongf compressedBytes=0;
1674   uLong  totalBytes;
1675   struct stat stat_p; 
1676 
1677   if ( -1 ==  stat (filename, &stat_p))
1678   { 
1679     IDLog("Error occurred attempting to stat file.\n"); 
1680     return; 
1681   }
1682   
1683   totalBytes     = stat_p.st_size;
1684
1685
1686   fitsData       = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes);
1687   compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3);
1688
1689
1690   
1691   if (fitsData == NULL || compressedData == NULL) {
1692     if (fitsData) free(fitsData);
1693     if (compressedData) free(compressedData);
1694     IDLog("Error! low memory. Unable to initialize fits buffers.\n");
1695     return;
1696   }
1697   
1698   fitsFile = fopen(filename, "r");
1699   
1700   if (fitsFile == NULL)
1701    return;
1702   
1703   /* #1 Read file from disk */ 
1704   for (i=0; i < totalBytes; i+= nr)
1705   {
1706      nr = fread(fitsData + i, 1, totalBytes - i, fitsFile);
1707     
1708     if (nr <= 0)
1709     {
1710        IDLog("Error reading temporary FITS file.\n");
1711        return;
1712     }
1713   }
1714   fclose(fitsFile);
1715   
1716   compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3;
1717   
1718   /* #2 Compress it */ 
1719   r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9);
1720   if (r != Z_OK)
1721   {
1722        /* this should NEVER happen */
1723        IDLog("internal error - compression failed: %d\n", r);
1724        return;
1725   }
1726   
1727   /* #3 Send it */
1728   imageB.blob = compressedData;
1729   imageB.bloblen = compressedBytes;
1730   imageB.size = totalBytes;
1731   strcpy(imageB.format, ".fits.z");
1732
1733   imageBP.s = IPS_OK;
1734   IDSetBLOB (&imageBP, NULL);
1735   
1736   free (fitsData);   
1737   free (compressedData);
1738   
1739}
1740
1741int ISTerminateTXDisplay(void) {
1742
1743  int res = 0;
1744  res= STV_Interrupt() ; /* with out it hangs */
1745  usleep(100000) ;
1746
1747  IERmCallback( cb) ;
1748  cb = -1 ;
1749
1750  if( TXDisplayS[0].s == ISS_ON) {
1751
1752    TXDisplaySP.s = IPS_BUSY ;
1753    IDSetSwitch(&TXDisplaySP, "Stopping display read out");
1754
1755    DisplayCTP.s = IPS_IDLE ;
1756    IUSaveText(&DisplayCT[0], "                        "); /* reset client's display */
1757    IUSaveText(&DisplayCT[1], "                        ");
1758    IDSetText( &DisplayCTP, NULL);
1759         
1760    DisplayBTP.s = IPS_IDLE ;
1761    IUSaveText(&DisplayBT[0], "                        "); /* reset client's display */
1762    IUSaveText(&DisplayBT[1], "                        ");
1763    IDSetText( &DisplayBTP, NULL); 
1764
1765    DisplayDTP.s = IPS_IDLE ;
1766    IUSaveText(&DisplayDT[0], "                        "); /* reset client's display */
1767    IUSaveText(&DisplayDT[1], "                        ");
1768    IDSetText( &DisplayDTP, NULL); 
1769
1770    if(( res= STV_TerminateTXDisplay()) != 0){
1771
1772      fprintf( stderr, "STV: error writing TTXD %d\n", res) ;
1773    }
1774  } else {
1775
1776    res= 0 ;
1777  }
1778  usleep(500000) ; /* make sure that everything is discarded */
1779  tcflush(fd, TCIOFLUSH);
1780
1781  return res ;
1782}
1783
1784int ISRestoreTXDisplay(void) {
1785
1786  int res ;
1787
1788  cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ;
1789
1790  if( TXDisplayS[0].s == ISS_ON) {
1791
1792    usleep(500000) ; /* STV need a little rest */
1793    res= STV_TXDisplay() ;
1794
1795    TXDisplaySP.s = IPS_OK ;
1796    IDSetSwitch(&TXDisplaySP, "Starting Display read out");
1797
1798    DisplayCTP.s = IPS_OK;
1799    IDSetText (&DisplayCTP, NULL);
1800   
1801    DisplayBTP.s = IPS_OK;
1802    IDSetText (&DisplayBTP, NULL);
1803
1804    DisplayDTP.s = IPS_OK;
1805    IDSetText (&DisplayDTP, NULL);
1806   
1807  }
1808  return res ;
1809}
1810
1811int ISMessageImageInfo( int buffer,  IMAGE_INFO *image_info) {
1812
1813  buffer++ ;
1814 
1815/*     IDMessage( mydev, "B%2d: descriptor:%d\n", buffer, image_info->descriptor) ; */
1816/*     IDMessage( mydev, "B%2d: height:%d\n", buffer, image_info->height) ; */
1817/*     IDMessage( mydev, "B%2d: width:%d\n", buffer, image_info->width) ; */
1818/*     IDMessage( mydev, "B%2d: top:%d\n", buffer, image_info->top) ; */
1819/*     IDMessage( mydev, "B%2d: left:%d\n", buffer, image_info->left) ; */
1820  IDMessage( mydev, "B%2d: Exposure:%6.3f, Height:%2d, Width:%2d, CCD Temperature:%3.1f\n", buffer, image_info->exposure, image_info->height, image_info->width, image_info->ccdTemp) ;
1821/*     IDMessage( mydev, "B%2d: noExposure:%d\n", buffer, image_info->noExposure) ; */
1822/*     IDMessage( mydev, "B%2d: analogGain:%d\n", buffer, image_info->analogGain) ; */
1823/*     IDMessage( mydev, "B%2d: digitalGain:%d\n", buffer, image_info->digitalGain) ; */
1824/*     IDMessage( mydev, "B%2d: focalLength:%d\n", buffer, image_info->focalLength) ; */
1825/*     IDMessage( mydev, "B%2d: aperture:%d\n", buffer, image_info->aperture) ; */
1826/*     IDMessage( mydev, "B%2d: packedDate:%d\n", buffer, image_info->packedDate) ; */
1827  IDMessage( mydev, "B%2d: Year:%4d, Month: %2d, Day:%2d\n", buffer, image_info->year, image_info->month, image_info->day) ;
1828/*     IDMessage( mydev, "B%2d: Day:%d\n", buffer, image_info->day) ; */
1829/*     IDMessage( mydev, "B%2d: Month:%d\n", buffer, image_info->month) ; */
1830/*     IDMessage( mydev, "B%2d: packedTime:%d\n", buffer, image_info->packedTime) ; */
1831/*     IDMessage( mydev, "B%2d: Seconds:%d\n", buffer, image_info->seconds) ; */
1832/*     IDMessage( mydev, "B%2d: minutes:%d\n", buffer, image_info->minutes) ; */
1833  IDMessage( mydev, "B%2d: Hours:%2d, Minutes:%2d, Seconds:%d\n", buffer, image_info->hours, image_info->minutes, image_info->seconds) ;
1834
1835/*     IDMessage( mydev, "B%2d: ccdTemp:%f\n", buffer, image_info->ccdTemp) ; */
1836/*     IDMessage( mydev, "B%2d: siteID:%d\n", buffer, image_info->siteID) ; */
1837/*     IDMessage( mydev, "B%2d: eGain:%d\n", buffer, image_info->eGain) ; */
1838/*     IDMessage( mydev, "B%2d: background:%d\n", buffer, image_info->background) ; */
1839/*     IDMessage( mydev, "B%2d: range :%d\n", buffer, image_info->range ) ;   */
1840/*     IDMessage( mydev, "B%2d: pedestal:%d\n", buffer, image_info->pedestal) ; */
1841/*     IDMessage( mydev, "B%2d: ccdTop  :%d\n", buffer, image_info->ccdTop) ; */
1842/*     IDMessage( mydev, "B%2d: ccdLeft:%d\n", buffer, image_info->ccdLeft) ; */
1843  return 0 ;
1844}
1845
1846
1847int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) {
1848
1849  int res ;
1850  int i, k ;
1851  int img_size ;
1852  char errmsg[1024] ;
1853  int image[320][320] ;
1854  IMAGE_INFO image_info ;
1855
1856  for(i= 0 ; i < 320 ; i++) {
1857    for(k= 0 ; k < 320 ; k++) {
1858      image[i][k]= -1 ;
1859    }
1860  }
1861 
1862
1863  res= STV_RequestImage( compression, buffer, x_offset, y_offset, &length, &lines, image, &image_info) ;
1864 
1865  if( res== 0) {
1866
1867    STVImg->width= length;
1868    STVImg->height= lines ;
1869
1870    img_size =   STVImg->width * STVImg->height * sizeof(unsigned short);
1871
1872    STVImg->img= malloc (img_size);
1873 
1874    for(i= 0 ; i < STVImg->height ; i++) { /* x */
1875      for(k= 0 ; k < STVImg->width ; k++) { /* y */
1876
1877        STVImg->img[ STVImg->width* i + k]= (unsigned short)image[i][k] ;
1878        /* Uncomment this line in case of doubts about decompressed values and compare */
1879        /* both sets. */
1880        /*fprintf( stderr, "Line: %d %d %d %d\n", i, k, image[i][k], STVImg->img[ STVImg->width* i + k]) ; */
1881
1882        if(STVImg->img[ STVImg->width* i + k] < image_info.minValue) {
1883         
1884          image_info.minValue= STVImg->img[ STVImg->width* i + k] ;
1885        }
1886        if(STVImg->img[ STVImg->width* i + k] > image_info.maxValue) {
1887         
1888          image_info.maxValue= STVImg->img[ STVImg->width* i + k] ;
1889        }
1890      }
1891    }
1892    writeFITS( "FITS.fits", &image_info, errmsg) ;
1893    /*fprintf( stderr, "Fits writing message: %s\n", errmsg) ;   */
1894    free( STVImg->img) ;
1895  }
1896  return res ;
1897}
1898
1899void ISUpdateDisplay( int buffer, int line) {
1900
1901  if( !(( line+1) % 10)) {
1902 
1903    sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ;
1904    strcpy( DisplayBT[0].text, DisplayCT[0].text) ;
1905    strcpy( DisplayDT[0].text, DisplayCT[0].text) ;
1906   
1907    DisplayCTP.s= IPS_OK ;
1908    IDSetText( &DisplayCTP, NULL) ;
1909    DisplayBTP.s= IPS_OK ;
1910    IDSetText( &DisplayBTP, NULL) ;
1911    DisplayDTP.s= IPS_OK ;
1912    IDSetText( &DisplayDTP, NULL) ;
1913
1914  } else if(( line+1)== 1) { /* first time  */
1915
1916    IDMessage( mydev, "Image download started") ;
1917
1918  } else if( line < 0) { /* last line */
1919
1920    line= -line ;
1921
1922    sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ;
1923    strcpy( DisplayBT[0].text, DisplayCT[0].text) ;
1924    strcpy( DisplayDT[0].text, DisplayCT[0].text) ;
1925
1926    DisplayCTP.s= IPS_OK ;
1927    IDSetText( &DisplayCTP, NULL) ;
1928    DisplayBTP.s= IPS_OK ;
1929    IDSetText( &DisplayBTP, NULL) ;
1930    DisplayDTP.s= IPS_OK ;
1931    IDSetText( &DisplayDTP, NULL) ;
1932    IDMessage( mydev, "Image download ended, buffer %2d line: %3d", buffer+1, line) ;
1933  }
1934}
Note: See TracBrowser for help on using the repository browser.