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

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