Index: drivers/telescope/lx200generic.cpp =================================================================== --- drivers/telescope/lx200generic.cpp (revision 242) +++ drivers/telescope/lx200generic.cpp (working copy) @@ -168,6 +168,18 @@ ISwitchVectorProperty MovementWESP = { mydev, "TELESCOPE_MOTION_WE", "West/East", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0}; /******************************************** + Property: Timed Guide movement. North/South +*********************************************/ +static INumber GuideNSN[] = {{"TIMED_GUIDE_N", "North (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_S", "South (sec)", "%g", 0, 10, 0.001, 0, 0, 0}}; +INumberVectorProperty GuideNSNP = { mydev, "TELESCOPE_TIMED_GUIDE_NS", "Guide North/South", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideNSN, NARRAY(GuideNSN), "", 0}; + +/******************************************** + Property: Timed Guide movement. West/East +*********************************************/ +static INumber GuideWEN[] = {{"TIMED_GUIDE_W", "West (sec)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_E", "East (sec)", "%g", 0, 10, 0.001, 0, 0, 0}}; +INumberVectorProperty GuideWENP = { mydev, "TELESCOPE_TIMED_GUIDE_WE", "Guide West/East", MOTION_GROUP, IP_RW, 0, IPS_IDLE, GuideWEN, NARRAY(GuideWEN), "", 0}; + +/******************************************** Property: Slew Accuracy Desciption: How close the scope have to be with respect to the requested coords for @@ -180,6 +192,16 @@ }; INumberVectorProperty SlewAccuracyNP = {mydev, "Slew Accuracy", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, SlewAccuracyN, NARRAY(SlewAccuracyN), "", 0}; +/******************************************** + Property: Use pulse-guide commands + Desciption: Set to on if this mount can support + pulse guide commands. There appears to + be no way to query this information from + the mount +*********************************************/ +static ISwitch UsePulseCmdS[] = {{ "Off", "", ISS_ON, 0, 0} , { "On", "", ISS_OFF, 0, 0}}; +static ISwitchVectorProperty UsePulseCmdSP= { mydev, "Use Pulse Cmd", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, UsePulseCmdS, NARRAY(UsePulseCmdS), "", 0}; + /**********************************************************************************************/ /************************************** GROUP: Focus ******************************************/ /**********************************************************************************************/ @@ -278,7 +300,10 @@ strcpy(TrackingFreqNP.device , newName ); strcpy(MovementNSSP.device , newName ); strcpy(MovementWESP.device , newName ); + strcpy(GuideNSNP.device , newName ); + strcpy(GuideWENP.device , newName ); strcpy(SlewAccuracyNP.device, newName); + strcpy(UsePulseCmdSP.device, newName); // FOCUS_GROUP strcpy(FocusModeSP.device , newName ); @@ -433,6 +458,8 @@ simulation = false; currentSet = 0; fd = -1; + GuideNSTID = 0; + GuideWETID = 0; // Children call parent routines, this is the default IDLog("INDI Library v%g\n", INDI_LIBV); @@ -474,7 +501,10 @@ IDDefSwitch (&TrackModeSP, NULL); IDDefSwitch (&MovementNSSP, NULL); IDDefSwitch (&MovementWESP, NULL); + IDDefNumber (&GuideNSNP, NULL ); + IDDefNumber (&GuideWENP, NULL ); IDDefNumber (&SlewAccuracyNP, NULL); + IDDefSwitch (&UsePulseCmdSP, NULL); // FOCUS_GROUP IDDefSwitch(&FocusModeSP, NULL); @@ -880,6 +910,116 @@ } + if (!strcmp(name, GuideNSNP.name)) + { + int direction; + int duration_msec; + int use_pulse_cmd; + if (checkPower(&GuideNSNP)) + return; + if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) + { + handleError(&GuideNSNP, err, "Can't guide while moving"); + return; + } + if (GuideNSNP.s == IPS_BUSY) + { + // Already guiding so stop before restarting timer + HaltMovement(fd, LX200_NORTH); + HaltMovement(fd, LX200_SOUTH); + } + if (GuideNSTID) { + IERmTimer(GuideNSTID); + GuideNSTID = 0; + } + IUUpdateNumber(&GuideNSNP, values, names, n); + + if (GuideNSNP.np[0].value > 0) { + duration_msec = GuideNSNP.np[0].value * 1000; + direction = LX200_NORTH; + } else { + duration_msec = GuideNSNP.np[1].value * 1000; + direction = LX200_SOUTH; + } + if (duration_msec <= 0) { + GuideNSNP.s = IPS_IDLE; + IDSetNumber (&GuideNSNP, NULL); + return; + } + use_pulse_cmd = getOnSwitch(&UsePulseCmdSP); + // fprintf(stderr, "Using %s mode to move %dmsec %s\n", + // use_pulse_cmd ? "Pulse" : "Legacy", + // duration_msec, direction == LX200_NORTH ? "North" : "South"); + if (use_pulse_cmd) { + SendPulseCmd(fd, direction, duration_msec); + } else { + if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) ) + { + handleError(&SlewModeSP, err, "Setting slew mode"); + return; + } + MoveTo(fd, direction); + } + GuideNSTID = IEAddTimer (duration_msec, guideTimeout, (void *)direction); + GuideNSNP.s = IPS_BUSY; + IDSetNumber(&GuideNSNP, NULL); + } + if (!strcmp(name, GuideWENP.name)) + { + int direction; + int duration_msec; + int use_pulse_cmd; + + if (checkPower(&GuideWENP)) + return; + if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) + { + handleError(&GuideWENP, err, "Can't guide while moving"); + return; + } + if (GuideWENP.s == IPS_BUSY) + { + // Already guiding so stop before restarting timer + HaltMovement(fd, LX200_WEST); + HaltMovement(fd, LX200_EAST); + } + if (GuideWETID) { + IERmTimer(GuideWETID); + GuideWETID = 0; + } + IUUpdateNumber(&GuideWENP, values, names, n); + + if (GuideWENP.np[0].value > 0) { + duration_msec = GuideWENP.np[0].value * 1000; + direction = LX200_WEST; + } else { + duration_msec = GuideWENP.np[1].value * 1000; + direction = LX200_EAST; + } + if (duration_msec <= 0) { + GuideWENP.s = IPS_IDLE; + IDSetNumber (&GuideWENP, NULL); + return; + } + use_pulse_cmd = getOnSwitch(&UsePulseCmdSP); + // fprintf(stderr, "Using %s mode to move %dmsec %s\n", + // use_pulse_cmd ? "Pulse" : "Legacy", + // duration_msec, direction == LX200_WEST ? "West" : "East"); + + if (use_pulse_cmd) { + SendPulseCmd(fd, direction, duration_msec); + } else { + if ( ( err = setSlewMode(fd, LX200_SLEW_GUIDE) < 0) ) + { + handleError(&SlewModeSP, err, "Setting slew mode"); + return; + } + MoveTo(fd, direction); + } + GuideWETID = IEAddTimer (duration_msec, guideTimeout, (void *)direction); + GuideWENP.s = IPS_BUSY; + IDSetNumber(&GuideWENP, NULL); + } } void LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) @@ -958,6 +1098,29 @@ IDSetSwitch(&MovementWESP, NULL); IDSetNumber(&EquatorialCoordsWNP, NULL); } + else if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) + { + GuideNSNP.s = GuideWENP.s = IPS_IDLE; + GuideNSN[0].value = GuideNSN[1].value = 0.0; + GuideWEN[0].value = GuideWEN[1].value = 0.0; + if (GuideNSTID) { + IERmTimer(GuideNSTID); + GuideNSTID = 0; + } + if (GuideWETID) { + IERmTimer(GuideWETID); + GuideNSTID = 0; + } + + AbortSlewSP.s = IPS_OK; + EquatorialCoordsWNP.s = IPS_IDLE; + IUResetSwitch(&AbortSlewSP); + + IDSetSwitch(&AbortSlewSP, "Guide aborted."); + IDSetNumber(&GuideNSNP, NULL); + IDSetNumber(&GuideWENP, NULL); + IDSetNumber(&EquatorialCoordsWNP, NULL); + } else { AbortSlewSP.s = IPS_OK; @@ -1096,6 +1259,11 @@ { if (checkPower(&MovementNSSP)) return; + if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) + { + handleError(&MovementNSSP, err, "Can't move while guiding"); + return; + } int last_move=-1; int current_move = -1; @@ -1144,6 +1312,11 @@ { if (checkPower(&MovementWESP)) return; + if (GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) + { + handleError(&MovementWESP, err, "Can't move while guiding"); + return; + } int last_move=-1; int current_move = -1; @@ -1237,7 +1410,19 @@ return; } + // Pulse-Guide command support + if (!strcmp (name, UsePulseCmdSP.name)) + { + if (checkPower(&UsePulseCmdSP)) + return; + IUResetSwitch(&UsePulseCmdSP); + IUUpdateSwitch(&UsePulseCmdSP, states, names, n); + + UsePulseCmdSP.s = IPS_OK; + IDSetSwitch(&UsePulseCmdSP, NULL); + return; + } } void LX200Generic::handleError(ISwitchVectorProperty *svp, int err, const char *msg) @@ -1423,6 +1608,44 @@ } +void LX200Generic::guideTimeout(void *p) +{ + int direction = (int)p; + int use_pulse_cmd; + + use_pulse_cmd = telescope->getOnSwitch(&UsePulseCmdSP); + if (direction == -1) + { + HaltMovement(telescope->fd, LX200_NORTH); + HaltMovement(telescope->fd, LX200_SOUTH); + HaltMovement(telescope->fd, LX200_EAST); + HaltMovement(telescope->fd, LX200_WEST); + IERmTimer(telescope->GuideNSTID); + IERmTimer(telescope->GuideWETID); + + } + else if (! use_pulse_cmd) + { + HaltMovement(telescope->fd, direction); + } + if (direction == LX200_NORTH || direction == LX200_SOUTH || direction == -1) + { + GuideNSNP.np[0].value = 0; + GuideNSNP.np[1].value = 0; + GuideNSNP.s = IPS_IDLE; + telescope->GuideNSTID = 0; + IDSetNumber(&GuideNSNP, NULL); + } + if (direction == LX200_WEST || direction == LX200_EAST || direction == -1) + { + GuideWENP.np[0].value = 0; + GuideWENP.np[1].value = 0; + GuideWENP.s = IPS_IDLE; + telescope->GuideWETID = 0; + IDSetNumber(&GuideWENP, NULL); + } +} + void LX200Generic::ISPoll() { double dx, dy; @@ -1754,7 +1977,6 @@ if (ConnectSP.s != IPS_OK) { - if (!strcmp(np->label, "")) IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name); else Index: drivers/telescope/lx200generic.h =================================================================== --- drivers/telescope/lx200generic.h (revision 242) +++ drivers/telescope/lx200generic.h (working copy) @@ -61,7 +61,10 @@ void mountSim(); static void updateFocusTimer(void *p); + static void guideTimeout(void *p); int fd; + int GuideNSTID; + int GuideWETID; protected: int timeFormat; @@ -76,6 +79,7 @@ char thisDevice[64]; int currentSet; int lastSet; + }; Index: drivers/telescope/lx200driver.c =================================================================== --- drivers/telescope/lx200driver.c (revision 242) +++ drivers/telescope/lx200driver.c (working copy) @@ -140,6 +140,8 @@ int selectTrackingMode(int fd, int trackMode); /* Select Astro-Physics tracking mode */ int selectAPTrackingMode(int fd, int trackMode); +/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */ +int SendPulseCmd(int fd, int direction, int duration_msec); /************************************************************************** Other Commands @@ -1197,6 +1199,25 @@ return 0; } +int SendPulseCmd(int fd, int direction, int duration_msec) +{ + int nbytes_write=0; + char cmd[20]; + switch (direction) + { + case LX200_NORTH: sprintf(cmd, "#:Mgn%04d#", duration_msec); break; + case LX200_SOUTH: sprintf(cmd, "#:Mgs%04d#", duration_msec); break; + case LX200_EAST: sprintf(cmd, "#:Mge%04d#", duration_msec); break; + case LX200_WEST: sprintf(cmd, "#:Mgw%04d#", duration_msec); break; + default: return 1; + } + + tty_write_string(fd, cmd, &nbytes_write); + + tcflush(fd, TCIFLUSH); + return 0; +} + int HaltMovement(int fd, int direction) { int error_type; Index: drivers/telescope/lx200driver.h =================================================================== --- drivers/telescope/lx200driver.h (revision 242) +++ drivers/telescope/lx200driver.h (working copy) @@ -222,12 +222,14 @@ int abortSlew(int fd); /* Move into one direction, two valid directions can be stacked */ int MoveTo(int fd, int direction); -/* Half movement in a particular direction */ +/* Halt movement in a particular direction */ int HaltMovement(int fd, int direction); /* Select the tracking mode */ int selectTrackingMode(int fd, int trackMode); /* Select Astro-Physics tracking mode */ int selectAPTrackingMode(int fd, int trackMode); +/* Send Pulse-Guide command (timed guide move), two valid directions can be stacked */ +int SendPulseCmd(int fd, int direction, int duration_msec); /************************************************************************** Other Commands Index: examples/tutorial_two.c =================================================================== --- examples/tutorial_two.c (revision 242) +++ examples/tutorial_two.c (working copy) @@ -25,6 +25,22 @@ #include #include +#include +#include + +void show_runtime(int state) { + static struct timeval tv; + struct timeval tv1; + double x, y; + + if (state) { + gettimeofday(&tv, NULL); + } else { + gettimeofday(&tv1, NULL); + fprintf(stderr, "Ran for: %fmsec\n", (double)(tv1.tv_sec * 1000.0 + tv1.tv_usec / 1000.0) - (double)(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0)); + } +} + /* INDI Core headers */ /* indidevapi.h contains API declerations */ @@ -87,7 +103,18 @@ #define currentRA eqN[0].value /* scope's current simulated RA, rads. Handy macro to right ascension from eqN[] */ #define currentDec eqN[1].value /* scope's current simulated Dec, rads. Handy macro to declination from eqN[] */ +/******************************************** + Property: Movement (Arrow keys on handset). North/South +*********************************************/ +static ISwitch MovementNSS[] = {{"MOTION_NORTH", "North", ISS_OFF, 0, 0}, {"MOTION_SOUTH", "South", ISS_OFF, 0, 0}}; +ISwitchVectorProperty MovementNSSP = { mydev, "TELESCOPE_MOTION_NS", "North/South", MAIN_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, MovementNSS, NARRAY(MovementNSS), "", 0}; +/******************************************** + Property: Movement (Arrow keys on handset). West/East +*********************************************/ +static ISwitch MovementWES[] = {{"MOTION_WEST", "West", ISS_OFF, 0, 0}, {"MOTION_EAST", "East", ISS_OFF, 0, 0}}; +ISwitchVectorProperty MovementWESP = { mydev, "TELESCOPE_MOTION_WE", "West/East", MAIN_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, MovementWES, NARRAY(MovementWES), "", 0}; + /* Initlization routine */ static void mountInit() { @@ -98,7 +125,7 @@ /* start timer to simulate mount motion The timer will call function mountSim after POLLMS milliseconds */ - IEAddTimer (POLLMS, mountSim, NULL); + //IEAddTimer (POLLMS, mountSim, NULL); inited = 1; @@ -112,6 +139,8 @@ IDDefSwitch (&connectSP, NULL); IDDefNumber (&eqNP, NULL); + IDDefSwitch (&MovementNSSP, NULL); + IDDefSwitch (&MovementWESP, NULL); } @@ -219,7 +248,26 @@ connectTelescope(); } } + else if (! strcmp(name, MovementNSSP.name)) { + sp = IUFindSwitch (&MovementNSSP, names[0]); + if (sp) { + IUResetSwitch(&MovementNSSP); + sp->s = states[0]; + show_runtime(sp->s); + IDSetSwitch (&MovementNSSP, "Toggle North/South."); + } + } + else if (! strcmp(name, MovementWESP.name)) { + sp = IUFindSwitch (&MovementWESP, names[0]); + if (sp) { + IUResetSwitch(&MovementWESP); + sp->s = states[0]; + show_runtime(sp->s); + IDSetSwitch (&MovementWESP, "Toggle West/East."); + } + } + } /* update the "mount" over time */