You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kstars/kstars/indi/temmadriver.c

1001 lines
20 KiB

#if 0
Temma INDI driver
Copyright (C) 2004 Francois Meyer (dulle @ free.fr)
Remi Petitdemange for the temma protocol
Reference site is http://dulle.free.fr/alidade/indi.php
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <time.h>
#include "indicom.h"
#include "indidevapi.h"
#include "eventloop.h"
#include "indicom.h"
#include "temmadriver.h"
char errormes[][128]={
"I/O Timeout",
"Error reading from io port",
"Error writing to io port",
"Unrecognized message"
};
char answer[32];
int fd;
int read_ret, write_ret;
unsigned char buffer[256];
unsigned char buffer2[256];
#if 1
/* Initlization routine */
static void mountInit()
{
static int inited; /* set once mountInit is called */
if (inited)
return;
/* setting default comm port */
PortT->text = realloc(PortT->text, 10);
TemmaNoteT[0].text = realloc( TemmaNoteT[0].text, 64);
TemmaNoteT[1].text = realloc( TemmaNoteT[1].text, 64);
if (!PortT->text || !TemmaNoteT[0].text || !TemmaNoteT[1].text){
fprintf(stderr,"Memory allocation error");
return;
}
strcpy(PortT->text, "/dev/ttyS0");
strcpy(TemmaNoteT[0].text, "Experimental Driver");
strcpy(TemmaNoteT[1].text, "http://dulle.free.fr/alidade/indi.php");
inited = 1;
}
#endif
void ISGetProperties (const char *dev) {
if (dev && strcmp (mydev, dev))
return;
mountInit();
IDDefSwitch (&powSw, NULL);
IDDefNumber (&eqTemma, NULL);
IDDefNumber (&eqNum, NULL);
IDDefSwitch (&OnCoordSetSw, NULL);
IDDefSwitch (&abortSlewSw, NULL);
IDDefText (&TemmaNoteTP, NULL);
IDDefSwitch (&RAmotorSw, NULL);
IDDefSwitch (&trackmodeSw, NULL);
IDDefText (&Port, NULL);
IDDefText (&TemmaVersion, NULL);
IDDefNumber (&Time, NULL);
IDDefNumber (&SDTime, NULL);
IDDefNumber (&cometNum, NULL);
IDDefNumber (&geoNum, NULL);
}
void ISNewBLOB (const char *dev, const char *name, int sizes[], char *blobs[], char *formats[], char *names[], int n)
{
dev=dev;name=name;sizes=sizes;blobs=blobs;formats=formats;names=names;n=n;
}
void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {
/*IText *tp;*/
if (strcmp (dev, mydev))
return;
if (!strcmp (name, Port.name)) {
IUSaveText(PortT, texts[0]);
Port.s = IPS_OK;
IDSetText (&Port, NULL);
}
return;
}
/* client is sending us a new value for a Numeric vector property */
void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {
/* ignore if not ours */
if (strcmp (dev, mydev))
return;
if (!strcmp (name, eqNum.name)) {
/* new equatorial target coords */
/*double newra = 0, newdec = 0;*/
int i, nset;
/* Check power, if it is off, then return */
if (power[0].s != ISS_ON)
{
eqNum.s = IPS_IDLE;
IDSetNumber(&eqNum, "Power is off");
return;
}
for (nset = i = 0; i < n; i++) {
/* Find numbers with the passed names in the eqNum property */
INumber *eqp = IUFindNumber (&eqNum, names[i]);
/* If the number found is Right ascension (eq[0]) then process it */
if (eqp == &eq[0])
{
currentRA = (values[i]);
nset += currentRA >= 0 && currentRA <= 24;
}
/* Otherwise, if the number found is Declination (eq[1]) then process it */
else if (eqp == &eq[1]) {
currentDec = (values[i]);
nset += currentDec >= -90 && currentDec <= 90;
}
} /* end for */
/* Did we process the two numbers? */
if (nset == 2) {
/*char r[32], d[32];*/
/* Set the mount state to BUSY */
eqNum.s = IPS_BUSY;
if (SLEWSW==ISS_ON || TRACKSW==ISS_ON){
IDSetNumber(&eqNum, "Moving to RA Dec %f %f", currentRA,
currentDec);
do_TemmaGOTO();
}
if (SYNCSW==ISS_ON){
IDSetNumber(&eqNum, "Syncing to RA Dec %f %f", currentRA, currentDec);
set_TemmaCurrentpos();
}
eqNum.s = IPS_OK;
IDSetNumber(&eqNum, "Synced");
}
/* We didn't process the two number correctly, report an error */
else {
/* Set property state to idle */
eqNum.s = IPS_IDLE;
IDSetNumber(&eqNum, "RA or Dec absent or bogus.");
}
return;
}
}
/* client is sending us a new value for a Switch property */
void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
{
ISwitch *sp;
/* ignore if not ours */
if (strcmp (dev, mydev))
return;
if (!strcmp (name, powSw.name)) {
sp = IUFindSwitch (&powSw, names[0]);
if (!sp)
return;
fprintf(stderr,"new state %s\n",names[0]);
sp->s = states[0];
if (!strcmp(names[0],"CONNECT")) {
connectMount();
}
if (!strcmp(names[0],"DISCONNECT")) {
disconnectMount();
}
}
if (!strcmp (name, abortSlewSw.name)) {
if (POWSW){
TemmaabortSlew();
IDSetSwitch (&abortSlewSw, "Abort slew");
}
else {
IDSetSwitch (&abortSlewSw, "Power is off");
}
}
if (!strcmp (name, RAmotorSw.name)) {
if (POWSW){
sp = IUFindSwitch (&RAmotorSw, names[0]);
if (!sp)
return;
fprintf(stderr,"new state %s\n",names[0]);
sp->s = states[0];
RAmotorSw.s = IPS_BUSY;
if (!strcmp(names[0],"RUN")) {
set_TemmaStandbyState(0);
}
if (!strcmp(names[0],"STOP")) {
set_TemmaStandbyState(1);
}
if(get_TemmaStandbyState(buffer)){
RAmotorSw.s = IPS_IDLE;
IDSetSwitch (&RAmotorSw, "Error writing to port");
return;
}
}
else {
IDSetSwitch (&RAmotorSw, "Power is off");
}
}
if (!strcmp (name, OnCoordSetSw.name)) {
if (POWSW){
IUResetSwitches(&OnCoordSetSw);
sp = IUFindSwitch (&OnCoordSetSw, names[0]);
if (!sp)
return;
fprintf(stderr,"new state %s\n",names[0]);
sp->s = states[0];
IUResetSwitches(&OnCoordSetSw);
IUUpdateSwitches(&OnCoordSetSw, states, names, n);
/* currentSet = getOnSwitch(&OnCoordSetSw); */
OnCoordSetSw.s = IPS_OK;
IDSetSwitch(&OnCoordSetSw, NULL);
}
else {
IDSetSwitch (&OnCoordSetSw, "Power is off");
}
}
}
double calcLST(char *strlst){
time_t computertime;
struct tm gmt;
double jd, gmst;
double lst;
/*int a,b;*/
time(&computertime);
gmtime_r(&computertime, &gmt);
gmt.tm_mon+=1;
gmt.tm_year+=1900;
currentUTC=(double)gmt.tm_hour+(double)gmt.tm_min/60+(double)gmt.tm_sec/3600;
jd=UTtoJD(&gmt);
gmst=JDtoGMST(jd);
lst=(gmst-longitude)/15;
lst=(lst/24-(int)(lst/24))*24;
if(lst>=24)
lst-=24;
sprintf(strlst,"%.2d%.2d%.2d", (int)lst,
((int)(lst*60))%60,
((int)(lst*3600))%60);
currentLST=lst;
IDSetNumber (&SDTime, NULL);
IDSetNumber (&Time, NULL);
return 0;
}
#if 1
/* update the mount over time */
void readMountcurrentpos (void *p)
{
char result[32];
if(POWSW){
get_TemmaCurrentpos(result);
calcLST(result);
/* This is a temporary workaround to allow
clients with only one eq property to work */
currentRA=temmaRA;
currentDec=temmaDec;
/* again */
IEAddTimer (POLLMS, readMountcurrentpos, NULL);
}
}
#endif
static void connectMount () {
fprintf(stderr,"opening mount port %s\n",PortT->text);
if (power[0].s == ISS_ON){
if (Port.s != IPS_OK){
powSw.s = IPS_IDLE;
power[0].s = ISS_OFF;
IDSetSwitch (&powSw, "Port not set.");
return;
}
else {
if (TemmaConnect(PortT->text)==0){
IDSetText (&Port, "Port is opened.");
if( !get_TemmaVERSION(buffer)){
powSw.s = IPS_OK;
power[0].s = ISS_ON;
power[1].s = ISS_OFF;
snprintf(buffer2,sizeof( buffer2 ),"%s",buffer+4);
IDSetText(&TemmaVersion , "Temma version set");
TemmaVersionT->text = realloc(TemmaVersionT->text, strlen(buffer2)+1);
if (!TemmaVersionT->text){
fprintf(stderr,"Memory allocation error");
return;
}
IDSetSwitch (&powSw, "Mount is ready");
IDSetSwitch (&powSw, VERSION);
strcpy(TemmaVersionT->text, buffer2);
TemmaVersion.s = IPS_OK;
IDSetText (&TemmaVersion, NULL);
IDLog("%s", buffer2);
/* start timer to read mount coords */
IEAddTimer (POLLMS, readMountcurrentpos, NULL);
}
else {
powSw.s = IPS_IDLE;
power[0].s = ISS_OFF;
power[1].s = ISS_ON;
IDSetText(&Port , "Com error");
IDSetSwitch (&powSw, "Port not set.");
}
if(get_TemmaStandbyState(answer)){
IDSetSwitch (&RAmotorSw, "Error writing to port");
return;
}
}
else {
powSw.s = IPS_IDLE;
power[0].s = ISS_OFF;
power[1].s = ISS_ON;
IDSetSwitch (&powSw, "Failed to open port.");
}
}
}
}
static void disconnectMount () {
fprintf(stderr,"closing mount port %s\n",PortT->text);
if (power[1].s == ISS_ON){
if (Port.s != IPS_OK){
powSw.s = IPS_IDLE;
power[0].s = ISS_OFF;
IDSetSwitch (&powSw, "Port not set.");
return;
}
else {
TemmaDisconnect();
powSw.s = IPS_IDLE;
power[0].s = ISS_OFF;
IDSetSwitch (&powSw, "Port is closed.");
}
}
else {
fprintf(stderr, "Already disconnected \n");
}
}
int TemmaConnect(const char *device) {
fprintf(stderr, "Connecting to device %s\n", device);
if (openPort(device) < 0){
fprintf(stderr, "Error connecting to device %s\n", device);
return -1;
}
else{
return 0;
}
}
int TemmaDisconnect() {
fprintf(stderr, "Disconnected.\n");
close(fd);
return 0;
}
int set_CometTracking(int RArate, int DECrate){
#if 0
Set Comet Tracking
LM+/-99999,+/-9999
RA : Adjust Sidereal time by seconds per Day
DEC : Adjust DEC tracking by Minutes Per Day
valeur DEC min=-600 /max=+600 (+/-10 deg / jour)
Example:
LM+120,+30 would slow the RA speed by 86164/86284 and
the Dec would track at 30 Minutes a day.
To stop tracking either send a LM0,0 (or a PS
sauf erreur on constate en faite l inverse en RA
retour Vsideral => LM0,0 ou LM+0,+0
#endif
char local_buffer[16];
if (RArate<-21541){
RArate=-21541;
}
if (RArate>21541){
RArate=21541;
}
if (DECrate<-600){
DECrate=-600;
}
if (DECrate>600){
DECrate=600;
}
snprintf(local_buffer, sizeof( local_buffer ), "%+6d,%+5d", RArate, DECrate);
set_TemmaCometTracking(local_buffer);
return 0;
}
int TemmaabortSlew() {
if (portWrite("PS") < 0)
return -1;
return 0;
}
int do_TemmaGOTO() {
/* Temma Sync */
char command[16];
char sign;
double dec;
calcLST(buffer);
set_TemmaLST(buffer);
dec=fabs(currentDec);
if (currentDec>0){
sign='+';
}
else {
sign='-';
}
snprintf(buffer, sizeof(buffer),"%.2d%.2d%.2d%c%.2d%.2d%.1d",
(int)currentRA,(int)(currentRA*(double)60)%60,((int)(currentRA*(double)6000))%100,sign,
(int)dec,(int)(dec*(double)60)%60,((int)(dec*(double)600))%10);
fprintf(stderr,"Goto %s\n", buffer);
snprintf(command,14,"P%s",buffer);
buffer[14]=0;
fprintf(stderr,"Goto command:%s\n", command);
portWrite(command);
portRead(buffer,-1,TEMMA_TIMEOUT);
if(command[0]=='R'){
return 0;
}
else
return -1;
}
int extractRA(char *buf){
int r,h,m,s;
/*double dra;*/
r=atoi(buf);
h=r/10000;
m=r/100-100*h;
s=(r%100)*.6;
temmaRA=((double)h+((double)m + (double)s/60)/60);
IDSetNumber (&eqTemma, NULL);
/* fprintf(stderr,"extractRA: %s %d %d %d %d %lf\n",buf,r,h,m,s,dra);*/
return 0;
}
int extractDEC(char *buf){
int dec,d,m,s;
/*double ddec;*/
dec=atoi(buf+1);
d=dec/1000;
m=dec/10-100*d;
s=(dec%10)*6;
temmaDec=((double)d+((double)m + (double)s/60)/60);
if (*buf=='-')
temmaDec*=-1;
IDSetNumber (&eqTemma, NULL);
/* fprintf(stderr,"extractDEC: %s %d %d %d %d %lf\n",buf,dec,d,m,s,ddec);*/
return 0;
}
int get_TemmaCurrentpos(char *local_buffer){
char buf[16];
if (portWrite("E") < 0)
return -1;
if(portRead(local_buffer,-1,TEMMA_TIMEOUT)==SUCCESS){
if(strstr(local_buffer, "E")==local_buffer){
strncpy(buf,local_buffer+1,6);
buf[6]=0;
extractRA(buf);
strncpy(buf,local_buffer+7,6);
buf[6]=0;
extractDEC(buf);
return 0;
}
else {
return -1;
}
}
return 0;
}
int set_TemmaCurrentpos(void) {
/* Temma Sync */
char buf[16], sign;
double dec;
calcLST(buf);
set_TemmaLST(buf);
portWrite("Z");
calcLST(buf);
set_TemmaLST(buf);
dec=fabs(currentDec);
if (currentDec>0){
sign='+';
}
else {
sign='-';
}
sprintf(buffer,"%.2d%.2d%.2d%c%.2d%.2d%.1d",
(int)currentRA,(int)(currentRA*(double)60)%60,((int)(currentRA*(double)6000))%100,sign,
(int)dec,(int)(dec*(double)60)%60,((int)(dec*(double)600))%10);
fprintf(stderr,"sync to %s %f %f\n", buffer,currentRA,dec);
snprintf(buf, sizeof(buf), "D%s",buffer);
buf[13]=0;
portWrite(buf);
*buffer=0;
portRead(buffer,-1,TEMMA_TIMEOUT);
if(buffer[0]=='R'){
return 0;
}
else{
return -1;
}
}
int do_TemmaSLEW(char mode){
/*char command[16];*/
sprintf(buffer,"M%c",mode); /* see bit definition in Temmadriver.h */
if (portWrite(buffer) < 0)
return -1;
return 0;
}
int get_TemmaVERSION(char *local_buffer){
int err;
if ((err=portWrite("v")) < 0){
return err;
}
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "ver")==local_buffer){
return 0;
}
else
return EREAD;
}
int get_TemmaGOTOstatus(char *local_buffer){
/*
0 no ongoing goto
1 ongoing Goto
-1 error
*/
if (portWrite("s") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "s")==local_buffer){
return 0;
}
else
return -1;
}
int get_TemmaBOTHcorrspeed(char *local_buffer){
if (portWrite("lg") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "lg")==local_buffer){
return 0;
}
else
return -1;
}
int get_TemmaDECcorrspeed(char *local_buffer){
if (portWrite("lb") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "lb")==local_buffer){
return 0;
}
else
return -1;
}
int set_TemmaDECcorrspeed(char *local_buffer){
char command[16];
snprintf(command, 4, "LB%s",local_buffer);
if (portWrite(command) < 0)
return -1;
return 0;
}
int get_TemmaRAcorrspeed(char *local_buffer){
if (portWrite("la") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "la")==local_buffer){
return 0;
}
else
return -1;
}
int set_TemmaRAcorrspeed(char *local_buffer){
char command[16];
snprintf(command, 4,"LA%s",local_buffer);
if (portWrite(command) < 0)
return -1;
return 0;
}
int get_TemmaLatitude(char *local_buffer){
if (portWrite("i") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(local_buffer[0]=='i'){
return 0;
}
else
return -1;
}
int set_TemmaLatitude(char *local_buffer){
char command[16];
double lat;
char sign;
lat=fabs(latitude);
if (latitude>0){
sign='+';
}
else {
sign='-';
}
sprintf(command,"I%c%.2d%.2d%.1d", sign,
(int)lat,
(int)(lat*(double)60)%60,
((int)(lat*(double)600))%10);
if (portWrite(command) < 0)
return -1;
return 0;
}
int get_TemmaLST(char *local_buffer){
if (portWrite("g") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(local_buffer[0]=='g'){
return 0;
}
else
return -1;
}
int set_TemmaLST(char *local_buffer){
char command[16];
snprintf(command,7,"T%s",local_buffer);
if (portWrite(command) < 0)
return -1;
return 0;
}
int get_TemmaCometTracking(char *local_buffer){
if (portWrite("lm") < 0)
return -1;
portRead(local_buffer,-1,TEMMA_TIMEOUT);
if(strstr(local_buffer, "lm")==local_buffer){
return 0;
}
else
return -1;
}
int set_TemmaStandbyState(int on){
if (on){
return portWrite("STN-ON");
}
else{
return portWrite("STN-OFF");
}
return 0;
}
int get_TemmaStandbyState(unsigned char *local_buffer){
int nb;
int status;
if ((nb=portWrite("STN-COD")) < 0){
IDSetSwitch (&RAmotorSw, "I/O error when asking RAmotor status");
return -1;
}
if((status=portRead(local_buffer,-1,TEMMA_TIMEOUT)==SUCCESS)){
if(strstr(local_buffer, "stn")==local_buffer){
local_buffer[7]=0;
if (strstr(local_buffer,"on")){ /* stanby on */
RAmotorSw.s = IPS_OK;
RAmotor[0].s = ISS_OFF;
RAmotor[1].s = ISS_ON;
IDSetSwitch (&RAmotorSw, "RA motor is off.");
}
else{
if (strstr(local_buffer,"off")){ /* stanby off */
RAmotorSw.s = IPS_OK;
RAmotor[0].s = ISS_ON;
RAmotor[1].s = ISS_OFF;
IDSetSwitch (&RAmotorSw, "RA motor is on.");
}
else {
RAmotorSw.s = IPS_OK;
IDSetSwitch (&RAmotorSw, "I/O error when getting RAmotor status");
}
}
}
return 0;
}
if (status<=ETIMEOUT && status >=ECOMMAND){
IDSetSwitch(&RAmotorSw, "%s", errormes[ETIMEOUT - status]);
}
return -1;
}
int set_TemmaCometTracking(char *local_buffer){
char command[16];
snprintf(command,15,"LM%s",local_buffer);
if (portWrite(command) < 0)
return -1;
return 0;
}
int set_TemmaSolarRate(void){
if (portWrite("LK") < 0)
return -1;
return 0;
}
int set_TemmaStellarRate(void){
if (portWrite("LL") < 0)
return -1;
return 0;
}
int switch_Temmamountside(void){
if (portWrite("PT") < 0)
return -1;
return 0;
}
/**********************************************************************
* Comm
**********************************************************************/
int openPort(const char *portID) {
struct termios ttyOptions;
if ( (fd = open(portID, O_RDWR)) == -1)
return -1;
memset(&ttyOptions, 0, sizeof(ttyOptions));
tcgetattr(fd, &ttyOptions);
/* 8 bit, enable read */
ttyOptions.c_cflag |= CS8;
/* parity */
ttyOptions.c_cflag |= PARENB;
ttyOptions.c_cflag &= ~PARODD;
ttyOptions.c_cflag &= ~CSTOPB;
ttyOptions.c_cflag |= CRTSCTS;
/* set baud rate */
cfsetispeed(&ttyOptions, B19200);
cfsetospeed(&ttyOptions, B19200);
/* set input/output flags */
ttyOptions.c_iflag = IGNBRK;
/* Read at least one byte */
ttyOptions.c_cc[VMIN] = 1;
ttyOptions.c_cc[VTIME] = 5;
/* Misc. */
ttyOptions.c_lflag = 0;
ttyOptions.c_oflag = 0;
/* set attributes */
tcsetattr(fd, TCSANOW, &ttyOptions);
/* flush the channel */
tcflush(fd, TCIOFLUSH);
return (fd);
}
int portWrite(char * buf) {
int nbytes=strlen(buf); /*, totalBytesWritten;*/
int bytesWritten = 0;
/*int retry=10;*/
bytesWritten = write(fd, buf, nbytes);
bytesWritten += write(fd, "\r\n", 2);
/*fprintf(stderr,"portwrite :%d octets %s\n", bytesWritten, buf);*/
if (bytesWritten!=nbytes+2){
perror("write error: ");
IDLog("Error writing to port");
return EWRITE;
}
return (bytesWritten);
}
int portRead(char *buf, int nbytes, int timeout) {
/*
A very basic finite state machine monitors
the bytes read ;
state 0 : read regular bytes
state 1 : just read a \n, waiting for a \r
state 2 : read a \n and a \r, command is over.
Not sure it is useful here but I use a more
sophisticated version of this with a GPS receiver
and it is robust and reliable
We return a null terminated string.
*/
int bytesRead = 0, state=0, /*i=0,*/ current=0;
/*int totalBytesRead = 0;*/
int err;
if ( (err = TemmareadOut(timeout)) ){
switch (err){
case ETIMEOUT:
IDLog("Error: timeout while reading");
return err;
}
}
while (read(fd,buf+bytesRead,1)==1){
/* fprintf(stderr,"%c",buf[bytesRead]); */
fflush(NULL);
switch (state) {
case 0:
if(buf[bytesRead]==13)
state=1;
break;
case 1:
if(buf[bytesRead]==10)
state=2;
else
if(buf[bytesRead]==13)
state=1;
else
state=0;
break;
}
++current;
if (state==2){
/*process(buf);*/
buf[bytesRead+1]=0;
state=current=0;
return SUCCESS;
}
bytesRead=current;
}
return state;
}
int TemmareadOut(int timeout) {
struct timeval tv;
fd_set readout;
int retval;
FD_ZERO(&readout);
FD_SET(fd, &readout);
/* wait for 'timeout' seconds */
tv.tv_sec = timeout;
tv.tv_usec = 0;
/* Wait till we have a change in the fd status */
retval = select (fd+1, &readout, NULL, NULL, &tv);
/* Return 0 on successful fd change */
if (retval > 0)
return 0;
/* Return -1 due to an error */
else if (retval == EREAD)
return retval;
/* Return -2 if time expires before anything interesting happens */
else {
return ETIMEOUT;
}
}