1 /*
2 * Telescope Control Protocol for Celestron NexStar GPS telescopes
3 *
4 * Copyright 2003 John Kielkopf
5 * John Kielkopf (kielkopf@louisville.edu)
6 *
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * 15 May 2003 -- Version 2.00
22 *
23 *
24 *
25 */
26
27 #include "celestronprotocol.h"
28
29 #ifndef _WIN32
30 #include <termios.h>
31 #endif
32
33 #define NULL_PTR(x) (x *)0
34
35 /* There are two classes of routines defined here: */
36
37 /* XmTel commands to allow easy NexStar access. These */
38 /* include routines that mimic the extensive LX200 command */
39 /* language and, for the most part, trap calls and */
40 /* respond with an error message to the console. */
41
42 /* NexStar specific commands and data. */
43
44 /* The NexStar command set as documented by Celestron */
45 /* is very limited. This version of xmtel uses ta few */
46 /* auxilliary commands which permit direct access to the motor */
47 /* controllers. */
48
49 /* XmTel compatibility commands */
50
51 int ConnectTel(char *port);
52 void DisconnectTel(void);
53 int CheckConnectTel(void);
54
55 void SetRate(int newRate);
56 void SetLimits(double limitLower, double limitHigher);
57 double GetRA(void);
58 double GetDec(void);
59 int SlewToCoords(double newRA, double newDec);
60 int SyncToCoords(double newRA, double newDec);
61 int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC);
62
63 void StopNSEW(void);
64 int SetSlewRate(void);
65
66 int SyncLST(double newTime);
67 int SyncLocalTime(void);
68
69 void Reticle(int reticle);
70 void Focus(int focus);
71 void Derotator(int rotate);
72 void Fan(int fan);
73
74 static int TelPortFD;
75 static int TelConnectFlag = 0;
76
77 /* NexStar local data */
78
79 static double returnRA; /* Last update of RA */
80 static double returnDec; /* Last update of Dec */
81 static int updateRA; /* Set if no RA inquiry since last update */
82 static int updateDec; /* Set if no Dec inquiry since last update */
83 static int slewRate; /* Rate for slew request in StartSlew */
84
85 /* Coordinate reported by NexStar = true coordinate + offset. */
86
87 static double offsetRA = 0; /* Correction to RA from NexStar */
88 static double offsetDec = 0; /* Correction to Dec from NexStar */
89
90 /* NexStar local commands */
91
92 void GetRAandDec(void); /* Update RA and Dec from NexStar */
93
94 /* Serial communication utilities */
95
96 typedef fd_set telfds;
97
98 static int readn(int fd, char *ptr, int nbytes, int sec);
99 static int writen(int fd, char *ptr, int nbytes);
100 static int telstat(int fd, int sec, int usec);
101
CheckConnectTel(void)102 int CheckConnectTel(void)
103 {
104 int numRead;
105 char returnStr[128];
106
107 //return TelConnectFlag;
108 tcflush(TelPortFD, TCIOFLUSH);
109
110 /* Test connection */
111
112 writen(TelPortFD, "Kx", 2);
113 numRead = readn(TelPortFD, returnStr, 3, 2);
114 returnStr[numRead] = '\0';
115
116 if (numRead == 2)
117 {
118 TelConnectFlag = 1;
119 return (0);
120 }
121 else
122 return -1;
123 }
124
ConnectTel(char * port)125 int ConnectTel(char *port)
126 {
127 #ifdef _WIN32
128 return -1;
129 #else
130 struct termios tty;
131 char returnStr[128];
132 int numRead;
133
134 fprintf(stderr, "Connecting to port: %s\n", port);
135
136 if (TelConnectFlag != 0)
137 return 0;
138
139 /* Make the connection */
140
141 TelPortFD = open(port, O_RDWR);
142 if (TelPortFD == -1)
143 return -1;
144
145 tcgetattr(TelPortFD, &tty);
146 cfsetospeed(&tty, (speed_t)B9600);
147 cfsetispeed(&tty, (speed_t)B9600);
148 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
149 tty.c_iflag = IGNBRK;
150 tty.c_lflag = 0;
151 tty.c_oflag = 0;
152 tty.c_cflag |= CLOCAL | CREAD;
153 tty.c_cc[VMIN] = 1;
154 tty.c_cc[VTIME] = 5;
155 tty.c_iflag &= ~(IXON | IXOFF | IXANY);
156 tty.c_cflag &= ~(PARENB | PARODD);
157 tcsetattr(TelPortFD, TCSANOW, &tty);
158
159 /* Flush the input (read) buffer */
160
161 tcflush(TelPortFD, TCIOFLUSH);
162
163 /* Test connection */
164
165 writen(TelPortFD, "Kx", 2);
166 numRead = readn(TelPortFD, returnStr, 3, 2);
167 returnStr[numRead] = '\0';
168
169 /* Diagnostic tests */
170 fprintf(stderr, "ConnectTel read %d characters: %s\n", numRead, returnStr);
171
172 if (numRead == 2)
173 {
174 TelConnectFlag = 1;
175 return (0);
176 }
177 else
178 return -1;
179
180 #endif
181 }
182
183 /* Assign and save slewRate for use in StartSlew */
184
SetRate(int newRate)185 void SetRate(int newRate)
186 {
187 if (newRate == SLEW)
188 {
189 slewRate = 9;
190 }
191 else if (newRate == FIND)
192 {
193 slewRate = 6;
194 }
195 else if (newRate == CENTER)
196 {
197 slewRate = 3;
198 }
199 else if (newRate == GUIDE)
200 {
201 slewRate = 1;
202 }
203 }
204
205 /* Start a slew in chosen direction at slewRate */
206 /* Use auxilliary NexStar command set through the hand control computer */
207
StartSlew(int direction)208 int StartSlew(int direction)
209 {
210 char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x09, 0x00, 0x00, 0x00 };
211 char inputStr[2048];
212
213 if (direction == NORTH)
214 {
215 slewCmd[2] = 0x11;
216 slewCmd[3] = 0x24;
217 slewCmd[4] = slewRate;
218 }
219 else if (direction == EAST)
220 {
221 slewCmd[2] = 0x10;
222 slewCmd[3] = 0x25;
223 slewCmd[4] = slewRate;
224 }
225 else if (direction == SOUTH)
226 {
227 slewCmd[2] = 0x11;
228 slewCmd[3] = 0x25;
229 slewCmd[4] = slewRate;
230 }
231 else if (direction == WEST)
232 {
233 slewCmd[2] = 0x10;
234 slewCmd[3] = 0x24;
235 slewCmd[4] = slewRate;
236 }
237
238 writen(TelPortFD, slewCmd, 8);
239
240 /* Look for '#' acknowledgment of request*/
241
242 for (;;)
243 {
244 if (readn(TelPortFD, inputStr, 1, 1))
245 {
246 if (inputStr[0] == '#')
247 return 0;
248 }
249 else
250 {
251 fprintf(stderr, "No acknowledgment from telescope in StartSlew.\n");
252 return -1;
253 }
254 }
255 }
256
257 /* Stop the slew in chosen direction */
258
StopSlew(int direction)259 int StopSlew(int direction)
260 {
261 char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x00, 0x00, 0x00, 0x00 };
262 char inputStr[2048];
263
264 if (direction == NORTH)
265 {
266 slewCmd[2] = 0x11;
267 slewCmd[3] = 0x24;
268 }
269 else if (direction == EAST)
270 {
271 slewCmd[2] = 0x10;
272 slewCmd[3] = 0x25;
273 }
274 else if (direction == SOUTH)
275 {
276 slewCmd[2] = 0x11;
277 slewCmd[3] = 0x25;
278 }
279 else if (direction == WEST)
280 {
281 slewCmd[2] = 0x10;
282 slewCmd[3] = 0x24;
283 }
284
285 writen(TelPortFD, slewCmd, 8);
286
287 /* Look for '#' acknowledgment of request*/
288
289 for (;;)
290 {
291 if (readn(TelPortFD, inputStr, 1, 1))
292 {
293 if (inputStr[0] == '#')
294 return 0;
295 }
296 else
297 {
298 fprintf(stderr, "No acknowledgment from telescope in StartSlew.\n");
299 return -1;
300 }
301 }
302 }
303
DisconnectTel(void)304 void DisconnectTel(void)
305 {
306 /* printf("DisconnectTel\n"); */
307 if (TelConnectFlag == 1)
308 close(TelPortFD);
309 TelConnectFlag = 0;
310 }
311
312 /* Test update status and return the telescope right ascension */
313 /* Set updateRA flag false */
314 /* Last telescope readout will be returned if no RA inquiry since then */
315 /* Otherwise force a new readout */
316 /* Two successive calls to GetRA will always force a new readout */
317
GetRA(void)318 double GetRA(void)
319 {
320 if (updateRA != 1)
321 GetRAandDec();
322 updateRA = 0;
323 return returnRA;
324 }
325
326 /* Test update status and return the telescope declination */
327 /* Set updateDec flag false */
328 /* Last telescope readout will returned if no Dec inquiry since then */
329 /* Otherwise force a new readout */
330 /* Two successive calls to GetDec will always force a new readout */
331
GetDec(void)332 double GetDec(void)
333 {
334 if (updateDec != 1)
335 GetRAandDec();
336 updateDec = 0;
337 return returnDec;
338 }
339
340 /* Read the telescope right ascension and declination and set update status */
341
isScopeSlewing()342 int isScopeSlewing()
343 {
344 int numRead;
345 char returnStr[128];
346
347 writen(TelPortFD, "L", 1);
348 numRead = readn(TelPortFD, returnStr, 2, 2);
349 returnStr[numRead] = '\0';
350
351 // 0 Slew complete
352 // 1 Slew in progress
353 return (returnStr[0] == '0' ? 0 : 1);
354 }
355
GetRAandDec(void)356 void GetRAandDec(void)
357 {
358 char returnStr[12];
359 int countRA, countDec;
360 int numRead;
361
362 writen(TelPortFD, "E", 1);
363 numRead = readn(TelPortFD, returnStr, 10, 1);
364 returnStr[4] = returnStr[9] = '\0';
365
366 /* Diagnostic
367 *
368 * printf("GetRAandDec: %d read %x\n",numRead,returnStr);
369 *
370 */
371
372 sscanf(returnStr, "%x", &countRA);
373 sscanf(returnStr + 5, "%x:", &countDec);
374 returnRA = (double)countRA;
375 returnRA = returnRA / (3. * 15. * 60. * 65536. / 64800.);
376 returnDec = (double)countDec;
377 returnDec = returnDec / (3. * 60. * 65536. / 64800.);
378
379 /* Account for the quadrant in declination */
380
381 /* 90 to 180 */
382
383 if ((returnDec > 90.) && (returnDec <= 180.))
384 {
385 returnDec = 180. - returnDec;
386 }
387
388 /* 180 to 270 */
389
390 if ((returnDec > 180.) && (returnDec <= 270.))
391 {
392 returnDec = returnDec - 270.;
393 }
394
395 /* 270 to 360 */
396
397 if ((returnDec > 270.) && (returnDec <= 360.))
398 {
399 returnDec = returnDec - 360.;
400 }
401
402 /* Set update flags */
403
404 updateRA = 1;
405 updateDec = 1;
406
407 /* Correct for offsets and return true coordinate */
408 /* Coordinate reported by NexStar = true coordinate + offset. */
409
410 returnRA = returnRA - offsetRA;
411 returnDec = returnDec - offsetDec;
412 }
413
414 /* Reset telescope coordinates to new coordinates by adjusting offsets*/
415 /* Coordinate reported by NexStar = true coordinate + offset. */
416
SyncToCoords(double newRA,double newDec)417 int SyncToCoords(double newRA, double newDec)
418 {
419 /* offsetRA = 0.;
420 offsetDec = 0.;
421 GetRAandDec();
422 offsetRA = returnRA - newRA;
423 offsetDec = returnDec - newDec;
424
425 return (0);*/
426
427 /* 2013-10-19 JM: Trying to support sync in Nextstar command set v4.10+ */
428 char str[20];
429 int n1, n2;
430
431 // so, lets format up a sync command
432 n1 = newRA * 0x1000000 / 24;
433 n2 = newDec * 0x1000000 / 360;
434 n1 = n1 << 8;
435 n2 = n2 << 8;
436 sprintf((char *)str, "s%08X,%08X", n1, n2);
437 writen(TelPortFD, str, 18);
438
439 /* Look for '#' in response */
440 for (;;)
441 {
442 if (readn(TelPortFD, str, 1, 2))
443 {
444 if (str[0] == '#')
445 break;
446 }
447 else
448 fprintf(stderr, "No acknowledgment from telescope after SyncToCoords.\n");
449 return 4;
450 }
451 return 0;
452 }
453
454 /* 2013-11-06 JM: support location update in Nextstar command set */
updateLocation(double lng,double lat)455 int updateLocation(double lng, double lat)
456 {
457 int lat_d, lat_m, lat_s;
458 int long_d, long_m, long_s;
459
460 char str[10];
461 char cmd[8];
462
463 // Convert from INDI standard to regular east/west -180 to 180
464 if (lng > 180)
465 lng -= 360;
466
467 getSexComponents(lat, &lat_d, &lat_m, &lat_s);
468 getSexComponents(lng, &long_d, &long_m, &long_s);
469
470 cmd[0] = abs(lat_d);
471 cmd[1] = lat_m;
472 cmd[2] = lat_s;
473 cmd[3] = lat_d > 0 ? 0 : 1;
474 cmd[4] = abs(long_d);
475 cmd[5] = long_m;
476 cmd[6] = long_s;
477 cmd[7] = long_d > 0 ? 0 : 1;
478
479 sprintf((char *)str, "W%c%c%c%c%c%c%c%c", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7]);
480 writen(TelPortFD, str, 9);
481
482 /* Look for '#' in response */
483 for (;;)
484 {
485 if (readn(TelPortFD, str, 1, 2))
486 {
487 if (str[0] == '#')
488 break;
489 }
490 else
491 fprintf(stderr, "No acknowledgment from telescope after updateLocation.\n");
492 return 4;
493 }
494 return 0;
495 }
496
updateTime(struct ln_date * utc,double utc_offset)497 int updateTime(struct ln_date *utc, double utc_offset)
498 {
499 char str[10];
500 char cmd[8];
501 struct ln_zonedate local_date;
502
503 // Celestron takes local time
504 ln_date_to_zonedate(utc, &local_date, utc_offset * 3600);
505
506 cmd[0] = local_date.hours;
507 cmd[1] = local_date.minutes;
508 cmd[2] = local_date.seconds;
509 cmd[3] = local_date.months;
510 cmd[4] = local_date.days;
511 cmd[5] = local_date.years - 2000;
512
513 if (utc_offset < 0)
514 cmd[6] = 256 - ((unsigned int)fabs(utc_offset));
515 else
516 cmd[6] = ((unsigned int)fabs(utc_offset));
517
518 // Always assume standard time
519 cmd[7] = 0;
520
521 sprintf((char *)str, "H%c%c%c%c%c%c%c%c", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7]);
522 writen(TelPortFD, str, 9);
523
524 /* Look for '#' in response */
525 for (;;)
526 {
527 if (readn(TelPortFD, str, 1, 2))
528 {
529 if (str[0] == '#')
530 break;
531 }
532 else
533 fprintf(stderr, "No acknowledgment from telescope after updateTime.\n");
534 return 4;
535 }
536 return 0;
537 }
538
539 /* Slew to new coordinates */
540 /* Coordinate sent to NexStar = true coordinate + offset. */
541
SlewToCoords(double newRA,double newDec)542 int SlewToCoords(double newRA, double newDec)
543 {
544 int countRA, countDec;
545 char r0, r1, r2, r3, d0, d1, d2, d3;
546 double degs, hrs;
547 char outputStr[32], inputStr[2048];
548
549 /* Add offsets */
550
551 hrs = newRA + offsetRA;
552 degs = newDec + offsetDec;
553
554 /* Convert float RA to integer count */
555
556 hrs = hrs * (3. * 15. * 60. * 65536. / 64800.);
557 countRA = (int)hrs;
558
559 /* Account for the quadrant in declination */
560
561 if ((newDec >= 0.0) && (newDec <= 90.0))
562 {
563 degs = degs * (3. * 60. * 65536. / 64800.);
564 }
565 else if ((newDec < 0.0) && (newDec >= -90.0))
566 {
567 degs = (360. + degs) * (3. * 60. * 65536. / 64800.);
568 }
569 else
570 {
571 fprintf(stderr, "Invalid newDec in SlewToCoords.\n");
572 return 1;
573 }
574
575 /* Convert float Declination to integer count */
576
577 countDec = (int)degs;
578
579 /* Convert each integer count to four HEX characters */
580 /* Inline coding just to be fast */
581
582 if (countRA < 65536)
583 {
584 r0 = countRA % 16;
585 if (r0 < 10)
586 {
587 r0 = r0 + 48;
588 }
589 else
590 {
591 r0 = r0 + 55;
592 }
593 countRA = countRA / 16;
594 r1 = countRA % 16;
595 if (r1 < 10)
596 {
597 r1 = r1 + 48;
598 }
599 else
600 {
601 r1 = r1 + 55;
602 }
603 countRA = countRA / 16;
604 r2 = countRA % 16;
605 if (r2 < 10)
606 {
607 r2 = r2 + 48;
608 }
609 else
610 {
611 r2 = r2 + 55;
612 }
613 r3 = countRA / 16;
614 if (r3 < 10)
615 {
616 r3 = r3 + 48;
617 }
618 else
619 {
620 r3 = r3 + 55;
621 }
622 }
623 else
624 {
625 printf("RA count overflow in SlewToCoords.\n");
626 return 2;
627 }
628 if (countDec < 65536)
629 {
630 d0 = countDec % 16;
631 if (d0 < 10)
632 {
633 d0 = d0 + 48;
634 }
635 else
636 {
637 d0 = d0 + 55;
638 }
639 countDec = countDec / 16;
640 d1 = countDec % 16;
641 if (d1 < 10)
642 {
643 d1 = d1 + 48;
644 }
645 else
646 {
647 d1 = d1 + 55;
648 }
649 countDec = countDec / 16;
650 d2 = countDec % 16;
651 if (d2 < 10)
652 {
653 d2 = d2 + 48;
654 }
655 else
656 {
657 d2 = d2 + 55;
658 }
659 d3 = countDec / 16;
660 if (d3 < 10)
661 {
662 d3 = d3 + 48;
663 }
664 else
665 {
666 d3 = d3 + 55;
667 }
668 }
669 else
670 {
671 fprintf(stderr, "Dec count overflow in SlewToCoords.\n");
672 return 3;
673 }
674
675 /* Send the command and characters to the NexStar */
676
677 sprintf(outputStr, "R%c%c%c%c,%c%c%c%c", r3, r2, r1, r0, d3, d2, d1, d0);
678 writen(TelPortFD, outputStr, 10);
679
680 /* Look for '#' in response */
681
682 for (;;)
683 {
684 if (readn(TelPortFD, inputStr, 1, 2))
685 {
686 if (inputStr[0] == '#')
687 break;
688 }
689 else
690 fprintf(stderr, "No acknowledgment from telescope after SlewToCoords.\n");
691 return 4;
692 }
693 return 0;
694 }
695
696 /* Test whether the destination has been reached */
697 /* With the NexStar we use the goto in progress query */
698 /* Return value is */
699 /* 0 -- goto in progress */
700 /* 1 -- goto complete within tolerance */
701 /* 2 -- goto complete but outside tolerance */
702
CheckCoords(double desRA,double desDec,double tolRA,double tolDEC)703 int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC)
704 {
705 double errorRA, errorDec, nowRA, nowDec;
706 char inputStr[2048];
707
708 writen(TelPortFD, "L", 1);
709
710 /* Look for '0#' in response indicating goto is not in progress */
711
712 for (;;)
713 {
714 if (readn(TelPortFD, inputStr, 2, 2))
715 {
716 if ((inputStr[0] == '0') && (inputStr[1] == '#'))
717 break;
718 }
719 else
720 return 0;
721 }
722
723 nowRA = GetRA();
724 errorRA = nowRA - desRA;
725 nowDec = GetDec();
726 errorDec = nowDec - desDec;
727
728 /* For 6 minute of arc precision; change as needed. */
729
730 if (fabs(errorRA) > tolRA || fabs(errorDec) > tolDEC)
731 return 1;
732 else
733 return 2;
734 }
735
736 /* Set lower and upper limits to protect hardware */
737
SetLimits(double limitLower,double limitHigher)738 void SetLimits(double limitLower, double limitHigher)
739 {
740 limitLower = limitHigher;
741 fprintf(stderr, "NexStar does not support software limits.\n");
742 }
743
744 /* Set slew speed limited by MAXSLEWRATE */
745
SetSlewRate(void)746 int SetSlewRate(void)
747 {
748 fprintf(stderr, "NexStar does not support remote setting of slew rate.\n");
749 return 0;
750 }
751
752 /* Stop all slew motion */
753
StopNSEW(void)754 void StopNSEW(void)
755 {
756 char inputStr[2048];
757
758 writen(TelPortFD, "M", 1);
759
760 /* Look for '#' */
761
762 for (;;)
763 {
764 if (readn(TelPortFD, inputStr, 1, 1))
765 {
766 if (inputStr[0] == '#')
767 break;
768 }
769 else
770 {
771 fprintf(stderr, "No acknowledgment from telescope in StopNSEW.\n");
772 }
773 }
774 }
775
776 /* Control the reticle function using predefined values */
777
Reticle(int reticle)778 void Reticle(int reticle)
779 {
780 reticle = reticle;
781 fprintf(stderr, "NexStar does not support remote setting of reticle.\n");
782 }
783
784 /* Control the focus using predefined values */
785
Focus(int focus)786 void Focus(int focus)
787 {
788 focus = focus;
789 fprintf(stderr, "NexStar does not support remote setting of focus.\n");
790 }
791
792 /* Control the derotator using predefined values */
793
Derotator(int rotate)794 void Derotator(int rotate)
795
796 {
797 rotate = rotate;
798 fprintf(stderr, "NexStar does not support an image derotator.\n");
799 }
800
801 /* Control the fan using predefined values */
802
Fan(int fan)803 void Fan(int fan)
804
805 {
806 fan = fan;
807 fprintf(stderr, "NexStar does not have a fan.\n");
808 }
809
810 /* Time synchronization utilities */
811
812 /* Reset the telescope sidereal time */
813
SyncLST(double newTime)814 int SyncLST(double newTime)
815 {
816 newTime = newTime;
817 fprintf(stderr, "NexStar does not support remote setting of sidereal time.\n");
818 return -1;
819 }
820
821 /* Reset the telescope local time */
822
SyncLocalTime()823 int SyncLocalTime()
824 {
825 fprintf(stderr, "NexStar does not support remote setting of local time.\n");
826 return -1;
827 }
828
829 /* Serial port utilities */
830
writen(fd,ptr,nbytes)831 static int writen(fd, ptr, nbytes) int fd;
832 char *ptr;
833 int nbytes;
834 {
835 int nleft, nwritten;
836 nleft = nbytes;
837 while (nleft > 0)
838 {
839 nwritten = write(fd, ptr, nleft);
840 if (nwritten <= 0)
841 break;
842 nleft -= nwritten;
843 ptr += nwritten;
844 }
845 return (nbytes - nleft);
846 }
847
readn(fd,ptr,nbytes,sec)848 static int readn(fd, ptr, nbytes, sec) int fd;
849 char *ptr;
850 int nbytes;
851 int sec;
852 {
853 int status;
854 int nleft, nread;
855 nleft = nbytes;
856 while (nleft > 0)
857 {
858 status = telstat(fd, sec, 0);
859 if (status <= 0)
860 break;
861 nread = read(fd, ptr, nleft);
862
863 /* Diagnostic */
864
865 /* printf("readn: %d read\n", nread); */
866
867 if (nread <= 0)
868 break;
869 nleft -= nread;
870 ptr += nread;
871 }
872 return (nbytes - nleft);
873 }
874
875 /*
876 * Examines the read status of a file descriptor.
877 * The timeout (sec, usec) specifies a maximum interval to
878 * wait for data to be available in the descriptor.
879 * To effect a poll, the timeout (sec, usec) should be 0.
880 * Returns non-negative value on data available.
881 * 0 indicates that the time limit referred by timeout expired.
882 * On failure, it returns -1 and errno is set to indicate the
883 * error.
884 */
telstat(fd,sec,usec)885 static int telstat(fd, sec, usec) register int fd, sec, usec;
886 {
887 int ret;
888 int width;
889 struct timeval timeout;
890 telfds readfds;
891
892 memset((char *)&readfds, 0, sizeof(readfds));
893 FD_SET(fd, &readfds);
894 width = fd + 1;
895 timeout.tv_sec = sec;
896 timeout.tv_usec = usec;
897 ret = select(width, &readfds, NULL_PTR(telfds), NULL_PTR(telfds), &timeout);
898 return (ret);
899 }
900